diff -urN oldtree/Documentation/00-INDEX newtree/Documentation/00-INDEX
--- oldtree/Documentation/00-INDEX	2006-04-01 04:48:27.000000000 -0500
+++ newtree/Documentation/00-INDEX	2006-04-01 05:36:13.521214750 -0500
@@ -130,6 +130,8 @@
 	- info on Linux input device support.
 io_ordering.txt
 	- info on ordering I/O writes to memory-mapped addresses.
+ioctl-mess.txt
+	- tree-wide ioctl registry.
 ioctl-number.txt
 	- how to implement and register device/driver ioctl calls.
 iostats.txt
diff -urN oldtree/Documentation/Changes newtree/Documentation/Changes
--- oldtree/Documentation/Changes	2006-04-01 04:48:27.000000000 -0500
+++ newtree/Documentation/Changes	2006-04-01 05:36:06.832796750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/acpi/sony_acpi.txt	2006-04-01 05:35:35.726852750 -0500
@@ -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/block/switching-sched.txt newtree/Documentation/block/switching-sched.txt
--- oldtree/Documentation/block/switching-sched.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/block/switching-sched.txt	2006-04-01 05:35:35.798857250 -0500
@@ -0,0 +1,22 @@
+As of the Linux 2.6.10 kernel, it is now possible to change the
+IO scheduler for a given block device on the fly (thus making it possible,
+for instance, to set the CFQ scheduler for the system default, but
+set a specific device to use the anticipatory or noop schedulers - which
+can improve that device's throughput).
+
+To set a specific scheduler, simply do this:
+
+echo SCHEDNAME > /sys/block/DEV/queue/scheduler
+
+where SCHEDNAME is the name of a defined IO scheduler, and DEV is the
+device name (hda, hdb, sga, or whatever you happen to have).
+
+The list of defined schedulers can be found by simply doing
+a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
+will be displayed, with the currently selected scheduler in brackets:
+
+# cat /sys/block/hda/queue/scheduler
+noop anticipatory deadline [cfq]
+# echo anticipatory > /sys/block/hda/queue/scheduler
+# cat /sys/block/hda/queue/scheduler
+noop [anticipatory] deadline cfq
diff -urN oldtree/Documentation/filesystems/reiser4.txt newtree/Documentation/filesystems/reiser4.txt
--- oldtree/Documentation/filesystems/reiser4.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/filesystems/reiser4.txt	2006-04-01 05:36:06.848797750 -0500
@@ -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/ioctl-mess.txt newtree/Documentation/ioctl-mess.txt
--- oldtree/Documentation/ioctl-mess.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/ioctl-mess.txt	2006-04-01 05:36:13.517214500 -0500
@@ -0,0 +1,4818 @@
+				IOCTL REGISTRY
+				==============
+
+If you've found an ioctl that isn't listed here, send a patch to current
+ioctl-mess.txt maintainer (see MAINTAINERS). If you're lazy or don't have
+time for patch-cooking, simple "there is SIOCGPIZZA ioctl" notice via email
+would also be fine.
+
+N: NAME
+I: data copied from userspace by copy_from_user()/get_user(), or
+	"I: (type) arg", or
+	"I: -".
+O: data copied to userspace by copy_to_user()/put_user(), or
+	"O: -".
+
+Please, keep the list in alphabetical wrt "N: " order.
+----------------------------------------------------------------------------
+N: 0x1260 (broken BLKGETSIZE)
+I: -
+O: u32
+
+N: ADD_NEW_DISK
+I: mdu_disk_info_t
+O: -
+
+N: AGPIOC_ACQUIRE
+I: -
+O: -
+
+N: AGPIOC_ALLOCATE
+I: struct agp_allocate
+O: struct agp_allocate
+
+N: AGPIOC_BIND
+I: struct agp_bind
+O: -
+
+N: AGPIOC_DEALLOCATE
+I: (int) arg
+O: -
+
+N: AGPIOC_INFO
+I: -
+O: struct agp_info
+
+N: AGPIOC_PROTECT
+I: -
+O: -
+
+N: AGPIOC_RELEASE
+I: -
+O: -
+
+N: AGPIOC_RESERVE
+I: struct agp_region [+ sizeof(struct agp_segment) * struct agp_region::seg_count]
+O: -
+
+N: AGPIOC_SETUP
+I: struct agp_setup
+O: -
+
+N: AGPIOC_UNBIND
+I: struct agp_unbind
+O: -
+
+AMDTP_IOC_ZAP
+
+N: APM_IOC_STANDBY
+I: -
+O: -
+
+N: APM_IOC_SUSPEND
+I: -
+O: -
+
+N: ATMARPD_CTRL
+I: -
+O: -
+
+N: ATMARP_ENCAP
+I: (unsigned char) arg
+O: -
+
+N: ATMARP_MKIP
+I: (int) arg
+O: -
+
+N: ATMARP_SETENTRY
+I: (u32) arg
+O: -
+
+N: ATMLEC_CTRL
+I: (int) arg
+O: -
+
+N: ATMLEC_DATA
+I: struct atmlec_ioc
+O: -
+
+N: ATMLEC_MCAST
+I: (int) arg
+O: -
+
+N: ATMMPC_CTRL
+I: (int) arg
+O: -
+
+N: ATMMPC_DATA
+I: struct atmmpc_ioc
+O: -
+
+N: ATMSIGD_CTRL
+I: -
+O: -
+
+N: ATMTCP_CREATE
+I: (int) arg
+O: -
+
+N: ATMTCP_REMOVE
+I: (int) arg
+O: -
+
+N: ATM_ADDADDR
+I: void __user * + int + int + struct sockaddr_atmsvc
+O: -
+
+ATM_ADDADDR32
+
+N: ATM_ADDPARTY
+I: struct sockaddr_atmsvc
+O: -
+
+ATM_DELADDR
+I: void __user * + int + int + struct sockaddr_atmsvc
+O: -
+
+ATM_DELADDR32
+
+N: ATM_DROPPARTY
+I: int
+O: -
+
+N: ATM_GETADDR
+I: void __user * + int + int
+O: int
+
+ATM_GETADDR32
+
+N: ATM_GETCIRANGE
+I: void __user * + int + int
+O: struct atm_cirange
+
+ATM_GETCIRANGE32
+
+N: ATM_GETESI
+I: void __user * + int + int
+O: unsigned char [ESI_LEN]
+
+ATM_GETESI32
+
+N: ATM_GETLINKRATE
+I: void __user * + int + int
+O: int
+
+ATM_GETLINKRATE32
+
+N: ATM_GETLOOP
+I: -
+O: int
+
+ATM_GETLOOP32
+
+N: ATM_GETNAMES
+I: void __user * + int
+O: int [size]
+
+ATM_GETNAMES32
+
+N: ATM_GETSTAT
+I: void __user * + int + int
+O: struct atm_dev_stats
+
+ATM_GETSTAT32
+
+N: ATM_GETSTATZ
+I: void __user * + int + int
+O: struct atm_dev_stats
+
+ATM_GETSTATZ32
+
+N: ATM_GETTYPE
+I: void __user * + int + int
+O: char [strlen(struct atm_dev::type) + 1]
+
+ATM_GETTYPE32
+
+N: ATM_NEWBACKENDIF
+I: atm_backend_t + struct atm_newif_br2684
+O: -
+
+N: ATM_QUERYLOOP
+I: -
+O: int
+
+ATM_QUERYLOOP32
+
+N: ATM_RSTADDR
+I: void __user * + int + int
+O: -
+
+ATM_RSTADDR32
+
+N: ATM_SETBACKEND
+I: atm_backend_t + struct atm_backend_br2684
+O: -
+
+N: ATM_SETCIRANGE
+I: void __user * + int + int + struct atm_cirange
+O: -
+
+ATM_SETCIRANGE32
+
+N: ATM_SETESI
+I: void __user * + int + int + unsigned char [ESI_LEN]
+O: -
+
+ATM_SETESI32
+
+N: ATM_SETESIF
+I: void __user * + int + int + unsigned char [ESI_LEN]
+O: -
+
+ATM_SETESIF32
+
+N: ATM_SETLOOP
+I: (int) arg
+O: -
+
+ATM_SETLOOP32
+
+N: ATM_SETSC
+I: -
+O: -
+
+N: ATYIO_CLKR
+I: -
+O: struct atyclk
+
+N: ATYIO_CLKW
+I: struct atyclk
+O: -
+
+N: ATYIO_FEATR
+I: u32
+O: -
+
+N: ATYIO_FEATW
+I: -
+O: u32
+
+AUDC_CONFIG_PINNACLE
+AUDC_SET_INPUT
+AUDC_SET_RADIO
+AUDIO_CHANNEL_SELECT
+AUDIO_CLEAR_BUFFER
+AUDIO_CONTINUE
+AUDIO_DIAG_LOOPBACK
+AUDIO_DRAIN
+AUDIO_FLUSH
+AUDIO_GETDEV
+AUDIO_GETDEV_SUNOS
+AUDIO_GETINFO
+AUDIO_GET_CAPABILITIES
+AUDIO_GET_STATUS
+AUDIO_PAUSE
+AUDIO_PLAY
+AUDIO_SELECT_SOURCE
+AUDIO_SETINFO
+AUDIO_SET_ATTRIBUTES
+AUDIO_SET_AV_SYNC
+AUDIO_SET_BYPASS_MODE
+AUDIO_SET_EXT_ID
+AUDIO_SET_ID
+AUDIO_SET_KARAOKE
+AUDIO_SET_MIXER
+AUDIO_SET_MUTE
+AUDIO_SET_STREAMTYPE
+AUDIO_STOP
+
+N: AUTOFS_IOC_ASKREGHOST
+I: -
+O: int
+
+N: AUTOFS_IOC_ASKUMOUNT
+I: -
+O: int
+
+N: AUTOFS_IOC_CATATONIC
+I: -
+O: -
+
+N: AUTOFS_IOC_EXPIRE
+I: -
+O: struct autofs_packet_expire
+
+N: AUTOFS_IOC_EXPIRE_MULTI
+I: int
+O: -
+
+N: AUTOFS_IOC_FAIL
+I: (autofs_wqt_t) arg
+O: -
+
+N: AUTOFS_IOC_PROTOSUBVER
+I: -
+O: int
+
+N: AUTOFS_IOC_PROTOVER
+I: -
+O: int
+
+N: AUTOFS_IOC_READY
+I: (autofs_wqt_t) arg
+O: -
+
+AUTOFS_IOC_SETTIMEOUT32
+
+N: AUTOFS_IOC_TOGGLEREGHOST
+I: int
+O: -
+
+N: BIODASDCMFDISABLE
+I: -
+O: -
+
+N: BIODASDCMFENABLE
+I: -
+O: -
+
+N: BIODASDDISABLE
+I: -
+O: -
+
+N: BIODASDENABLE
+I: -
+O: -
+
+N: BIODASDFMT
+I: struct format_data_t
+O: -
+
+N: BIODASDFORMAT
+I: -
+O: struct attrib_data_t
+
+N: BIODASDGATTR
+I: -
+O: struct attrib_data_t
+
+N: BIODASDINFO
+I: -
+O: struct dasd_information_t
+
+N: BIODASDINFO2
+I: -
+O: struct dasd_information2_t
+
+N: BIODASDPRRD
+I: -
+O: struct dasd_profile_info_t
+
+N: BIODASDPRRST
+I: -
+O: -
+
+N: BIODASDPSRD
+I: -
+O: struct dasd_rssd_perf_stats_t
+
+N: BIODASDQUIESCE
+I: -
+O: -
+
+BIODASDREADALLCMB
+BIODASDRESETCMB
+
+N: BIODASDRESUME
+I: -
+O: -
+
+N: BIODASDRLSE
+I: -
+O: -
+
+N: BIODASDRSRV
+I: -
+O: -
+
+N: BIODASDSATTR
+I: struct attrib_data_t
+O: -
+
+N: BIODASDSLCK
+I: -
+O: -
+
+N: BLKBSZGET
+I: -
+O: int
+
+BLKBSZGET_32
+
+N: BLKBSZSET
+I: int
+O: -
+
+BLKBSZSET_32
+BLKELVGET
+BLKELVSET
+
+N: BLKFLSBUF
+I: -
+O: -
+
+N: BLKFRAGET
+I: -
+O: long
+
+N: BLKFRASET
+I: (unsigned long) arg
+O: -
+
+N: BLKGETSIZE
+I: -
+O: unsigned long
+
+N: BLKGETSIZE64
+I: -
+O: u64
+
+BLKGETSIZE64_32
+
+N: BLKI2OGRSTRAT
+I: -
+O: int
+
+N: BLKI2OGWSTRAT
+I: -
+O: int
+
+N: BLKI2OSRSTRAT
+I: (int) arg
+O: -
+
+N: BLKI2OSWSTRAT
+I: (int) arg
+O: -
+
+N: BLKPG
+I: struct blkpg_ioctl_arg + struct blkpg_partition
+O: -
+
+N: BLKRAGET
+I: -
+O: long
+
+N: BLKRASET
+I: (unsigned long) arg
+O: -
+
+N: BLKROGET
+I: -
+O: int
+
+N: BLKROSET
+I: int
+O: -
+
+N: BLKRRPART
+I: -
+O: -
+
+N: BLKSECTGET
+I: -
+O: unsigned short
+
+BLKSECTSET
+
+N: BLKSSZGET
+I: -
+O: int
+
+N: BNEPCONNADD
+I: struct bnep_connadd_req
+O: struct bnep_connadd_req
+
+N: BNEPCONNDEL
+I: struct bnep_conndel_req
+O: -
+
+N: BNEPGETCONNINFO
+I: struct bnep_conninfo
+O: struct bnep_conninfo
+
+N: BNEPGETCONNLIST
+I: struct bnep_connlist_req
+O: struct bnep_connlist_req
+
+N: BPP_GET_DATA
+I: -
+O: -
+
+N: BPP_GET_PINS
+I: -
+O: -
+
+N: BPP_PUT_DATA
+I: (unsigned char) arg
+O: -
+
+N: BPP_PUT_PINS
+I: (unsigned short) arg
+O: -
+
+N: BPP_SET_INPUT
+I: (unsigned long) arg
+O: -
+
+N: BR2684_SETFILT
+I: struct br2684_filter_set
+O: -
+
+N: BT832_HEXDUMP
+I: -
+O: -
+
+N: BT832_REATTACH
+I: -
+O: -
+
+N: BTTV_VBISIZE
+I: -
+O: -
+
+BTTV_VERSION
+BUZIOC_G_PARAMS
+BUZIOC_G_STATUS
+BUZIOC_QBUF_CAPT
+BUZIOC_QBUF_PLAY
+BUZIOC_REQBUFS
+BUZIOC_SYNC
+BUZIOC_S_PARAMS
+
+N: CAPI_CLR_FLAGS
+I: unsigned
+O: -
+
+N: CAPI_GET_ERRCODE
+I: -
+O: __u16
+
+N: CAPI_GET_FLAGS
+I: -
+O: unsigned
+
+N: CAPI_GET_MANUFACTURER
+I: __u32
+O: __u8 [CAPI_MANUFACTURER_LEN]
+
+N: CAPI_GET_PROFILE
+I: __u32
+O: __u16
+
+N: CAPI_GET_SERIAL
+I: __u32
+O: __u8 [CAPI_SERIAL_LEN]
+
+N: CAPI_GET_VERSION
+I: __u32
+O: struct capi_version
+
+N: CAPI_INSTALLED
+I: -
+O: -
+
+N: CAPI_MANUFACTURER_CMD
+I: struct capi_manufacturer_cmd
+O: -
+
+N: CAPI_NCCI_GETUNIT
+I: unsigned
+O: -
+
+N: CAPI_NCCI_OPENCOUNT
+I: unsigned
+O: -
+
+N: CAPI_REGISTER
+I: struct capi_register_params
+O: -
+
+N: CAPI_SET_FLAGS
+I: unsigned
+O: -
+
+N: CA_GET_CAP
+I: -
+O: struct ca_caps
+
+N: CA_GET_DESCR_INFO
+I: -
+O: -
+
+N: CA_GET_MSG
+I: struct ca_msg
+O: struct ca_msg | -
+
+N: CA_GET_SLOT_INFO
+I: -
+O: struct ca_slot_info
+
+N: CA_RESET
+I: -
+O: -
+
+N: CA_SEND_MSG
+I: struct ca_msg
+O: -
+
+N: CA_SET_DESCR
+I: -
+O: -
+
+N: CA_SET_PID
+I: -
+O: -
+
+N: CCISS_BIG_PASSTHRU
+I: BIG_IOCTL_Command_struct
+O: BIG_IOCTL_Command_struct
+
+N: CCISS_DEREGDISK
+I: -
+O: -
+
+N: CCISS_GETBUSTYPES
+I: -
+O: BusTypes_type
+
+N: CCISS_GETDRIVVER
+I: -
+O: DriverVer_type
+
+N: CCISS_GETFIRMVER
+I: -
+O: FirmwareVer_type
+
+N: CCISS_GETHEARTBEAT
+I: -
+O: Heartbeat_type
+
+N: CCISS_GETINTINFO
+I: -
+O: cciss_coalint_struct
+
+N: CCISS_GETLUNINFO
+I: -
+O: LogvolInfo_struct
+
+N: CCISS_GETNODENAME
+I: -
+O: NodeName_type
+
+N: CCISS_GETPCIINFO
+I: -
+O: cciss_pci_info_struct
+
+N: CCISS_PASSTHRU
+I: IOCTL_Command_struct [+ IOCTL_Command_struct::buf_size]
+O: IOCTL_Command_struct [+ IOCTL_Command_struct::buf_size]
+
+CCISS_PASSTHRU32
+
+N: CCISS_REGNEWD
+I: -
+O: -
+
+CCISS_RESCANDISK
+
+N: CCISS_REVALIDVOLS
+I: -
+O: -
+
+N: CCISS_SETINTINFO
+I: cciss_coalint_struct
+O: -
+
+N: CCISS_SETNODENAME
+I: NodeName_type
+O: -
+
+N: CDROMCLOSETRAY
+I: -
+O: -
+
+N: CDROMEJECT
+I: -
+O: -
+
+N: CDROMEJECT_SW
+I: (unsigned long) arg
+O: -
+
+N: CDROMMULTISESSION
+I: struct cdrom_multisession
+O: struct cdrom_multisession | -
+
+N: CDROMPAUSE
+I: -
+O: -
+
+N: CDROMPLAYBLK
+I: struct cdrom_blk
+O: -
+
+N: CDROMPLAYMSF
+I: struct cdrom_msf
+O: -
+
+N: CDROMPLAYTRKIND
+I: struct cdrom_ti
+O: -
+
+N: CDROMREADALL
+I: struct cdrom_msf
+O: void [CD_FRAMESIZE_RAWER]
+
+N: CDROMREADAUDIO
+I: struct cdrom_read_audio
+O: -
+
+N: CDROMREADCOOKED
+I: struct cdrom_msf
+O: void [CD_FRAMESIZE]
+
+N: CDROMREADMODE1
+I: struct cdrom_msf
+O: unsigned char [CD_FRAMESIZE]
+
+N: CDROMREADMODE2
+I: struct cdrom_msf
+O: unsigned char [CD_FRAMESIZE_RAW0]
+
+N: CDROMREADRAW
+I: struct cdrom_msf
+O: unsigned char [CD_FRAMESIZE_RAW]
+
+N: CDROMREADTOCENTRY
+I: struct cdrom_tocentry
+O: struct cdrom_tocentry
+
+N: CDROMREADTOCHDR
+I: struct cdrom_tocentry
+O: struct cdrom_tocentry
+
+N: CDROMRESET
+I: -
+O: -
+
+N: CDROMRESUME
+I: -
+O: -
+
+N: CDROMSEEK
+I: struct cdrom_msf
+O: -
+
+N: CDROMSTART
+I: -
+O: -
+
+N: CDROMSTOP
+I: -
+O: -
+
+N: CDROMSUBCHNL
+I: struct cdrom_subchnl
+O: struct cdrom_subchnl
+
+N: CDROMVOLCTRL
+I: struct cdrom_volctrl
+O: -
+
+N: CDROMVOLREAD
+I: struct cdrom_volctrl
+O: struct cdrom_volctrl
+
+N: CDROM_CHANGER_NSLOTS
+I: -
+O: -
+
+N: CDROM_CLEAR_OPTIONS
+I: (int) arg
+O: -
+
+N: CDROM_DEBUG
+I: (unsigned long) arg
+O: -
+
+N: CDROM_DISC_STATUS
+I: -
+O: -
+
+N: CDROM_DRIVE_STATUS
+I: (int) arg
+O: -
+
+N: CDROM_GET_CAPABILITY
+I: -
+O: -
+
+N: CDROM_GET_MCN
+I: -
+O: struct cdrom_mcn
+
+N: CDROM_LOCKDOOR
+I: (int) arg
+O: -
+
+N: CDROM_MEDIA_CHANGED
+I: (unsigned int) arg
+O: -
+
+N: CDROM_SELECT_DISC
+I: (int) arg
+O: -
+
+N: CDROM_SELECT_SPEED
+I: (int) arg
+O: -
+
+N: CDROM_SEND_PACKET
+I: struct cdrom_generic_command
+O: struct cdrom_generic_command
+
+N: CDROM_SET_OPTIONS
+I: (int) arg
+O: -
+
+N: CHIOEXCHANGE
+I: struct changer_exchange
+O: -
+
+N: CHIOGELEM
+I: struct changer_get_element
+O: struct changer_get_element
+
+N: CHIOGPARAMS
+I: -
+O: struct changer_params
+
+CHIOGPICKER
+
+N: CHIOGSTATUS
+I: struct changer_element_status
+O: u_char [?]
+
+N: CHIOGSTATUS32
+I: struct changer_element_status32
+O: u_char [?]
+
+N: CHIOGVPARAMS
+I: -
+O: struct changer_vendor_params
+
+N: CHIOINITELEM
+I: -
+O: -
+
+N: CHIOMOVE
+I: struct changer_move
+O: -
+
+N: CHIOPOSITION
+I: struct changer_position
+O: -
+
+CHIOSPICKER
+
+N: CHIOSVOLTAG
+I: struct changer_set_voltag
+O: -
+
+N: CIFS_IOC_CHECKUMOUNT
+I: -
+O: -
+
+N: CIOC_KERNEL_VERSION
+I: -
+O: int
+
+CLEAR_ARRAY
+
+N: CM206CTL_GET_LAST_STAT
+I: (unsigned long) arg
+O: -
+
+N: CM206CTL_GET_STAT
+I: (unsigned long) arg
+O: -
+
+N: CMD_AC97_BOOST
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_GETCTLGPR
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_GETGPR
+I: struct mixer_private_ioctl
+O: struct dsp_gpr
+
+N: CMD_GETGPR2OSS
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_GETPATCH
+I: struct mixer_private_ioctl
+O: struct dsp_rpatch | struct dsp_patch
+
+N: CMD_GETRECSRC
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_GETVOICEPARAM
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_PRIVATE3_VERSION
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_READFN0
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_READPTR
+I: struct mixer_private_ioctl
+O: struct mixer_private_ioctl
+
+N: CMD_SETCTLGPR
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETGPOUT
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETGPR
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETGPR2OSS
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETMCH_FX
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETPASSTHROUGH
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETPATCH
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETRECSRC
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_SETVOICEPARAM
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_WRITEFN0
+I: struct mixer_private_ioctl
+O: -
+
+N: CMD_WRITEPTR
+I: struct mixer_private_ioctl
+O: -
+
+N: CMTPCONNADD
+I: struct cmtp_connadd_req
+O: struct cmtp_connadd_req
+
+N: CMTPCONNDEL
+I: struct cmtp_conndel_req
+O: -
+
+N: CMTPGETCONNINFO
+I: struct cmtp_conninfo
+O: struct cmtp_conninfo
+
+N: CMTPGETCONNLIST
+I: struct cmtp_connlist_req
+O: struct cmtp_connlist_req
+
+N: COM_CLRPORTSTATS
+I: comstats_t
+O: comstats_t
+
+N: COM_GETBRDSTATS
+I: combrd_t
+O: combrd_t
+
+N: COM_GETPORTSTATS
+I: comstats_t
+O: comstats_t
+
+N: COM_READBOARD
+I: stlbrd_t
+O: stlbrd_t
+
+COM_READPANEL
+
+N: COM_READPORT
+I: stlport_t
+O: stlport_t
+
+N: COSAIOBMGET
+I: -
+O: -
+
+N: COSAIOBMSET
+I: (unsigned short) arg
+O: -
+
+N: COSAIODOWNLD
+I: struct cosa_download
+O:
+
+N: COSAIONRCARDS
+I: -
+O: -
+
+N: COSAIONRCHANS
+I: -
+O: -
+
+N: COSAIORIDSTR
+I: -
+O: char [COSA_MAX_ID_STRING]
+
+N: COSAIORMEM
+I: struct cosa_download
+O: -
+
+N: COSAIORSET
+I: -
+O: -
+
+N: COSAIORTYPE
+I: -
+O: char [strlen(struct cosa_data::type) + 1]
+
+N: COSAIOSTRT
+I: (int) arg
+O: -
+
+N: CPQFC_IOCTL_FC_TDR
+I: -
+O: -
+
+N: D7SIOCRD
+I: -
+O: int
+
+N: D7SIOCTM
+I: -
+O: -
+
+N: D7SIOCWR
+I: int
+O: -
+
+N: DASDAPIVER
+I: -
+O: int
+
+DECODER_DUMP
+DECODER_ENABLE_OUTPUT
+DECODER_GET_CAPABILITIES
+DECODER_GET_STATUS
+DECODER_INDYCAM_GET_CONTROLS
+DECODER_INDYCAM_SET_CONTROLS
+DECODER_INIT
+DECODER_SAA7191_GET_CONTROLS
+DECODER_SAA7191_GET_STATUS
+DECODER_SAA7191_SET_CONTROLS
+DECODER_SAA7191_SET_NORM
+DECODER_SET_GPIO
+DECODER_SET_INPUT
+DECODER_SET_NORM
+DECODER_SET_OUTPUT
+DECODER_SET_PICTURE
+DECODER_SET_VBI_BYPASS
+
+N: DEVFSDIOC_GET_PROTO_REV
+I: -
+O: int
+
+N: DEVFSDIOC_RELEASE_EVENT_QUEUE
+I: -
+O: -
+
+N: DEVFSDIOC_SET_DEBUG_MASK
+I: int
+O: -
+
+N: DEVFSDIOC_SET_EVENT_MASK
+I: (int) arg
+O: -
+
+DMX_GET_CAPS
+DMX_GET_EVENT
+DMX_GET_PES_PIDS
+DMX_GET_STC
+DMX_SET_BUFFER_SIZE
+DMX_SET_FILTER
+DMX_SET_PES_FILTER
+DMX_SET_SOURCE
+DMX_START
+DMX_STOP
+DM_DEV_CREATE
+DM_DEV_CREATE_32
+DM_DEV_REMOVE
+DM_DEV_REMOVE_32
+DM_DEV_RENAME
+DM_DEV_RENAME_32
+DM_DEV_STATUS
+DM_DEV_STATUS_32
+DM_DEV_SUSPEND
+DM_DEV_SUSPEND_32
+DM_DEV_WAIT
+DM_DEV_WAIT_32
+DM_LIST_DEVICES
+DM_LIST_DEVICES_32
+DM_LIST_VERSIONS
+DM_LIST_VERSIONS_32
+DM_REMOVE_ALL
+DM_REMOVE_ALL_32
+DM_TABLE_CLEAR
+DM_TABLE_CLEAR_32
+DM_TABLE_DEPS
+DM_TABLE_DEPS_32
+DM_TABLE_LOAD
+DM_TABLE_LOAD_32
+DM_TABLE_STATUS
+DM_TABLE_STATUS_32
+DM_TARGET_MSG
+DM_TARGET_MSG_32
+DM_VERSION
+DM_VERSION_32
+
+N: DPT_BLINKLED
+I: -
+O: u32
+
+DPT_CLRSTAT
+DPT_CONFIG
+
+N: DPT_CTRLINFO
+I: -
+O: drvrHBAinfo_S
+
+DPT_DEBUG
+DPT_NUMCTRLS
+DPT_PERF_INFO
+
+N: DPT_SIGNATURE
+I: -
+O: static dpt_sig_S
+
+DPT_SIGNATURE_PACKED
+DPT_STATINFO
+DPT_STATS_CLEAR
+DPT_STATS_INFO
+
+N: DPT_SYSINFO
+I: -
+O: struct sysInfo_S
+
+DPT_TARGET_BUSY
+DPT_TIMEOUT
+DRM32_IOCTL_ADD_MAP
+DRM32_IOCTL_DMA
+DRM32_IOCTL_FREE_BUFS
+DRM32_IOCTL_GET_UNIQUE
+DRM32_IOCTL_INFO_BUFS
+DRM32_IOCTL_MAP_BUFS
+DRM32_IOCTL_RES_CTX
+DRM32_IOCTL_SET_UNIQUE
+DRM32_IOCTL_VERSION
+
+N: DRM_IOCTL_ADD_BUFS
+I: struct drm_buf_desc
+O: struct drm_buf_desc
+
+N: DRM_IOCTL_ADD_CTX
+I: struct drm_ctx
+O: struct drm_ctx
+
+N: DRM_IOCTL_ADD_DRAW
+I: -
+O: struct drm_draw
+
+N: DRM_IOCTL_AUTH_MAGIC
+I: struct drm_auth
+O: -
+
+N: DRM_IOCTL_BLOCK
+I: -
+O: -
+
+N: DRM_IOCTL_CONTROL
+I: struct drm_control
+O: -
+
+N: DRM_IOCTL_FINISH
+I: -
+O: -
+
+N: DRM_IOCTL_GET_CTX
+I: struct drm_ctx
+O: struct drm_ctx
+
+N: DRM_IOCTL_GET_MAGIC
+I: -
+O: struct drm_auth
+
+N: DRM_IOCTL_IRQ_BUSID
+I: struct drm_irq_busid
+O: struct drm_irq_busid
+
+N: DRM_IOCTL_LOCK
+I: struct drm_lock
+O: -
+
+N: DRM_IOCTL_MARK_BUFS
+I: struct drm_buf_desc
+O: -
+
+N: DRM_IOCTL_MOD_CTX
+I: -
+O: -
+
+N: DRM_IOCTL_NEW_CTX
+I: struct drm_ctx
+O: -
+
+N: DRM_IOCTL_RM_CTX
+I: struct drm_ctx
+O: -
+
+N: DRM_IOCTL_RM_DRAW
+I: -
+O: -
+
+N: DRM_IOCTL_SWITCH_CTX
+I: struct drm_ctx
+O: -
+
+N: DRM_IOCTL_UNBLOCK
+I: -
+O: -
+
+N: DRM_IOCTL_UNLOCK
+I: struct drm_lock
+O: -
+
+DS_ACCESS_CONFIGURATION_REGISTER
+DS_ADJUST_RESOURCE_INFO
+DS_BIND_MTD
+DS_BIND_REQUEST
+DS_EJECT_CARD
+DS_GET_CONFIGURATION_INFO
+DS_GET_DEVICE_INFO
+DS_GET_FIRST_REGION
+DS_GET_FIRST_TUPLE
+DS_GET_FIRST_WINDOW
+DS_GET_MEM_PAGE
+DS_GET_NEXT_DEVICE
+DS_GET_NEXT_REGION
+DS_GET_NEXT_TUPLE
+DS_GET_NEXT_WINDOW
+DS_GET_STATUS
+DS_GET_TUPLE_DATA
+DS_INSERT_CARD
+DS_PARSE_TUPLE
+DS_REPLACE_CIS
+DS_RESET_CARD
+DS_RESUME_CARD
+DS_SUSPEND_CARD
+DS_UNBIND_REQUEST
+DS_VALIDATE_CIS
+
+N: DV1394_IOC_RECEIVE_FRAMES
+I: (unsigned int) arg
+O: -
+
+N: DV1394_IOC_SHUTDOWN
+I: -
+O: -
+
+N: DV1394_IOC_START_RECEIVE
+I: -
+O: -
+
+N: DV1394_IOC_SUBMIT_FRAMES
+I: (unsigned int) arg
+O: -
+
+N: DV1394_IOC_WAIT_FRAMES
+I: (unsigned int) arg
+O: -
+
+N: DVD_AUTH
+I: dvd_authinfo
+O: dvd_authinfo
+
+N: DVD_READ_STRUCT
+I: dvd_struct
+O: dvd_struct
+
+DVD_WRITE_STRUCT
+EATAUSRCMD
+ENCODER_ENABLE_OUTPUT
+ENCODER_GET_CAPABILITIES
+ENCODER_SET_INPUT
+ENCODER_SET_NORM
+ENCODER_SET_OUTPUT
+
+N: ENI_MEMDUMP
+I: -
+O: -
+
+N: ENI_SETMULT
+I: struct eni_multipliers
+O: -
+
+ENVCTRL_RD_CPU_TEMPERATURE
+ENVCTRL_RD_CPU_VOLTAGE
+ENVCTRL_RD_ETHERNET_TEMPERATURE
+ENVCTRL_RD_FAN_STATUS
+ENVCTRL_RD_GLOBALADDRESS
+ENVCTRL_RD_MTHRBD_TEMPERATURE
+ENVCTRL_RD_SCSI_TEMPERATURE
+ENVCTRL_RD_SHUTDOWN_TEMPERATURE
+ENVCTRL_RD_VOLTAGE_STATUS
+ENVCTRL_RD_WARNING_TEMPERATURE
+EVIOCGABS(abs)
+
+N: EVIOCGEFFECTS
+I: -
+O: int
+
+N: EVIOCGID
+I: -
+O: struct input_id
+
+N: EVIOCGKEYCODE
+I: int
+O: int
+
+N: EVIOCGRAB
+I: (unsigned long) arg
+O: -
+
+N: EVIOCGVERSION
+I: -
+O: int
+
+N: EVIOCRMFF
+I: (int) arg
+O: -
+
+EVIOCSABS(abs)
+
+N: EVIOCSKEYCODE
+I: int + int
+O: -
+
+EXT2_IOC32_GETFLAGS
+EXT2_IOC32_GETVERSION
+EXT2_IOC32_SETFLAGS
+EXT2_IOC32_SETVERSION
+
+N: FBIOBLANK
+I: (int) arg
+O: -
+
+FBIOGATTR
+FBIOGCURMAX
+FBIOGCURPOS
+FBIOGCURSOR
+FBIOGCURSOR32
+
+N: FBIOGETCMAP
+I: struct fb_cmap_user + u16 [?] + u16 [?] + u16 [?]
+O: u16 [?]
+
+FBIOGETCMAP32
+
+N: FBIOGETCMAP_SPARC
+I: int + int + unsigned char __user * + unsigned char __user * + unsigned char
+__user *
+O: u8 [?] + u8 [?] + u8 [?]
+
+N: FBIOGET_CON2FBMAP
+I: struct fb_con2fbmap
+O: struct fb_con2fbmap
+
+N: FBIOGET_FSCREENINFO
+I: -
+O: struct fb_fix_screeninfo
+
+N: FBIOGET_VBLANK
+I: -
+O: struct fb_vblank
+
+N: FBIOGET_VSCREENINFO
+I: -
+O: struct fb_var_screeninfo
+
+N: FBIOGTYPE
+I: -
+O: struct fbtype
+
+FBIOGVIDEO
+
+N: FBIOPAN_DISPLAY
+I: struct fb_var_screeninfo
+O: -
+
+FBIOPUTCMAP
+FBIOPUTCMAP32
+FBIOPUTCMAP_SPARC
+
+N: FBIOPUT_CON2FBMAP
+I: struct fb_con2fbmap
+O: -
+
+N: FBIOPUT_VSCREENINFO
+I: struct fb_var_screeninfo
+O: struct fb_var_screeninfo
+
+FBIOSATTR
+FBIOSCURPOS
+FBIOSCURSOR
+FBIOSCURSOR32
+FBIOSVIDEO
+
+N: FBIO_ATY128_GET_MIRROR
+I: -
+O: __u32
+
+N: FBIO_ATY128_SET_MIRROR
+I: __u32
+O: -
+
+N: FBIO_CURSOR
+I: -
+O: -
+
+N: FBIO_GETCONTROL2
+I: -
+O: unsigned char
+
+N: FBIO_RADEON_GET_MIRROR
+I: -
+O: __u32
+
+N: FBIO_RADEON_SET_MIRROR
+I: __u32
+O: -
+
+N: FBIO_WAITEVENT
+I: -
+O: -
+
+N: FBIO_WAITFORVSYNC
+I: __u32
+O: -
+
+FBIO_WID_ALLOC
+FBIO_WID_FREE
+FBIO_WID_GET
+FBIO_WID_PUT
+FDCLRPRM
+FDDEFPRM
+FDDEFPRM32
+FDEJECT
+FDFLUSH
+FDFMTBEG
+FDFMTEND
+FDFMTTRK
+FDGETDRVPRM
+FDGETDRVPRM32
+FDGETDRVSTAT
+FDGETDRVSTAT32
+FDGETDRVTYP
+FDGETFDCSTAT
+FDGETFDCSTAT32
+FDGETMAXERRS
+FDGETPRM
+FDGETPRM32
+FDMSGOFF
+FDMSGON
+FDPOLLDRVSTAT
+FDPOLLDRVSTAT32
+FDRAWCMD
+FDRESET
+FDSETDRVPRM
+FDSETDRVPRM32
+FDSETEMSGTRESH
+FDSETMAXERRS
+FDSETPRM
+FDSETPRM32
+FDTWADDLE
+FDWERRORCLR
+FDWERRORGET
+FDWERRORGET32
+FE_DISEQC_RECV_SLAVE_REPLY
+FE_DISEQC_RESET_OVERLOAD
+FE_DISEQC_SEND_BURST
+FE_DISEQC_SEND_MASTER_CMD
+FE_DISHNETWORK_SEND_LEGACY_CMD
+FE_ENABLE_HIGH_LNB_VOLTAGE
+FE_GET_EVENT
+FE_GET_FRONTEND
+FE_GET_INFO
+FE_READ_BER
+FE_READ_SIGNAL_STRENGTH
+FE_READ_SNR
+FE_READ_STATUS
+FE_READ_UNCORRECTED_BLOCKS
+FE_SET_FRONTEND
+FE_SET_TONE
+FE_SET_VOLTAGE
+
+N: FIBMAP
+I: int
+O: int
+
+N: FIGETBSZ
+I: -
+O: int
+
+N: FIOASYNC
+I: int
+O: -
+
+N: FIOCLEX
+I: -
+O: -
+
+N: FIOGETOWN
+I: -
+O: int
+
+N: FIONBIO
+I: int
+O: -
+
+N: FIONCLEX
+I: -
+O: -
+
+N: FIONREAD
+I: -
+O: int
+
+N: FIOQSIZE
+I: -
+O: loff_t
+
+N: FIOSETOWN
+I: int
+O: -
+
+N: FSACTL_CLOSE_GET_ADAPTER_FIB
+I: (u32) arg
+O: -
+
+N: FSACTL_DELETE_DISK
+I: struct aac_delete_disk
+O: -
+
+N: FSACTL_FORCE_DELETE_DISK
+I: struct aac_delete_disk
+O: -
+
+N: FSACTL_GET_CONTAINERS
+I: -
+O: -
+
+N: FSACTL_GET_NEXT_ADAPTER_FIB
+I: struct fib_ioctl
+O: [struct hw_fib]
+
+N: FSACTL_GET_PCI_INFO
+I: -
+O: struct aac_pci_info
+
+N: FSACTL_MINIPORT_REV_CHECK
+I: -
+O: struct revision
+
+N: FSACTL_OPEN_GET_ADAPTER_FIB
+I: -
+O: u32
+
+N: FSACTL_QUERY_DISK
+I: struct aac_query_disk
+O: struct aac_query_disk
+
+FSACTL_SENDFIB
+FSACTL_SEND_LARGE_FIB
+FSACTL_SEND_RAW_SRB
+
+N: GADGETFS_CLEAR_HALT
+I: -
+O: -
+
+N: GADGETFS_FIFO_FLUSH
+I: -
+O: -
+
+N: GADGETFS_FIFO_STATUS
+I: -
+O: -
+
+GCAOFF
+GCAON
+GCDESCRIBE
+GCFASTLOCK
+GCID
+GCLOCK
+GCLOCK_MINIMUM
+GCMAP
+GCMAP_HPUX
+GCOFF
+GCON
+GCSTATIC_CMAP
+GCTERM
+GCUNLOCK
+GCUNLOCK_MINIMUM
+GCUNMAP
+GCUNMAP_HPUX
+GCVARIABLE_CMAP
+GET_ARRAY_INFO
+GET_BITMAP_FILE
+GET_DISK_INFO
+GIO_FONT
+GIO_FONTX
+
+N: GIO_SCRNMAP
+I: -
+O: unsigned char [E_TABSZ]
+
+GIO_UNIMAP
+GIO_UNISCRNMAP
+
+N: HCIDEVDOWN
+I: (__u16) arg
+O: -
+
+N: HCIDEVRESET
+I: (__u16) arg
+O: -
+
+N: HCIDEVRESTAT
+I: (__u16) arg
+O: -
+
+N: HCIDEVUP
+I: (__u16) arg
+O: -
+
+N: HCIGETCONNINFO
+I: struct hci_conn_info_req
+O: struct hci_conn_info
+
+N: HCIGETCONNLIST
+I: struct hci_conn_list_req
+O: struct hci_conn_info
+
+N: HCIGETDEVINFO
+I: struct hci_dev_info
+O: struct hci_dev_info
+
+HCIGETDEVLIST
+
+N: HCIINQUIRY
+I: struct hci_inquiry_req
+O: struct hci_inquiry_req + struct inquiry_info [?]
+
+N: HCISETACLMTU
+I: struct hci_dev_req
+O: -
+
+N: HCISETAUTH
+I: struct hci_dev_req
+O: -
+
+N: HCISETENCRYPT
+I: struct hci_dev_req
+O: -
+
+N: HCISETLINKMODE
+I: struct hci_dev_req
+O: -
+
+N: HCISETLINKPOL
+I: struct hci_dev_req
+O: -
+
+N: HCISETPTYPE
+I: struct hci_dev_req
+O: -
+
+N: HCISETRAW
+I: (nusigned long) arg
+O: -
+
+N: HCISETSCAN
+I: struct hci_dev_req
+O: -
+
+N: HCISETSCOMTU
+I: struct hci_dev_req
+O: -
+
+N: HCISETSECMGR
+I: (nusigned long) arg
+O: -
+
+N: HCIUARTGETPROTO
+I: -
+O: -
+
+N: HCIUARTSETPROTO
+I: (int) arg
+O: -
+
+HDIO_DRIVE_CMD
+HDIO_DRIVE_TASK
+HDIO_GETGEO
+HDIO_GET_32BIT
+HDIO_GET_DMA
+HDIO_GET_IDENTITY
+HDIO_GET_KEEPSETTINGS
+HDIO_GET_MULTCOUNT
+HDIO_GET_NICE
+HDIO_GET_NOWERR
+HDIO_GET_UNMASKINTR
+HDIO_SCAN_HWIF
+HDIO_SET_32BIT
+HDIO_SET_DMA
+HDIO_SET_KEEPSETTINGS
+HDIO_SET_MULTCOUNT
+HDIO_SET_NICE
+HDIO_SET_NOWERR
+HDIO_SET_PIO_MODE
+HDIO_SET_UNMASKINTR
+
+N: HE_GET_REG
+I: struct he_ioctl_reg
+O: struct he_ioctl_reg
+
+N: HIDIOCAPPLICATION
+I: (unsigned) arg
+O: -
+
+N: HIDIOCGCOLLECTIONINDEX
+I: struct hiddev_usage_ref
+O: -
+
+N: HIDIOCGCOLLECTIONINFO
+I: struct hiddev_collection_info
+O: struct hiddev_collection_info
+
+N: HIDIOCGDEVINFO
+I: -
+O: struct hiddev_devinfo
+
+N: HIDIOCGFIELDINFO
+I: -
+O: struct hiddev_field_info
+
+N: HIDIOCGFLAG
+I: -
+O: int
+
+N: HIDIOCGREPORT
+I: struct hiddev_report_info
+O -
+
+N: HIDIOCGREPORTINFO
+I: struct hiddev_report_info
+O: struct hiddev_report_info
+
+HIDIOCGSTRING
+
+N: HIDIOCGUCODE
+I: struct hiddev_usage_ref
+O: struct hiddev_usage_ref
+
+N: HIDIOCGUSAGE
+I: struct hiddev_usage_ref
+O: struct hiddev_usage_ref
+
+N: HIDIOCGUSAGES
+I: struct hiddev_usage_ref_multi
+O: struct hiddev_usage_ref_multi
+
+N: HIDIOCGVERSION
+I: -
+O: int
+
+N: HIDIOCINITREPORT
+I: -
+O: -
+
+N: HIDIOCSFLAG
+I: int
+O: -
+
+N: HIDIOCSREPORT
+I: struct hiddev_report_info
+O: -
+
+N: HIDIOCSUSAGE
+I: struct hiddev_usage_ref
+O: -
+
+N: HIDIOCSUSAGES
+I: struct hiddev_usage_ref_multi
+O: -
+
+N: HIDPCONNADD
+I: struct hidp_connadd_req
+O: struct hidp_connadd_req
+
+N: HIDPCONNDEL
+I: struct hidp_conndel_req
+O -
+
+N: HIDPGETCONNINFO
+I: struct hidp_conninfo
+O: struct hidp_conninfo
+
+N: HIDPGETCONNLIST
+I: struct hidp_connlist_req
+O: struct hidp_connlist_req
+
+HOT_ADD_DISK
+HOT_GENERATE_ERROR
+HOT_REMOVE_DISK
+
+N: HPET_DPI
+I: -
+O: -
+
+N: HPET_EPI
+I: -
+O: -
+
+N: HPET_IE_OFF
+I: -
+O: -
+
+N: HPET_IE_ON
+I: -
+O: -
+
+N: HPET_INFO
+I: -
+O: struct hpet_info
+
+N: HPET_IRQFREQ
+I: (unsigned long) arg
+O: -
+
+N: I2C_FUNCS
+I: -
+O: unsigned long
+
+N: I2C_PEC
+I: (unsigned long) arg
+O: -
+
+I2C_RDWR
+
+N: I2C_RETRIES
+I: (int) arg
+O: -
+
+N: I2C_SLAVE
+I: (int) arg
+O: -
+
+N: I2C_SLAVE_FORCE
+I: (int) arg
+O: -
+
+I2C_SMBUS
+
+N: I2C_TENBIT
+I: (unsigned long) arg
+O: -
+
+N: I2C_TIMEOUT
+I: (int) arg
+O: -
+
+N: I2OEVTGET
+I: -
+O: struct i2o_evt_get
+
+N: I2OEVTREG
+I: struct i2o_evt_id
+O: -
+
+N: I2OGETIOPS
+I: -
+O: u8 [MAX_I2O_CONTROLLERS];
+
+I2OHRTGET
+I2OHTML
+I2OLCTGET
+I2OPARMGET
+I2OPARMSET
+I2OPASSTHRU
+I2OPASSTHRU32
+
+N: I2ORESCANCMD
+I: -
+O: -
+
+N: I2ORESETCMD
+I: -
+O: -
+
+N: I2OSWDEL
+I: struct i2o_sw_xfer + unsigned int
+O: -
+
+I2OSWDL
+I2OSWUL
+I2OUSRCMD
+
+N: I2OVALIDATE
+I: (int) arg
+O: -
+
+N: I8K_BIOS_VERSION
+I: -
+O: int
+
+N: I8K_FN_STATUS
+I: -
+O: int
+
+N: I8K_GET_FAN
+I: int
+O: int
+
+N: I8K_GET_SPEED
+I: int
+O: int
+
+N: I8K_GET_TEMP
+I: -
+O: int
+
+N: I8K_MACHINE_ID
+I: -
+O: unsigned char [16]
+
+N: I8K_POWER_STATUS
+I: -
+O: int
+
+N: I8K_SET_FAN
+I: int + int
+O: int
+
+N: IDT77105_GETSTAT
+I: -
+O: struct idt77105_stats
+
+N: IDT77105_GETSTATZ
+I: -
+O: struct idt77105_stats
+
+IIOCDBGVAR
+IIOCDELRULE
+IIOCDOCFACT
+IIOCDOCFDIS
+IIOCDOCFINT
+IIOCDODFACT
+IIOCDRVCTL
+IIOCGETCPS
+IIOCGETDRV
+IIOCGETDVR
+IIOCGETMAP
+IIOCGETNAM
+IIOCGETPRF
+IIOCGETRULE
+IIOCGETSET
+IIOCGETVER
+IIOCINSRULE
+IIOCMODRULE
+IIOCNETAIF
+IIOCNETALN
+IIOCNETANM
+IIOCNETASL
+IIOCNETDIF
+IIOCNETDIL
+IIOCNETDLN
+IIOCNETDNM
+IIOCNETDWRSET
+IIOCNETGCF
+IIOCNETGNM
+IIOCNETGPN
+IIOCNETHUP
+IIOCNETLCR
+IIOCNETSCF
+IIOCSETBRJ
+IIOCSETGST
+IIOCSETMAP
+IIOCSETPRF
+IIOCSETSET
+IIOCSETVER
+IIOCSIGPRF
+IOCTL_AU_BUFLEN
+IOCTL_AU_CONNECT
+IOCTL_AU_DEVINFO
+IOCTL_AU_RXAVAIL
+IOCTL_AU_SERVREQ
+IOCTL_AU_SLEN
+IOCTL_AU_TXREADY
+IOCTL_DAB_BULK
+IOCTL_DAB_OVERRUNS
+IOCTL_DAB_VERSION
+IOCTL_MW_DSP_ABILITIES
+IOCTL_MW_GET_IPC
+IOCTL_MW_READCLEAR_DATA
+IOCTL_MW_READ_DATA
+IOCTL_MW_READ_INST
+IOCTL_MW_REGISTER_IPC
+IOCTL_MW_RESET
+IOCTL_MW_RUN
+IOCTL_MW_TRACE
+IOCTL_MW_UNREGISTER_IPC
+IOCTL_MW_WRITE_DATA
+IOCTL_MW_WRITE_INST
+IOCTL_TIPAR_DELAY
+IOCTL_TIPAR_TIMEOUT
+IOCTL_TISER_DELAY
+IOCTL_TISER_TIMEOUT
+IOCTL_TIUSB_GET_DEVID
+IOCTL_TIUSB_GET_MAXPS
+IOCTL_TIUSB_RESET_DEVICE
+IOCTL_TIUSB_RESET_PIPES
+IOCTL_TIUSB_TIMEOUT
+
+N: IOC_NVRAM_GET_OFFSET
+I: int
+O: int
+
+N: IOC_NVRAM_SYNC
+I: -
+O: -
+
+N: IRTTY_IOCGET
+I: -
+O: struct irtty_info
+
+N: IRTTY_IOCTDONGLE
+I: (IRDA_DONGLE) arg
+O: -
+
+N: IXJCTL_AEC_GET_LEVEL
+I: -
+O: -
+
+N: IXJCTL_AEC_START
+I: (int) arg
+O: -
+
+N: IXJCTL_AEC_STOP
+I: -
+O: -
+
+N: IXJCTL_CARDTYPE
+I: -
+O: -
+
+N: IXJCTL_CID
+I: -
+O: PHONE_CID
+
+N: IXJCTL_CIDCW
+I: PHONE_CID
+O: -
+
+N: IXJCTL_DAA_AGAIN
+I: (char) arg
+O: -
+
+N: IXJCTL_DAA_COEFF_SET
+I: (unsigned long) arg
+O: -
+
+N: IXJCTL_DRYBUFFER_CLEAR
+I: -
+O: -
+
+N: IXJCTL_DRYBUFFER_READ
+I: -
+O: unsigned long
+
+N: IXJCTL_DSP_IDLE
+I: -
+O: -
+
+IXJCTL_DSP_RESET
+
+N: IXJCTL_DSP_TYPE
+I: -
+O: -
+
+N: IXJCTL_DSP_VERSION
+I: -
+O: -
+
+N: IXJCTL_DTMF_PRESCALE
+I: (int) arg
+O: -
+
+N: IXJCTL_FILTER_CADENCE
+I: IXJ_FILTER_CADENCE
+O: -
+
+N: IXJCTL_FRAMES_READ
+I: -
+O: unsigned long
+
+N: IXJCTL_FRAMES_WRITTEN
+I: -
+O: unsigned long
+
+N: IXJCTL_GET_FILTER_HIST
+I: (unsigned long) arg
+O: -
+
+N: IXJCTL_HZ
+I: (int) arg
+O: -
+
+N: IXJCTL_INIT_TONE
+I: IXJ_TONE
+O: -
+
+N: IXJCTL_INTERCOM_START
+I: (int) arg
+O: -
+
+N: IXJCTL_INTERCOM_STOP
+I: (int) arg
+O: -
+
+N: IXJCTL_MIXER
+I: (long) arg
+O: -
+
+IXJCTL_PLAY_CID
+
+N: IXJCTL_PORT
+I: (int) arg
+O: -
+
+N: IXJCTL_POTS_PSTN
+I: (int) arg
+O: -
+
+N: IXJCTL_PSTN_LINETEST
+I: -
+O: -
+
+N: IXJCTL_RATE
+I: (int) arg
+O: -
+
+N: IXJCTL_READ_WAIT
+I: -
+O: unsigned long
+
+N: IXJCTL_SC_RXG
+I: (int) arg
+O: -
+
+N: IXJCTL_SC_TXG
+I: (int) arg
+O: -
+
+N: IXJCTL_SERIAL
+I: -
+O: -
+
+N: IXJCTL_SET_FILTER
+I: IXJ_FILTER
+O: -
+
+N: IXJCTL_SET_FILTER_RAW
+I: IXJ_FILTER_RAW
+O: -
+
+N: IXJCTL_SET_LED
+I: (int) arg
+O: -
+
+N: IXJCTL_SIGCTL
+I: IXJ_SIGDEF
+O: -
+
+N: IXJCTL_TESTRAM
+I: -
+O: -
+
+IXJCTL_TONE_CADENCE
+
+N: IXJCTL_VERSION
+I: -
+O: "\nDriver version IXJ_VER_MAJOR.IXJ_VER_MINOR.IXJ_BLD_VER"
+
+N: IXJCTL_VMWI
+I: (int) arg
+O: -
+
+N: IXJCTL_WRITE_WAIT
+I: -
+O: unsigned long
+
+N: JFFS_GET_STATUS
+I: -
+O: struct jffs_flash_status
+
+N: JFFS_PRINT_HASH
+I: -
+O: -
+
+N: JFFS_PRINT_TREE
+I: -
+O: -
+
+N: JSIOCGAXES
+I: -
+O: __u8
+
+N: JSIOCGAXMAP
+I: -
+O: __u8 [ABS_MAX + 1]
+
+N: JSIOCGBTNMAP
+I: -
+O: __u16 [KEY_MAX - BTN_MISC + 1]
+
+N: JSIOCGBUTTONS
+I: -
+O: __u8
+
+JSIOCGCORR
+
+N: JSIOCGVERSION
+I: -
+O: __u32
+
+N: JSIOCSAXMAP
+I: __u8 [ABS_MAX + 1]
+O: -
+
+N: JSIOCSBTNMAP
+I: __u16 [KEY_MAX - BTN_MISC + 1]
+O: -
+
+JSIOCSCORR
+KDFONTOP
+
+N: KDGETKEYCODE
+I: struct kbkeycode
+O: unsigned int
+
+N: KDGETLED
+I: -
+O: unsigned char
+
+N: KDGETMODE
+I: -
+O: unsigned char
+
+KDGHWCLK
+KDGKBDIACR
+
+N: KDGKBENT
+I: struct kbentry
+O: unsigned short
+
+N: KDGKBLED
+I: -
+O: unsigned char
+
+N: KDGKBMETA
+I: -
+O: unsigned char
+
+N: KDGKBMODE
+I: -
+O: unsigned char
+
+KDGKBSENT
+
+N: KDGKBTYPE
+I: -
+O: unsigned char
+
+N: KDKBDREP
+I: struct kbd_repeat
+O: struct kbd_repeat
+
+N: KDMKTONE
+I: (unsigned int) arg
+O: -
+
+N: KDSETKEYCODE
+I: struct kbkeycode
+O: -
+
+N: KDSETLED
+I: (unsigned int) arg
+O: -
+
+N: KDSETMODE
+I: (unsigned char) arg
+O: -
+
+KDSHWCLK
+
+N: KDSIGACCEPT
+I: (int) arg
+O: -
+
+KDSKBDIACR
+
+N: KDSKBENT
+I: struct kbentry
+O: -
+
+N: KDSKBLED
+I: (unsigned char) arg
+O: -
+
+N: KDSKBMETA
+I: (unsigned char) arg
+O: -
+
+N: KDSKBMODE
+I: (unsigned char) arg
+O: -
+
+KDSKBSENT
+KIOCCMD
+KIOCGLED
+KIOCGRATE
+KIOCGTRANS
+KIOCLAYOUT
+KIOCSDIRECT
+KIOCSLED
+
+N: KIOCSOUND
+I: (unsigned int) arg
+O: -
+
+KIOCSRATE
+KIOCTRANS
+KIOCTYPE
+
+N: KYRO_IOCTL_OVERLAY_CREATE
+I: overlay_create
+O: -
+
+N: KYRO_IOCTL_OVERLAY_OFFSET
+I: -
+O: unsigned long
+
+N: KYRO_IOCTL_OVERLAY_VIEWPORT_SET
+I: overlay_viewport_set
+O: -
+
+N: KYRO_IOCTL_SET_VIDEO_MODE
+I: -
+O: -
+
+N: KYRO_IOCTL_STRIDE
+I: -
+O: unsigned long
+
+N: KYRO_IOCTL_UVSTRIDE
+I: -
+O: unsigned long
+
+LEO_CLUTALLOC
+LEO_CLUTFREE
+LEO_CLUTPOST
+LEO_CLUTREAD
+LEO_GETGAMMA
+LEO_SETGAMMA
+
+N: LOOP_CHANGE_FD
+I: (unsigned int) arg
+O: -
+
+N: LOOP_CLR_FD
+I: -
+O: -
+
+N: LOOP_GET_STATUS
+I: -
+O: struct loop_info
+
+N: LOOP_GET_STATUS64
+I: -
+O: struct loop_info64
+
+N: LOOP_SET_FD
+I: (unsigned int) arg
+O: -
+
+N: LOOP_SET_STATUS
+I: struct loop_info
+O: -
+
+N: LOOP_SET_STATUS64
+I: struct loop_info64
+O: -
+
+N: LPGETSTATUS
+I: -
+O: int
+
+N: MATROXFB_GET_ALL_OUTPUTS
+I: -
+O: u_int32_t
+
+N: MATROXFB_GET_AVAILABLE_OUTPUTS
+I: -
+O: u_int32_t
+
+N: MATROXFB_GET_OUTPUT_CONNECTION
+I: -
+O: u_int32_t
+
+N: MATROXFB_GET_OUTPUT_MODE
+I: struct matroxioc_output_mode
+O: struct matroxioc_output_mode
+
+N: MATROXFB_SET_OUTPUT_CONNECTION
+I: u_int32_t
+O: -
+
+N: MATROXFB_SET_OUTPUT_MODE
+I: struct matroxioc_output_mode
+O: -
+
+N: MCE_GETCLEAR_FLAGS
+I: -
+O: unsigned
+
+N: MCE_GET_LOG_LEN
+I: -
+O: int
+
+N: MCE_GET_RECORD_LEN
+I: -
+O: int
+
+MEGAIOCCMD
+
+N: MEMERASE
+I: struct erase_info_user
+O: -
+
+N: MEMGETBADBLOCK
+I: loff_t
+O: -
+
+N: MEMGETINFO
+I: -
+O: struct mtd_info_user
+
+N: MEMGETOOBSEL
+I: -
+O: struct nand_oobinfo
+
+N: MEMGETREGIONCOUNT
+I: -
+O: int
+
+N: MEMGETREGIONINFO
+I: struct region_info_user
+O: struct mtd_erase_region_info
+
+N: MEMLOCK
+I: struct erase_info_user
+O: -
+
+N: MEMREADOOB
+I: struct mtd_oob_buf
+O: uint32_t retlen + unsigned char [retlen]
+
+MEMREADOOB32
+
+N: MEMSETBADBLOCK
+I: loff_t
+O: -
+
+N: MEMSETOOBSEL
+I: struct nand_oobinfo
+O: -
+
+N: MEMUNLOCK
+I: struct erase_info_user
+O: -
+
+N: MEMWRITEOOB
+I: struct mtd_oob_buf + unsigned char [struct mtd_oob_buf::length]
+O: uint32_t
+
+MEMWRITEOOB32
+MEYEIOC_G_PARAMS
+MEYEIOC_QBUF_CAPT
+MEYEIOC_STILLCAPT
+MEYEIOC_STILLJCAPT
+MEYEIOC_SYNC
+MEYEIOC_S_PARAMS
+
+MGSL_IOCCLRMODCOUNT
+
+N: MGSL_IOCGIF
+I: -
+O: int
+
+N: MGSL_IOCGSTATS
+I: -
+O: struct mgsl_icount
+
+N: MGSL_IOCGTXIDLE
+I: -
+O: int
+
+N: MGSL_IOCLOOPTXDONE
+I: -
+O: -
+
+N: MGSL_IOCRXENABLE
+I: (int) arg
+O: -
+
+N: MGSL_IOCSIF
+I: (int) arg
+O: -
+
+N: MGSL_IOCSTXIDLE
+I: (int) arg
+O: -
+
+N: MGSL_IOCTXABORT
+I: -
+O: -
+
+N: MGSL_IOCTXENABLE
+I: (int) arg
+O: -
+
+N: MICROCODE_IOCFREE
+I: -
+O: -
+
+N: MMTIMER_GETBITS
+I: -
+O: -
+
+N: MMTIMER_GETOFFSET
+I: -
+O: -
+
+N: MMTIMER_MMAPAVAIL
+I: -
+O: -
+
+MPTCOMMAND
+MPTCOMMAND32
+MPTEVENTENABLE
+MPTEVENTQUERY
+MPTEVENTREPORT
+MPTFWDOWNLOAD
+MPTFWDOWNLOAD32
+MPTFWREPLACE
+MPTHARDRESET
+MPTIOCINFO
+MPTIOCINFO1
+MPTIOCINFO2
+MPTRWPERF
+MPTTARGETINFO
+MPTTEST
+MSP_GET_DFPREG
+MSP_SET_DFPREG
+MSP_SET_MATRIX
+MTIOCFTCMD
+MTIOCFTFORMAT
+MTIOCGET
+MTIOCGET32
+MTIOCGETCONFIG
+MTIOCGETSIZE
+MTIOCPOS
+MTIOCPOS32
+MTIOCRDFTSEG
+MTIOCSETCONFIG
+MTIOCTOP
+MTIOCVOLINFO
+MTIOCWRFTSEG
+MTIOC_ZFTAPE_GETBLKSZ
+MTRRIOC32_ADD_ENTRY
+MTRRIOC32_ADD_PAGE_ENTRY
+MTRRIOC32_DEL_ENTRY
+MTRRIOC32_DEL_PAGE_ENTRY
+MTRRIOC32_GET_ENTRY
+MTRRIOC32_GET_PAGE_ENTRY
+MTRRIOC32_KILL_ENTRY
+MTRRIOC32_KILL_PAGE_ENTRY
+MTRRIOC32_SET_ENTRY
+MTRRIOC32_SET_PAGE_ENTRY
+MXB_S_AUDIO_CD
+MXB_S_AUDIO_LINE
+
+N: NBD_CLEAR_QUE
+I: -
+O: -
+
+N: NBD_CLEAR_SOCK
+I: -
+O: -
+
+N: NBD_DISCONNECT
+I: -
+O: -
+
+N: NBD_DO_IT
+I: -
+O: -
+
+N: NBD_PRINT_DEBUG
+I: -
+O: -
+
+N: NBD_SET_BLKSIZE
+I: (int) arg
+O: -
+
+N: NBD_SET_SIZE
+I: (u64) arg
+O: -
+
+N: NBD_SET_SIZE_BLOCKS
+I: (u64) arg
+O: -
+
+N: NBD_SET_SOCK
+I: (unsigned int) arg
+O: -
+
+N: NCP_IOC_CONN_LOGGED_IN
+I: -
+O: -
+
+N: NCP_IOC_GETCHARSETS
+I: -
+O: struct ncp_nls_ioctl
+
+N: NCP_IOC_GETDENTRYTTL
+I: -
+O: u_int32_t
+
+NCP_IOC_GETMOUNTUID2_32
+NCP_IOC_GETOBJECTNAME_32
+NCP_IOC_GETPRIVATEDATA_32
+
+N: NCP_IOC_GETROOT
+I: -
+O: struct ncp_setroot_ioctl
+
+NCP_IOC_GET_FS_INFO_V2_32
+
+N: NCP_IOC_LOCKUNLOCK
+I: struct ncp_lock_ioctl
+O: -
+
+NCP_IOC_NCPREQUEST_32
+
+N: NCP_IOC_SETCHARSETS
+I: struct ncp_nls_ioctl
+O: -
+
+N: NCP_IOC_SETDENTRYTTL
+I: u_int32_t
+O: -
+
+NCP_IOC_SETOBJECTNAME_32
+NCP_IOC_SETPRIVATEDATA_32
+
+N: NCP_IOC_SETROOT
+I: struct ncp_setroot_ioctl
+O: -
+
+N: NCP_IOC_SET_SIGN_WANTED
+I: unsigned char
+O: -
+
+N: NCP_IOC_SIGN_INIT
+I: [struct ncp_sign_init]
+O: -
+
+N: NCP_IOC_SIGN_WANTED
+I: -
+O: int
+
+NET_ADD_IF
+NET_GET_IF
+NET_REMOVE_IF
+
+N: NS_ADJBUFLEV
+I: (int) arg
+O: -
+
+N: NS_GETPSTAT
+I: int
+O: pool_levels
+
+N: NS_SETBUFLEV
+I: pool_levels
+O: -
+
+N: NVRAM_INIT
+I: -
+O: -
+
+N: NVRAM_SETCKS
+I: -
+O: -
+
+N: OLD_PHONE_RING_START
+I: -
+O: -
+
+OPIOCGET
+
+N: OPIOCGETCHILD
+I: int
+O: int
+
+N: OPIOCGETNEXT
+I: int
+O: int
+
+N: OPIOCGETOPTNODE
+I: -
+O: int
+
+OPIOCNEXTPROP
+OPIOCSET
+OPROMCHILD
+OPROMGETBOOTARGS
+OPROMGETCONS
+OPROMGETFBNAME
+OPROMGETOPT
+OPROMGETPROP
+OPROMNEXT
+OPROMNXTOPT
+OPROMNXTPROP
+OPROMPATH2NODE
+OPROMPCI2NODE
+OPROMSETCUR
+OPROMSETOPT
+OPROMSETOPT2
+OPROMU2P
+OSD_GET_CAPABILITY
+OSD_SEND_CMD
+
+N: OSS_GETVERSION
+I: -
+O: int
+
+N: OTPGETREGIONCOUNT
+I: -
+O: int
+
+OTPGETREGIONINFO
+
+N: OTPLOCK
+I: struct otp_info
+O: -
+
+N: OTPSELECT
+I: int
+O: -
+
+OV511IOC_RI2C
+OV511IOC_WI2C
+OVCAMCHIP_CMD_G_CTRL
+OVCAMCHIP_CMD_INITIALIZE
+OVCAMCHIP_CMD_Q_SUBTYPE
+OVCAMCHIP_CMD_S_CTRL
+OVCAMCHIP_CMD_S_MODE
+OVCAMCHIP_MAX_CMD
+
+N: PACKET_CTRL_CMD
+I: struct pkt_ctrl_command
+O: struct pkt_ctrl_command
+
+N: PA_PERF_OFF
+I: -
+O: uint32_t [4]
+
+N: PA_PERF_ON
+I: -
+O: -
+
+N: PA_PERF_VERSION
+I: -
+O: int
+
+N: PCIIOC_CONTROLLER
+I: -
+O: -
+
+N: PCIIOC_MMAP_IS_IO
+I: -
+O: -
+
+N: PCIIOC_MMAP_IS_MEM
+I: -
+O: -
+
+N: PCIIOC_WRITE_COMBINE
+I: (unsigned long) arg
+O: -
+
+N: PHONE_BUSY
+I: -
+O: -
+
+N: PHONE_CAPABILITIES
+I: -
+O: -
+
+N: PHONE_CAPABILITIES_CHECK
+I: struct phone_capability
+O: -
+
+PHONE_CAPABILITIES_LIST
+
+N: PHONE_CPT_STOP
+I: -
+O: -
+
+N: PHONE_DIALTONE
+I: -
+O: -
+
+N: PHONE_DTMF_OOB
+I: (unsigned int) arg
+O: -
+
+N: PHONE_DTMF_READY
+I: -
+O: -
+
+N: PHONE_EXCEPTION
+I: -
+O: -
+
+N: PHONE_FRAME
+I: (int) arg
+O: -
+
+N: PHONE_GET_DTMF
+I: -
+O: -
+
+N: PHONE_GET_DTMF_ASCII
+I: -
+O: -
+
+N: PHONE_GET_TONE_OFF_TIME
+I: -
+O: -
+
+N: PHONE_GET_TONE_ON_TIME
+I: -
+O: -
+
+N: PHONE_GET_TONE_STATE
+I: -
+O: -
+
+N: PHONE_HOOKSTATE
+I: -
+O: -
+
+N: PHONE_MAXRINGS
+I: (char) arg
+O: -
+
+N: PHONE_PLAY_CODEC
+I: (int) arg
+O: -
+
+N: PHONE_PLAY_DEPTH
+I: (int) arg
+O: -
+
+N: PHONE_PLAY_LEVEL
+I: -
+O: -
+
+N: PHONE_PLAY_START
+I: -
+O: -
+
+N: PHONE_PLAY_STOP
+I: -
+O: -
+
+N: PHONE_PLAY_TONE
+I: (char) arg
+O: -
+
+PHONE_PLAY_VOLUME
+PHONE_PLAY_VOLUME_LINEAR
+
+N: PHONE_PSTN_GET_STATE
+I: -
+O: -
+
+PHONE_PSTN_LINETEST
+
+N: PHONE_PSTN_SET_STATE
+I: (int) arg
+O: -
+
+N: PHONE_QUERY_CODEC
+I: struct phone_codec_data
+O: struct phone_codec_data
+
+N: PHONE_REC_CODEC
+I: (int) arg
+O: -
+
+N: PHONE_REC_DEPTH
+I: (int) arg
+O: -
+
+N: PHONE_REC_LEVEL
+I: -
+O: -
+
+N: PHONE_REC_START
+I: -
+O: -
+
+N: PHONE_REC_STOP
+I: -
+O: -
+
+PHONE_REC_VOLUME
+PHONE_REC_VOLUME_LINEAR
+
+N: PHONE_RING
+I: -
+O: -
+
+N: PHONE_RINGBACK
+I: -
+O: -
+
+N: PHONE_RING_CADENCE
+I: (unsigned short) arg
+O: -
+
+N: PHONE_RING_START
+I: [PHONE_CID]
+O: -
+
+N: PHONE_RING_STOP
+I: -
+O: -
+
+N: PHONE_SET_TONE_OFF_TIME
+I: (unsigned short) arg
+O: -
+
+N: PHONE_SET_TONE_ON_TIME
+I: (unsigned short) arg
+O: -
+
+N: PHONE_VAD
+I: (int) arg
+O: -
+
+N: PHONE_WINK
+I: -
+O: -
+
+PHONE_WINK_DURATION
+PIO_FONT
+PIO_FONTRESET
+PIO_FONTX
+
+N: PIO_SCRNMAP
+I: unsigned char [E_TABSZ]
+O: -
+
+PIO_UNIMAP
+
+N: PIO_UNIMAPCLR
+I: struct unimapinit
+O: -
+
+N: PIO_UNISCRNMAP
+I: unsigned short [E_TABSZ]
+O: -
+
+N: PLANBG_GRAB_BPL
+I: -
+O: int
+
+N: PLANBIOCGMODE
+I: -
+O: int
+
+N: PLANBIOCGSAAREGS
+I: struct planb_saa_regs
+O: struct planb_saa_regs
+
+N: PLANBIOCGSTAT
+I:
+O: struct planb_stat_regs
+
+N: PLANBIOCSMODE
+I: int
+O: -
+
+N: PLANBIOCSSAAREGS
+I: struct planb_saa_regs
+O: -
+
+PLANB_INTR_DEBUG
+
+N: PLANB_INV_REGS
+I: struct planb_any_regs
+O: struct planb_any_regs
+
+N: PMU_IOC_CAN_SLEEP
+I: -
+O: __u32
+
+N: PMU_IOC_GET_BACKLIGHT
+I: -
+O: int
+
+N: PMU_IOC_GET_MODEL
+I: -
+O: int
+
+N: PMU_IOC_GRAB_BACKLIGHT
+I: -
+O: -
+
+N: PMU_IOC_HAS_ADB
+I: -
+O: int
+
+N: PMU_IOC_SET_BACKLIGHT
+I: __u32
+O: -
+
+N: PMU_IOC_SLEEP
+I: -
+O: -
+
+N: PPCLAIM
+I: -
+O: -
+
+N: PPCLRIRQ
+I: -
+O: int
+
+N: PPDATADIR
+I: int
+O: -
+
+N: PPEXCL
+I: -
+O: -
+
+N: PPFCONTROL
+I: unsigned char + unsigned char
+O: -
+
+N: PPGETFLAGS
+I: -
+O: int
+
+N: PPGETMODE
+I: -
+O: int
+
+N: PPGETMODES
+I: -
+O: unsigned int
+
+N: PPGETPHASE
+I: -
+O: int
+
+N: PPGETTIME
+I: -
+O: struct timeval
+
+N: PPNEGOT
+I: int
+O: -
+
+N: PPPIOCATTACH
+I: int
+O: -
+
+N: PPPIOCATTCHAN
+I: int
+O: -
+
+N: PPPIOCBUNDLE
+I: unsigned long
+O: -
+
+N: PPPIOCCONNECT
+I: int
+O: -
+
+N: PPPIOCDETACH
+I: -
+O: -
+
+N: PPPIOCDISCONN
+I: -
+O: -
+
+N: PPPIOCGASYNCMAP
+I: -
+O: __u32
+
+N: PPPIOCGCALLINFO
+I: -
+O: struct pppcallinfo
+
+N: PPPIOCGCHAN
+I: -
+O: int
+
+N: PPPIOCGCOMPRESSORS
+I: -
+O: unsigned long [8]
+
+N: PPPIOCGDEBUG
+I: -
+O: unsigned long
+
+N: PPPIOCGFLAGS
+I: -
+O: unsigned int
+
+N: PPPIOCGIDLE
+I: -
+O: struct ppp_idle
+
+PPPIOCGIDLE32
+
+N: PPPIOCGIFNAME
+I: -
+O: char [10]
+
+N: PPPIOCGMPFLAGS
+I: -
+O: unsigned int
+
+N: PPPIOCGMRU
+I: -
+O: int
+
+N: PPPIOCGNPMODE
+I: struct npioctl
+O: struct npioctl
+
+N: PPPIOCGRASYNCMAP
+I: -
+O: u32
+
+N: PPPIOCGUNIT
+I: -
+O: int
+
+N: PPPIOCGXASYNCMAP
+I: -
+O: u32 [8]
+
+N: PPPIOCNEWUNIT
+I: int
+O: int
+
+N: PPPIOCSACTIVE
+I: struct sock_fprog + struct sock_fprog::len * struct sock_filter
+O: -
+
+PPPIOCSACTIVE32
+
+N: PPPIOCSASYNCMAP
+I: u32
+O: -
+
+N: PPPIOCSCOMPRESS
+I: struct isdn_ppp_comp_data
+O: -
+
+PPPIOCSCOMPRESS32
+
+N: PPPIOCSCOMPRESSOR
+I: struct isdn_ppp_comp_data
+O: -
+
+N: PPPIOCSDEBUG
+I: unsigned long
+O: -
+
+N: PPPIOCSFLAGS
+I: unsigned long
+O: -
+
+N: PPPIOCSMAXCID
+I: unsigned long
+O: -
+
+N: PPPIOCSMPFLAGS
+I: unsigned long
+O: -
+
+N: PPPIOCSMPMRU
+I: -
+O: -
+
+N: PPPIOCSMPMTU
+I: -
+O: -
+
+N: PPPIOCSMRRU
+I: int
+O: -
+
+N: PPPIOCSMRU
+I: int
+O: -
+
+N: PPPIOCSNPMODE
+I: struct npioctl
+O: -
+
+N: PPPIOCSPASS
+I: struct sock_fprog + struct sock_fprog::len * struct sock_filter
+O:
+
+PPPIOCSPASS32
+
+N: PPPIOCSRASYNCMAP
+I: u32
+O: -
+
+N: PPPIOCSXASYNCMAP
+I: u32 [8]
+O: -
+
+PPPIOCXFERUNIT
+
+N: PPPOEIOCDFWD
+I: -
+O: -
+
+PPPOEIOCGFWD
+
+N: PPPOEIOCSFWD
+I: struct sockaddr_pppox
+O: -
+
+N: PPRCONTROL
+I: -
+O: unsigned char
+
+N: PPRDATA
+I: -
+O: unsigned char
+
+N: PPRELEASE
+I: -
+O: -
+
+N: PPRSTATUS
+I: -
+O: unsigned char
+
+N: PPSETFLAGS
+I: int
+O: -
+
+N: PPSETMODE
+I: int
+O: -
+
+N: PPSETPHASE
+I: int
+O: -
+
+N: PPSETTIME
+I: struct timeval
+O: -
+
+N: PPWCONTROL
+I: unsigned char
+O: -
+
+N: PPWCTLONIRQ
+I: unsigned char
+O: -
+
+N: PPWDATA
+I: unsigned char
+O: -
+
+N: PPYIELD
+I: -
+O: -
+
+N: PRINT_RAID_DEBUG
+I: -
+O: -
+
+PROTECT_ARRAY
+
+N: RAID_AUTORUN
+I: (int) arg
+O: -
+
+N: RAID_VERSION
+I: -
+O: struct mdu_version_s
+
+N: RAW_GETBIND
+I: struct raw_config_request
+O: struct raw_config_request
+
+N: RAW_SETBIND
+I: struct raw_config_request
+O: -
+
+REISERFS_IOC_UNPACK32
+
+N: RESTART_ARRAY_RW
+I: -
+O: -
+
+N: RFCOMMCREATEDEV
+I: struct rfcomm_dev_req
+O: -
+
+N: RFCOMMGETDEVINFO
+I: struct rfcomm_dev_info
+O: struct rfcomm_dev_info
+
+N: RFCOMMGETDEVLIST
+I: u16
+O: struct rfcomm_dev_list_req + struct rfcomm_dev_info [?]
+
+N: RFCOMMRELEASEDEV
+I: struct rfcomm_dev_req
+O: -
+
+RFCOMMSTEALDLC
+
+RNDADDENTROPY
+
+N: RNDADDTOENTCNT
+I: int
+O: -
+
+N: RNDCLEARPOOL
+I: -
+O: -
+
+N: RNDGETENTCNT
+I: -
+O: int
+
+RNDGETPOOL
+
+N: RNDZAPENTCNT
+I: -
+O: -
+
+RTC32_EPOCH_READ
+RTC32_EPOCH_SET
+RTC32_IRQP_READ
+RTC32_IRQP_SET
+
+N: RTCGET
+I: -
+O: struct rtc_time
+
+N: RTCSET
+I: struct rtc_time
+O: -
+
+N: RTC_AIE_OFF
+I: -
+O: -
+
+N: RTC_AIE_ON
+I: -
+O: -
+
+N: RTC_ALM_READ
+I: -
+O: struct rtc_time
+
+N: RTC_ALM_SET
+I: struct rtc_time
+O: -
+
+N: RTC_EPOCH_READ
+I: -
+O: unsigned long
+
+RTC_EPOCH_READ32
+
+N: RTC_EPOCH_SET
+I: (unsigned long) arg
+O: -
+
+RTC_EPOCH_SET32
+
+N: RTC_IRQP_READ
+I: -
+O: unsigned long
+
+RTC_IRQP_READ32
+
+N: RTC_IRQP_SET
+I: (unsigned long) arg
+O: -
+
+RTC_IRQP_SET32
+
+N: RTC_PIE_OFF
+I: -
+O: -
+
+N: RTC_PIE_ON
+I: -
+O: -
+
+N: RTC_PLL_GET
+I: -
+O: struct rtc_pll_info
+
+N: RTC_PLL_SET
+I: struct rtc_pll_info
+O: -
+
+N: RTC_RD_TIME
+I: -
+O: struct rtc_time
+
+N: RTC_SET_CHARGE
+I: int
+O: -
+
+N: RTC_SET_TIME
+I: struct rtc_time
+O: -
+
+N: RTC_UIE_OFF
+I: -
+O: -
+
+N: RTC_UIE_ON
+I: -
+O: -
+
+N: RTC_VLOW_RD
+I: -
+O: int
+
+N: RTC_VLOW_SET
+I: -
+O: -
+
+N: RTC_WIE_OFF
+I: -
+O: -
+
+N: RTC_WIE_ON
+I: -
+O: -
+
+N: RTC_WKALM_RD
+I: -
+O: unsigned char + unsigned char + struct rtc_time
+
+N: RTC_WKALM_SET
+I: unsigned char + struct rtc_time
+O: -
+
+N: RUN_ARRAY
+I: -
+O: -
+
+N: SBPROF_ZBSTART
+I: -
+O: -
+
+N: SBPROF_ZBSTOP
+I: -
+O: -
+
+N: SBPROF_ZBWAITFULL
+I: -
+O: int
+
+N: SCSI_IOCTL_DOORLOCK
+I: -
+O: -
+
+N: SCSI_IOCTL_DOORUNLOCK
+I: -
+O: -
+
+N: SCSI_IOCTL_GET_BUS_NUMBER
+I: -
+O: int
+
+N: SCSI_IOCTL_GET_IDLUN
+I: -
+O: struct scsi_idlun
+
+N: SCSI_IOCTL_GET_PCI
+I: -
+O: char [BUS_ID_SIZE]
+
+N: SCSI_IOCTL_PROBE_HOST
+I: unsigned int
+O: char [?]
+
+SCSI_IOCTL_SEND_COMMAND
+
+N: SCSI_IOCTL_TEST_UNIT_READY
+I: -
+O: -
+
+N: SET_ARRAY_INFO
+I: - | mdu_array_info_t
+O: -
+
+N: SET_BITMAP_FILE
+I: (int) arg
+O: -
+
+N: SET_DISK_FAULTY
+I: (u32) arg
+O: -
+
+SET_DISK_INFO
+
+N: SG_EMULATED_HOST
+I: -
+O: int
+
+N: SG_GET_COMMAND_Q
+I: -
+O: int
+
+N: SG_GET_KEEP_ORPHAN
+I: -
+O: int
+
+N: SG_GET_LOW_DMA
+I: -
+O: int
+
+N: SG_GET_NUM_WAITING
+I: -
+O: int
+
+N: SG_GET_PACK_ID
+I: -
+O: int
+
+N: SG_GET_REQUEST_TABLE
+I: -
+O: struct sg_req_info [SG_MAX_QUEUE]
+
+N: SG_GET_RESERVED_SIZE
+I: -
+O: int
+
+N: SG_GET_SCSI_ID
+I: -
+O: int + int + int + int + int + short + short + int [2] /* struct sg_scsi_id */
+
+N: SG_GET_SG_TABLESIZE
+I: -
+O: int
+
+N: SG_GET_TIMEOUT
+I: -
+O: -
+
+N: SG_GET_TRANSFORM
+I: -
+O: int
+
+N: SG_GET_VERSION_NUM
+I: -
+O: int
+
+SG_IO
+
+N: SG_NEXT_CMD_LEN
+I: int
+O: -
+
+N: SG_SCSI_RESET
+I: int
+O: -
+
+N: SG_SET_COMMAND_Q
+I: int
+O: -
+
+N: SG_SET_DEBUG
+I: int
+O: -
+
+N: SG_SET_FORCE_LOW_DMA
+I: int
+O: -
+
+N: SG_SET_FORCE_PACK_ID
+I: int
+O: -
+
+N: SG_SET_KEEP_ORPHAN
+I: int
+O: -
+
+N: SG_SET_RESERVED_SIZE
+I: int
+O: -
+
+N: SG_SET_TIMEOUT
+I: int
+O: -
+
+N: SG_SET_TRANSFORM
+I: (void *) arg
+O: -
+
+N: SIOCADDDLCI
+I: struct dlci_add
+O: struct dlci_add
+
+N: SIOCADDMULTI
+I: struct ifreq
+O: -
+
+N: SIOCADDRT
+I: struct rtentry
+O: -
+
+N: SIOCATALKDIFADDR
+I: struct ifreq
+O: struct ifreq
+
+N: SIOCATMARK
+I: -
+O: -
+
+N: SIOCBONDCHANGEACTIVE
+I: struct ifreq
+O: -
+
+N: SIOCBONDENSLAVE
+I: struct ifreq
+O: -
+
+N: SIOCBONDINFOQUERY
+I: struct ifreq
+O: -
+
+N: SIOCBONDRELEASE
+I: struct ifreq
+O: -
+
+N: SIOCBONDSETHWADDR
+I: struct ifreq
+O: -
+
+N: SIOCBONDSLAVEINFOQUERY
+I: struct ifreq
+O: -
+
+N: SIOCBRADDBR
+I: char buf[IFNAMSIZ]
+O: -
+
+N: SIOCBRADDIF
+I: struct ifreq
+O: -
+
+N: SIOCBRDELBR
+I: char buf[IFNAMSIZ]
+O: -
+
+N: SIOCBRDELIF
+I: struct ifreq
+O: -
+
+N: SIOCDARP
+I: struct arpreq
+O: -
+
+N: SIOCDELDLCI
+I: struct dlci_add
+O: -
+
+N: SIOCDELMULTI
+I: struct ifreq
+O: -
+
+N: SIOCDELRT
+I: struct rtentry
+O: -
+
+N: SIOCDIFADDR
+I: struct ifreq
+O: struct ifreq
+
+SIOCDRARP
+
+N: SIOCETHTOOL
+I: struct ifreq
+O: struct ifreq
+
+N: SIOCGARP
+I: struct arpreq
+O: struct arpreq
+
+N: SIOCGIFADDR
+I: struct ifreq
+O: -
+
+SIOCGIFBR
+
+N: SIOCGIFBRDADDR
+I: struct ifreq
+O: struct ifreq
+
+N: SIOCGIFCONF
+I: struct ifconf
+O: struct ifconf
+
+N: SIOCGIFDSTADDR
+I: struct ifreq
+O: struct ifreq
+
+N: SIOCGIFENCAP
+I: -
+O: int
+
+N: SIOCGIFFLAGS
+I: struct ifreq
+O: struct ifreq
+
+N: SIOCGIFHWADDR
+I: struct ifreq
+O: struct ifreq
+
+SIOCGIFINDEX
+SIOCGIFMAP
+SIOCGIFMEM
+SIOCGIFMETRIC
+SIOCGIFMTU
+SIOCGIFNAME
+SIOCGIFNETMASK
+SIOCGIFPFLAGS
+SIOCGIFTXQLEN
+SIOCGIFVLAN
+SIOCGIWAP
+SIOCGIWAPLIST
+SIOCGIWENCODE
+SIOCGIWESSID
+SIOCGIWFRAG
+SIOCGIWFREQ
+SIOCGIWMODE
+SIOCGIWNAME
+SIOCGIWNICKN
+SIOCGIWNWID
+SIOCGIWPOWER
+SIOCGIWPRIV
+SIOCGIWRANGE
+SIOCGIWRATE
+SIOCGIWRETRY
+SIOCGIWRTS
+SIOCGIWSCAN
+SIOCGIWSENS
+SIOCGIWSPY
+SIOCGIWSTATS
+SIOCGIWTHRSPY
+SIOCGIWTXPOW
+SIOCGMIIPHY
+SIOCGMIIREG
+SIOCGPGRP
+SIOCGPPPCSTATS
+SIOCGPPPSTATS
+SIOCGPPPVER
+SIOCGRARP
+SIOCGSTAMP
+SIOCMKCLIP
+SIOCRTMSG
+SIOCSARP
+SIOCSIFADDR
+SIOCSIFATMTCP
+SIOCSIFBR
+SIOCSIFBRDADDR
+SIOCSIFDSTADDR
+SIOCSIFENCAP
+SIOCSIFFLAGS
+SIOCSIFHWADDR
+SIOCSIFLINK
+SIOCSIFMAP
+SIOCSIFMEM
+SIOCSIFMETRIC
+SIOCSIFMTU
+SIOCSIFNAME
+SIOCSIFNETMASK
+SIOCSIFPFLAGS
+SIOCSIFTXQLEN
+SIOCSIFVLAN
+SIOCSIWAP
+SIOCSIWCOMMIT
+SIOCSIWENCODE
+SIOCSIWESSID
+SIOCSIWFRAG
+SIOCSIWFREQ
+SIOCSIWMODE
+SIOCSIWNICKN
+SIOCSIWNWID
+SIOCSIWPOWER
+SIOCSIWPRIV
+SIOCSIWRANGE
+SIOCSIWRATE
+SIOCSIWRETRY
+SIOCSIWRTS
+SIOCSIWSCAN
+SIOCSIWSENS
+SIOCSIWSPY
+SIOCSIWSTATS
+SIOCSIWTHRSPY
+SIOCSIWTXPOW
+SIOCSMIIREG
+SIOCSPGRP
+SIOCSRARP
+
+N: SISFB_GET_AUTOMAXIMIZE
+I: -
+O: u32
+
+N: SISFB_GET_AUTOMAXIMIZE_OLD
+I: -
+O: u32
+
+N: SISFB_GET_INFO
+I: -
+O: struct sisfb_info
+
+N: SISFB_GET_INFO_OLD
+I: -
+O: struct sisfb_info
+
+N: SISFB_GET_INFO_SIZE
+I: -
+O: u32
+
+N: SISFB_GET_TVPOSOFFSET
+I: -
+O: u32
+
+N: SISFB_GET_TVPOSOFFSET
+I: -
+O: u32
+
+N: SISFB_GET_VBRSTATUS
+I: -
+O: u32
+
+N: SISFB_GET_VBRSTATUS_OLD
+I: -
+O: u32
+
+N: SISFB_SET_AUTOMAXIMIZE
+I: u32
+O: -
+
+N: SISFB_SET_AUTOMAXIMIZE_OLD
+I: u32
+O: -
+
+N: SISFB_SET_LOCK
+I: u32
+O: -
+
+N: SISFB_SET_TVPOSOFFSET
+I: u32
+O: -
+
+N: SISUSB_COMMAND
+I: struct sisusb_command
+O: -
+
+N: SISUSB_GET_CONFIG
+I: -
+O: struct sisusb_info
+
+N: SISUSB_GET_CONFIG_SIZE
+I: -
+O: u32
+
+SMB_IOC_GETMOUNTUID_32
+
+N: SMB_IOC_NEWCONN
+I: -
+O: struct smb_conn_opt
+
+SNDCTL_COPR_HALT
+SNDCTL_COPR_LOAD
+SNDCTL_COPR_RCODE
+SNDCTL_COPR_RCVMSG
+SNDCTL_COPR_RDATA
+SNDCTL_COPR_RESET
+SNDCTL_COPR_RUN
+SNDCTL_COPR_SENDMSG
+SNDCTL_COPR_WCODE
+SNDCTL_COPR_WDATA
+SNDCTL_DSP_CHANNELS
+SNDCTL_DSP_GETBLKSIZE
+SNDCTL_DSP_GETCAPS
+SNDCTL_DSP_GETFMTS
+SNDCTL_DSP_GETIPTR
+SNDCTL_DSP_GETISPACE
+SNDCTL_DSP_GETODELAY
+SNDCTL_DSP_GETOPTR
+SNDCTL_DSP_GETOSPACE
+SNDCTL_DSP_GETTRIGGER
+SNDCTL_DSP_NONBLOCK
+SNDCTL_DSP_POST
+SNDCTL_DSP_PROFILE
+SNDCTL_DSP_RESET
+SNDCTL_DSP_SETDUPLEX
+SNDCTL_DSP_SETFMT
+SNDCTL_DSP_SETFRAGMENT
+SNDCTL_DSP_SETSYNCRO
+SNDCTL_DSP_SETTRIGGER
+SNDCTL_DSP_SPEED
+SNDCTL_DSP_STEREO
+SNDCTL_DSP_SUBDIVIDE
+SNDCTL_DSP_SYNC
+SNDCTL_FM_4OP_ENABLE
+SNDCTL_FM_LOAD_INSTR
+SNDCTL_MIDI_INFO
+SNDCTL_MIDI_MPUCMD
+SNDCTL_MIDI_MPUMODE
+SNDCTL_MIDI_PRETIME
+SNDCTL_SEQ_CTRLRATE
+SNDCTL_SEQ_GETINCOUNT
+SNDCTL_SEQ_GETOUTCOUNT
+SNDCTL_SEQ_GETTIME
+SNDCTL_SEQ_NRMIDIS
+SNDCTL_SEQ_NRSYNTHS
+SNDCTL_SEQ_OUTOFBAND
+SNDCTL_SEQ_PANIC
+SNDCTL_SEQ_PERCMODE
+SNDCTL_SEQ_RESET
+SNDCTL_SEQ_RESETSAMPLES
+SNDCTL_SEQ_SYNC
+SNDCTL_SEQ_TESTMIDI
+SNDCTL_SEQ_THRESHOLD
+SNDCTL_SYNTH_CONTROL
+SNDCTL_SYNTH_ID
+SNDCTL_SYNTH_INFO
+SNDCTL_SYNTH_MEMAVL
+SNDCTL_SYNTH_REMOVESAMPLE
+SNDCTL_TMR_CONTINUE
+SNDCTL_TMR_METRONOME
+SNDCTL_TMR_SELECT
+SNDCTL_TMR_SOURCE
+SNDCTL_TMR_START
+SNDCTL_TMR_STOP
+SNDCTL_TMR_TEMPO
+SNDCTL_TMR_TIMEBASE
+SNDRV_DM_FM_IOCTL_RESET
+SNDRV_EMU10K1_IOCTL_CONTINUE
+SNDRV_EMU10K1_IOCTL_STOP
+SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER
+SNDRV_SB_CSP_IOCTL_PAUSE
+SNDRV_SB_CSP_IOCTL_RESTART
+SNDRV_SB_CSP_IOCTL_STOP
+SNDRV_SB_CSP_IOCTL_UNLOAD_CODE
+SND_SSCAPE_LOAD_BOOTB
+SND_SSCAPE_LOAD_MCODE
+SONET_CLRDIAG
+SONET_GETDIAG
+SONET_GETFRAMING
+SONET_GETFRSENSE
+SONET_GETSTAT
+SONET_GETSTATZ
+SONET_SETDIAG
+SONET_SETFRAMING
+SOUND_MIXER_3DSE
+SOUND_MIXER_ACCESS
+SOUND_MIXER_AGC
+SOUND_MIXER_GETLEVELS
+SOUND_MIXER_INFO
+SOUND_MIXER_PRIVATE1
+SOUND_MIXER_PRIVATE2
+SOUND_MIXER_PRIVATE3
+SOUND_MIXER_PRIVATE4
+SOUND_MIXER_PRIVATE5
+SOUND_MIXER_SETLEVELS
+SOUND_OLD_MIXER_INFO
+SOUND_PCM_READ_BITS
+SOUND_PCM_READ_CHANNELS
+SOUND_PCM_READ_FILTER
+SOUND_PCM_READ_RATE
+SOUND_PCM_WRITE_FILTER
+SPIOCSTYPE
+SSP_FRAME_SYNC
+SSP_INBUFCHUNK
+SSP_IPOLARITY
+SSP_MODE
+SSP_OPOLARITY
+SSP_SPEED
+SSP_SPI
+START_ARRAY
+STL_BINTR
+STL_BRESET
+STL_BSTART
+STL_BSTOP
+STL_GETPFLAG
+STL_SETPFLAG
+STOP_ARRAY
+STOP_ARRAY_RO
+TAPE390_DISPLAY
+TCFLSH
+TCGETA
+
+N: TCGETS
+I: -
+O: struct termios
+
+TCSBRK
+TCSBRKP
+TCSETA
+TCSETAF
+TCSETAW
+TCSETS
+TCSETSF
+TCSETSW
+TCXONC
+TDA9840_DETECT
+TDA9840_LEVEL_ADJUST
+TDA9840_STEREO_ADJUST
+TDA9840_SWITCH
+TDA9840_TEST
+TDA9887_SET_CONFIG
+TEA6415C_SWITCH
+TEA6420_SWITCH
+TIOCCBRK
+TIOCCONS
+TIOCEXCL
+
+N: TIOCGETC
+I: -
+O: struct tchars
+
+TIOCGETD
+
+N: TIOCGETP
+I: -
+O: struct sgttyb
+
+TIOCGICOUNT
+
+N: TIOCGLTC
+I: -
+O: struct ltchars
+
+TIOCGPGRP
+TIOCGPTN
+TIOCGSERIAL
+TIOCGSID
+TIOCGSOFTCAR
+TIOCGWINSZ
+TIOCLINUX
+TIOCMBIC
+TIOCMBIS
+TIOCMGET
+TIOCMIWAIT
+TIOCMSET
+TIOCNOTTY
+TIOCNXCL
+TIOCOUTQ
+TIOCPKT
+TIOCSBRK
+TIOCSCLPSINIT
+TIOCSCTTY
+TIOCSERCONFIG
+TIOCSERGETLSR
+TIOCSERGETMULTI
+TIOCSERGSTRUCT
+TIOCSERGWILD
+TIOCSERSETMULTI
+TIOCSERSWILD
+TIOCSETA
+TIOCSETAF
+TIOCSETAW
+
+N: TIOCSETC
+I: struct tchars
+O: -
+
+N: TIOCSETD
+I: int
+O: -
+
+N: TIOCSETN
+I: struct sgttyb
+O: -
+
+N: TIOCSETP
+I: struct sgttyb
+O: -
+
+N: TIOCSLTC
+I: struct ltchars
+O: -
+
+N: TIOCSPGRP
+I: pid_t
+O: -
+
+N: TIOCSPTLCK
+I: int
+O: -
+
+TIOCSSERIAL
+TIOCSSOFTCAR
+TIOCSTART
+
+N: TIOCSTI
+I: char
+O: -
+
+TIOCSTOP
+
+N: TIOCSWINSZ
+I: struct winsize
+O: -
+
+TIOCTTYGSTRUCT
+
+N: TOSH_SMM
+I: SMMRegisters
+O: SMMRegisters
+
+N: TS_GET_CAL
+I: -
+O: struct ts_calibration
+
+N: TS_SET_CAL
+I: struct ts_calibration
+O: -
+
+N: TUBGETI
+I: -
+O: char
+
+N: TUBGETMOD
+I: -
+O: struct raw3270_iocb
+
+N: TUBGETO
+I: -
+O: char
+
+N: TUBICMD
+I: (int) arg
+O: -
+
+N: TUBOCMD
+I: (int) arg
+O: -
+
+TUBSETMOD
+TUNER_SET_TYPE_ADDR
+
+N: TUNSETDEBUG
+I: (int) arg
+O: -
+
+TUNSETIFF
+
+N: TUNSETLINK
+I: (int) arg
+O: -
+
+N: TUNSETNOCSUM
+I: (unsigned long) arg
+O: -
+
+N: TUNSETOWNER
+I: (uid_t) arg
+O: -
+
+N: TUNSETPERSIST
+I: (unsigned long) arg
+O: -
+
+N: UDF_GETEABLOCK
+I: -
+O: char [UDF_I_LENEATTR(inode)]
+
+N: UDF_GETEASIZE
+I: -
+O: int
+
+N: UDF_GETVOLIDENT
+I: -
+O: char [32]
+
+N: UDF_RELOCATE_BLOCKS
+I: long
+O: long
+
+UI_BEGIN_FF_ERASE
+UI_BEGIN_FF_UPLOAD
+
+N: UI_DEV_CREATE
+I: -
+O: -
+
+N: UI_DEV_DESTROY
+I: -
+O: -
+
+UI_END_FF_ERASE
+UI_END_FF_UPLOAD
+
+N: UI_SET_ABSBIT
+I: (int) arg
+O: -
+
+N: UI_SET_EVBIT
+I: (int) arg
+O: -
+
+N: UI_SET_FFBIT
+I: (int) arg
+O: -
+
+N: UI_SET_KEYBIT
+I: (int) arg
+O: -
+
+N: UI_SET_LEDBIT
+I: (int) arg
+O: -
+
+N: UI_SET_MSCBIT
+I: (int) arg
+O: -
+
+UI_SET_PHYS
+
+N: UI_SET_RELBIT
+I: (int) arg
+O: -
+
+N: UI_SET_SNDBIT
+I: (int) arg
+O: -
+
+UNPROTECT_ARRAY
+
+N: USBDEVFS_BULK
+I: struct usbdevfs_bulktransfer
+O: -
+
+USBDEVFS_BULK32
+
+N: USBDEVFS_CLAIMINTERFACE
+I: unsigned int
+O: -
+
+N: USBDEVFS_CLEAR_HALT
+I: unsigned int
+O: -
+
+USBDEVFS_CONNECT
+
+N: USBDEVFS_CONNECTINFO
+I: -
+O: struct usbdevfs_connectinfo
+
+USBDEVFS_CONTROL
+USBDEVFS_CONTROL32
+
+N: USBDEVFS_DISCARDURB
+I: -
+O: -
+
+USBDEVFS_DISCONNECT
+
+N: USBDEVFS_DISCSIGNAL
+I: struct usbdevfs_disconnectsignal
+O: -
+
+USBDEVFS_DISCSIGNAL32
+
+N: USBDEVFS_GETDRIVER
+I: struct usbdevfs_getdriver
+O: struct usbdevfs_getdriver
+
+USBDEVFS_HUB_PORTINFO
+USBDEVFS_REAPURB
+USBDEVFS_REAPURB32
+USBDEVFS_REAPURBNDELAY
+USBDEVFS_REAPURBNDELAY32
+
+N: USBDEVFS_RELEASEINTERFACE
+I: unsigned int
+O: -
+
+N: USBDEVFS_RESET
+I: -
+O: -
+
+N: USBDEVFS_RESETEP
+I: unsigned int
+O: -
+
+N: USBDEVFS_SETCONFIGURATION
+I: unsigned int
+O: -
+
+N: USBDEVFS_SETINTERFACE
+I: struct usbdevfs_setinterface
+O: -
+
+USBDEVFS_SUBMITURB
+USBDEVFS_SUBMITURB32
+USBTEST_REQUEST
+VFAT_IOCTL_READDIR_BOTH32
+VFAT_IOCTL_READDIR_SHORT32
+VIDEO_CLEAR_BUFFER
+VIDEO_CONTINUE
+VIDEO_FAST_FORWARD
+VIDEO_FREEZE
+VIDEO_GET_CAPABILITIES
+VIDEO_GET_EVENT
+VIDEO_GET_FRAME_RATE
+VIDEO_GET_NAVI
+VIDEO_GET_SIZE
+VIDEO_GET_STATUS
+VIDEO_PLAY
+VIDEO_SELECT_SOURCE
+VIDEO_SET_ATTRIBUTES
+VIDEO_SET_BLANK
+VIDEO_SET_DISPLAY_FORMAT
+VIDEO_SET_FORMAT
+VIDEO_SET_HIGHLIGHT
+VIDEO_SET_ID
+VIDEO_SET_SPU
+VIDEO_SET_SPU_PALETTE
+VIDEO_SET_STREAMTYPE
+VIDEO_SET_SYSTEM
+VIDEO_SLOWMOTION
+VIDEO_STILLPICTURE
+VIDEO_STOP
+VIDIOCCAPTURE
+VIDIOCGAUDIO
+VIDIOCGCAP
+VIDIOCGCAPTURE
+VIDIOCGCHAN
+VIDIOCGFBUF
+VIDIOCGFBUF32
+VIDIOCGFREQ
+VIDIOCGFREQ32
+VIDIOCGMBUF
+VIDIOCGPICT
+VIDIOCGPLAYINFO
+VIDIOCGTUNER
+VIDIOCGTUNER32
+VIDIOCGUNIT
+VIDIOCGVBIFMT
+VIDIOCGWIN
+VIDIOCGWIN32
+VIDIOCKEY
+VIDIOCMCAPTURE
+VIDIOCPWCFACTORY
+VIDIOCPWCGAGC
+VIDIOCPWCGAWB
+VIDIOCPWCGAWBSPEED
+VIDIOCPWCGBACKLIGHT
+VIDIOCPWCGCONTOUR
+VIDIOCPWCGCQUAL
+VIDIOCPWCGDYNNOISE
+VIDIOCPWCGFLICKER
+VIDIOCPWCGLED
+VIDIOCPWCGREALSIZE
+VIDIOCPWCGSERIAL
+VIDIOCPWCGVIDCMD
+VIDIOCPWCGVIDTABLE
+VIDIOCPWCMPTGANGLE
+VIDIOCPWCMPTGRANGE
+VIDIOCPWCMPTRESET
+VIDIOCPWCMPTSANGLE
+VIDIOCPWCMPTSTATUS
+VIDIOCPWCPROBE
+VIDIOCPWCRUSER
+VIDIOCPWCSAGC
+VIDIOCPWCSAWB
+VIDIOCPWCSAWBSPEED
+VIDIOCPWCSBACKLIGHT
+VIDIOCPWCSCONTOUR
+VIDIOCPWCSCQUAL
+VIDIOCPWCSDYNNOISE
+VIDIOCPWCSFLICKER
+VIDIOCPWCSLED
+VIDIOCPWCSSHUTTER
+VIDIOCPWCSUSER
+VIDIOCSAUDIO
+VIDIOCSCAPTURE
+VIDIOCSCHAN
+VIDIOCSFBUF
+VIDIOCSFBUF32
+VIDIOCSFREQ
+VIDIOCSFREQ32
+VIDIOCSMICROCODE
+VIDIOCSPICT
+VIDIOCSPLAYMODE
+VIDIOCSTUNER
+VIDIOCSTUNER32
+VIDIOCSVBIFMT
+VIDIOCSWIN
+VIDIOCSWIN32
+VIDIOCSWRITEMODE
+VIDIOCSYNC
+
+N: VIDIOC_CROPCAP
+I: -
+O: struct v4l2_cropcap
+
+VIDIOC_CROPCAP_OLD
+
+N: VIDIOC_DQBUF
+I: struct v4l2_buffer
+O: struct v4l2_buffer
+
+VIDIOC_ENUMAUDIO
+VIDIOC_ENUMAUDOUT
+
+N: VIDIOC_ENUMINPUT
+I: struct v4l2_input
+O: struct v4l2_input
+
+VIDIOC_ENUMOUTPUT
+VIDIOC_ENUMSTD
+
+N: VIDIOC_ENUM_FMT
+I: struct v4l2_fmtdesc
+O: struct v4l2_fmtdesc
+
+VIDIOC_G_AUDIO
+VIDIOC_G_AUDIO_OLD
+VIDIOC_G_AUDOUT
+VIDIOC_G_AUDOUT_OLD
+VIDIOC_G_CROP
+
+N: VIDIOC_G_CTRL
+I: struct v4l2_control
+O: struct v4l2_control
+
+VIDIOC_G_FBUF
+
+N: VIDIOC_G_FMT
+I: struct v4l2_format
+O: struct v4l2_format
+
+VIDIOC_G_FREQUENCY
+
+N: VIDIOC_G_INPUT
+I: int
+O: -
+
+N: VIDIOC_G_JPEGCOMP
+I: -
+O: struct v4l2_jpegcompression
+
+VIDIOC_G_MODULATOR
+VIDIOC_G_MPEGCOMP
+VIDIOC_G_OUTPUT
+
+N: VIDIOC_G_PARM
+I: struct v4l2_streamparm
+O: struct v4l2_streamparm
+
+VIDIOC_G_PRIORITY
+VIDIOC_G_STD
+VIDIOC_G_TUNER
+VIDIOC_OVERLAY
+VIDIOC_OVERLAY_OLD
+
+N: VIDIOC_QBUF
+I: struct v4l2_buffer
+O: -
+
+N: VIDIOC_QUERYBUF
+I: struct v4l2_buffer
+O: struct v4l2_buffer
+
+N: VIDIOC_QUERYCAP
+I: -
+O: struct v4l2_capability
+
+N: VIDIOC_QUERYCTRL
+I: struct v4l2_queryctrl
+O: struct v4l2_queryctrl
+
+VIDIOC_QUERYMENU
+VIDIOC_QUERYSTD
+
+N: VIDIOC_REQBUFS
+I: struct v4l2_requestbuffers
+O: struct v4l2_requestbuffers
+
+VIDIOC_RESERVED
+
+N: VIDIOC_STREAMOFF
+I: int
+O: -
+
+N: VIDIOC_STREAMON
+I: int
+O: -
+
+VIDIOC_S_AUDIO
+VIDIOC_S_AUDOUT
+
+N: VIDIOC_S_CROP
+I: struct v4l2_crop
+O: struct v4l2_crop
+
+N: VIDIOC_S_CTRL
+I: struct v4l2_control
+O: -
+
+N: VIDIOC_S_CTRL_OLD
+I: struct v4l2_control
+O: -
+
+VIDIOC_S_FBUF
+
+N: VIDIOC_S_FMT
+I: struct v4l2_format
+O: struct v4l2_format
+
+VIDIOC_S_FREQUENCY
+
+N: VIDIOC_S_INPUT
+I: int
+O: -
+
+N: VIDIOC_S_JPEGCOMP
+I: struct v4l2_jpegcompression
+O: -
+
+VIDIOC_S_MODULATOR
+VIDIOC_S_MPEGCOMP
+VIDIOC_S_OUTPUT
+VIDIOC_S_PARM
+VIDIOC_S_PARM_OLD
+VIDIOC_S_PRIORITY
+VIDIOC_S_STD
+VIDIOC_S_TUNER
+
+N: VIDIOC_TRY_FMT
+I: struct v4l2_format
+O: struct v4l2_format
+
+N: VMCP_GETCODE
+I: -
+O: int
+
+N: VMCP_GETSIZE
+I: -
+O: int
+
+N: VMCP_SETBUF
+I: int
+O: -
+
+VTXIOCCLRCACHE
+VTXIOCCLRFOUND
+VTXIOCCLRPAGE
+VTXIOCGETINFO
+VTXIOCGETPAGE
+VTXIOCGETSTAT
+VTXIOCPAGEREQ
+VTXIOCPUTPAGE
+VTXIOCPUTSTAT
+VTXIOCSETDISP
+VTXIOCSETVIRT
+VTXIOCSTOPDAU
+
+N: VT_ACTIVATE
+I: (unsigned int) arg
+O: -
+
+N: VT_DISALLOCATE
+I: (unsigned int) arg
+O: -
+
+N: VT_GETMODE
+I: -
+O: struct vt_mode
+
+N: VT_GETSTATE
+I: -
+O: unsigned short + unsigned short
+
+N: VT_LOCKSWITCH
+I: -
+O: -
+
+N: VT_OPENQRY
+I: -
+O: int
+
+N: VT_RELDISP
+I: (unsigned long) arg
+O: -
+
+N: VT_RESIZE
+I: ushort + ushort
+O: -
+
+N: VT_RESIZEX
+I: ushort + ushort + ushort + ushort + ushort + ushort
+O: -
+
+N: VT_SETMODE
+I: struct vt_mode
+O: -
+
+N: VT_UNLOCKSWITCH
+I: -
+O: -
+
+N: VT_WAITACTIVE
+I: (int) arg
+O: -
+
+N: WDIOC_GETBOOTSTATUS
+I: -
+O: int
+
+N: WDIOC_GETSTATUS
+I: -
+O: int
+
+N: WDIOC_GETSUPPORT
+I: -
+O: struct watchdog_info
+
+N: WDIOC_GETTEMP
+I: -
+O: int
+
+N: WDIOC_GETTIMEOUT
+I: -
+O: int
+
+N: WDIOC_KEEPALIVE
+I: -
+O: -
+
+N: WDIOC_SETOPTIONS
+I: int
+O: -
+
+N: WDIOC_SETTIMEOUT
+I: int
+O: int
+
+N: WIOCGSTAT
+I: -
+O: int
+
+N: WIOCSTART
+I: -
+O: -
+
+N: WIOCSTOP
+I: -
+O: -
+
+WRITE_RAID_INFO
+
+N: Z90QUIESCE
+I: -
+O: -
+
+N: ZATM_GETPOOL
+I: int
+O: struct zatm_pool_info
+
+N: ZATM_GETPOOLZ
+I: int
+O: struct zatm_pool_info
+
+N: ZATM_SETPOOL
+I: int + struct zatm_pool_info
+O: -
+
+__NET_ADD_IF_OLD
+__NET_GET_IF_OLD
+__TCGETSTAT
+__TCSETSTAT
+__TIOCCDTR
+__TIOCFLUSH
+__TIOCGETC
+__TIOCGETP
+__TIOCGETX
+__TIOCGLTC
+__TIOCGSIZE
+__TIOCHPCL
+__TIOCISIZE
+__TIOCISPACE
+__TIOCLBIC
+__TIOCLBIS
+__TIOCLGET
+__TIOCLSET
+__TIOCMODG
+__TIOCMODS
+__TIOCREMOTE
+__TIOCSDTR
+__TIOCSETC
+__TIOCSETN
+__TIOCSETP
+__TIOCSETX
+__TIOCSIGNAL
+__TIOCSLTC
+__TIOCSSIZE
+__TIOCTCNTL
+__TIOCUCNTL
diff -urN oldtree/Documentation/kernel-parameters.txt newtree/Documentation/kernel-parameters.txt
--- oldtree/Documentation/kernel-parameters.txt	2006-04-01 04:48:27.000000000 -0500
+++ newtree/Documentation/kernel-parameters.txt	2006-04-01 05:35:30.698538500 -0500
@@ -138,6 +138,9 @@
 	acpi_irq_isa=	[HW,ACPI] If irq_balance, mark listed IRQs used by ISA
 			Format: <irq>,<irq>...
 
+	acpi_os_name=	[HW,ACPI] Tell ACPI BIOS the name of the OS
+			Format: To spoof as Windows 98: ="Microsoft Windows"
+
 	acpi_osi=	[HW,ACPI] empty param disables _OSI
 
 	acpi_serialize	[HW,ACPI] force serialization of AML methods
diff -urN oldtree/Documentation/leds-class.txt newtree/Documentation/leds-class.txt
--- oldtree/Documentation/leds-class.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/leds-class.txt	2006-04-01 05:35:57.284200000 -0500
@@ -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/memory-barriers.txt newtree/Documentation/memory-barriers.txt
--- oldtree/Documentation/memory-barriers.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/memory-barriers.txt	2006-04-01 05:35:52.867924000 -0500
@@ -0,0 +1,1639 @@
+			 ============================
+			 LINUX KERNEL MEMORY BARRIERS
+			 ============================
+
+Contents:
+
+ (*) Abstract memory access model.
+
+     - Device operations.
+     - Guarantees.
+
+ (*) What are memory barriers?
+
+     - Varieties of memory barrier.
+     - What can't be assumed about memory barriers?
+     - Data dependency barriers.
+     - Control dependencies.
+     - SMP barrier pairing.
+
+ (*) Explicit kernel barriers.
+
+     - Compiler barrier.
+     - The CPU memory barriers.
+     - MMIO write barrier.
+
+ (*) Implicit kernel memory barriers.
+
+     - Locking functions.
+     - Interrupt disabling functions.
+     - Miscellaneous functions.
+
+ (*) Inter-CPU locking barrier effects.
+
+     - Locks vs memory accesses.
+     - Locks vs I/O accesses.
+
+ (*) Where are memory barriers needed?
+
+     - Interprocessor interaction.
+     - Atomic operations.
+     - Accessing devices.
+     - Interrupts.
+
+ (*) Kernel I/O barrier effects.
+
+ (*) Assumed minimum execution ordering model.
+
+ (*) The effects of the cpu cache.
+
+     - Cache coherency.
+     - Cache coherency vs DMA.
+     - Cache coherency vs MMIO.
+
+ (*) The things CPUs get up to.
+
+     - And then there's the Alpha.
+
+ (*) References.
+
+
+============================
+ABSTRACT MEMORY ACCESS MODEL
+============================
+
+Consider the following abstract model of the system:
+
+		            :                :
+		            :                :
+		            :                :
+		+-------+   :   +--------+   :   +-------+
+		|       |   :   |        |   :   |       |
+		|       |   :   |        |   :   |       |
+		| CPU 1 |<----->| Memory |<----->| CPU 2 |
+		|       |   :   |        |   :   |       |
+		|       |   :   |        |   :   |       |
+		+-------+   :   +--------+   :   +-------+
+		    ^       :       ^        :       ^
+		    |       :       |        :       |
+		    |       :       |        :       |
+		    |       :       v        :       |
+		    |       :   +--------+   :       |
+		    |       :   |        |   :       |
+		    |       :   |        |   :       |
+		    +---------->| Device |<----------+
+		            :   |        |   :
+		            :   |        |   :
+		            :   +--------+   :
+		            :                :
+
+Each CPU executes a program that generates memory access operations.  In the
+abstract CPU, memory operation ordering is very relaxed, and a CPU may actually
+perform the memory operations in any order it likes, provided program causality
+appears to be maintained.  Similarly, the compiler may also arrange the
+instructions it emits in any order it likes, provided it doesn't affect the
+apparent operation of the program.
+
+So in the above diagram, the effects of the memory operations performed by a
+CPU are perceived by the rest of the system as the operations cross the
+interface between the CPU and rest of the system (the dotted lines).
+
+
+For example, consider the following sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1; B == 2 }
+	A = 3;		x = A;
+	B = 4;		y = B;
+
+The set of accesses as seen by the memory system in the middle can be arranged
+in 24 different combinations:
+
+	STORE A=3,	STORE B=4,	x=LOAD A->3,	y=LOAD B->4
+	STORE A=3,	STORE B=4,	y=LOAD B->4,	x=LOAD A->3
+	STORE A=3,	x=LOAD A->3,	STORE B=4,	y=LOAD B->4
+	STORE A=3,	x=LOAD A->3,	y=LOAD B->2,	STORE B=4
+	STORE A=3,	y=LOAD B->2,	STORE B=4,	x=LOAD A->3
+	STORE A=3,	y=LOAD B->2,	x=LOAD A->3,	STORE B=4
+	STORE B=4,	STORE A=3,	x=LOAD A->3,	y=LOAD B->4
+	STORE B=4, ...
+	...
+
+and can thus result in four different combinations of values:
+
+	x == 1, y == 2
+	x == 1, y == 4
+	x == 3, y == 2
+	x == 3, y == 4
+
+
+Furthermore, the stores committed by a CPU to the memory system may not be
+perceived by the loads made by another CPU in the same order as the stores were
+committed.
+
+
+As a further example, consider this sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;		Q = P;
+	P = &B		D = *Q;
+
+There is an obvious data dependency here, as the value loaded into D depends on
+the address retrieved from P by CPU 2.  At the end of the sequence, any of the
+following results are possible:
+
+	(Q == &A) and (D == 1)
+	(Q == &B) and (D == 2)
+	(Q == &B) and (D == 4)
+
+Note that CPU 2 will never try and load C into D because the CPU will load P
+into Q before issuing the load of *Q.
+
+
+DEVICE OPERATIONS
+-----------------
+
+Some devices present their control interfaces as collections of memory
+locations, but the order in which the control registers are accessed is very
+important.  For instance, imagine an ethernet card with a set of internal
+registers that are accessed through an address port register (A) and a data
+port register (D).  To read internal register 5, the following code might then
+be used:
+
+	*A = 5;
+	x = *D;
+
+but this might show up as either of the following two sequences:
+
+	STORE *A = 5, x = LOAD *D
+	x = LOAD *D, STORE *A = 5
+
+the second of which will almost certainly result in a malfunction, since it set
+the address _after_ attempting to read the register.
+
+
+GUARANTEES
+----------
+
+There are some minimal guarantees that may be expected of a CPU:
+
+ (*) On any given CPU, dependent memory accesses will be issued in order, with
+     respect to itself.  This means that for:
+
+	Q = P; D = *Q;
+
+     the CPU will issue the following memory operations:
+
+	Q = LOAD P, D = LOAD *Q
+
+     and always in that order.
+
+ (*) Overlapping loads and stores within a particular CPU will appear to be
+     ordered within that CPU.  This means that for:
+
+	a = *X; *X = b;
+
+     the CPU will only issue the following sequence of memory operations:
+
+	a = LOAD *X, STORE *X = b
+
+     And for:
+
+	*X = c; d = *X;
+
+     the CPU will only issue:
+
+	STORE *X = c, d = LOAD *X
+
+     (Loads and stores overlap if they are targetted at overlapping pieces of
+     memory).
+
+And there are a number of things that _must_ or _must_not_ be assumed:
+
+ (*) It must not be assumed that independent loads and stores will be issued in
+     the order given.  This means that for:
+
+	X = *A; Y = *B; *D = Z;
+
+     we may get any of the following sequences:
+
+	X = LOAD *A,  Y = LOAD *B,  STORE *D = Z
+	X = LOAD *A,  STORE *D = Z, Y = LOAD *B
+	Y = LOAD *B,  X = LOAD *A,  STORE *D = Z
+	Y = LOAD *B,  STORE *D = Z, X = LOAD *A
+	STORE *D = Z, X = LOAD *A,  Y = LOAD *B
+	STORE *D = Z, Y = LOAD *B,  X = LOAD *A
+
+ (*) It must be assumed that overlapping memory accesses may be merged or
+     discarded.  This means that for:
+
+	X = *A; Y = *(A + 4);
+
+     we may get any one of the following sequences:
+
+	X = LOAD *A; Y = LOAD *(A + 4);
+	Y = LOAD *(A + 4); X = LOAD *A;
+	{X, Y} = LOAD {*A, *(A + 4) };
+
+     And for:
+
+	*A = X; Y = *A;
+
+     we may get either of:
+
+	STORE *A = X; Y = LOAD *A;
+	STORE *A = Y;
+
+
+=========================
+WHAT ARE MEMORY BARRIERS?
+=========================
+
+As can be seen above, independent memory operations are effectively performed
+in random order, but this can be a problem for CPU-CPU interaction and for I/O.
+What is required is some way of intervening to instruct the compiler and the
+CPU to restrict the order.
+
+Memory barriers are such interventions.  They impose a perceived partial
+ordering between the memory operations specified either side of the barrier.
+They request that the sequence of memory events generated appears to other
+parts of the system as if the barrier is effective on that CPU.
+
+
+VARIETIES OF MEMORY BARRIER
+---------------------------
+
+Memory barriers come in four basic varieties:
+
+ (1) Read (or load) memory barriers.
+
+     A read memory barrier gives a guarantee that all the LOAD operations
+     specified before the barrier will appear to happen before all the LOAD
+     operations specified after the barrier with respect to the other
+     components of the system.
+
+     A read barrier is a partial ordering on loads only; it is not required to
+     have any effect on stores.
+
+     A read barrier guarantees that the issuing CPU's perception of all the
+     other stores in that system is up to date by the time the next load goes
+     from that CPU to the rest of the system.
+
+     Read memory barriers imply data dependency barriers, and so can substitute
+     for them.
+
+ (2) Write (or store) memory barriers.
+
+     A write memory barrier gives a guarantee that all the STORE operations
+     specified before the barrier will appear to happen before all the STORE
+     operations specified after the barrier with respect to the other
+     components of the system.
+
+     A write barrier is a partial ordering on stores only; it is not required
+     to have any effect on loads.
+
+ (3) General memory barriers.
+
+     A general memory barrier is a combination of both a read memory barrier
+     and a write memory barrier.  It is a partial ordering over both loads and
+     stores.
+
+     General memory barriers imply both read and write memory barriers, and so
+     can substitute for either.
+
+ (4) Data dependency barriers.
+
+     A data dependency barrier is a weaker form of read barrier.  In the case
+     where two loads are performed such that the second depends on the result
+     of the first (eg: the first load retrieves the address to which the second
+     load will be directed), a data dependency barrier would be required to
+     make sure that the target of the second load is updated before the address
+     obtained by the first load is accessed.
+
+     A data dependency barrier is a partial ordering on interdependent loads
+     only; it is not required to have any effect on stores, independent loads
+     or overlapping loads.
+
+     A data dependency barrier guarantees that the issuing CPU's perception of
+     all the other stores in that system is up to date by the time the next
+     load goes from that CPU to the rest of the system.
+
+     [!] Note that the first load really has to have a _data_ dependency, not a
+     control dependency.  If the address for the second load is dependent on
+     the first load, but the dependency is through a conditional rather than
+     actually loading the address itself, then it's a _control_ dependency and
+     a full read barrier or better is required.  See the "Control dependencies"
+     subsection for more information.
+
+Plus two common implicit varieties:
+
+ (5) LOCK operations.
+
+     This acts as a one-way permeable barrier.  It guarantees that all memory
+     operations after the LOCK operation will appear to happen after the LOCK
+     operation with respect to the other components of the system.
+
+     Memory operations that occur before a LOCK operation may appear to happen
+     after it completes.
+
+ (6) UNLOCK operations.
+
+     This also acts as a one-way permeable barrier.  It guarantees that all
+     memory operations before the UNLOCK operation will appear to happen before
+     the UNLOCK operation with respect to the other components of the system.
+
+     Memory operations that occur after an UNLOCK operation may appear to
+     happen before it completes.
+
+     LOCK and UNLOCK operations are guaranteed to appear with respect to each
+     other strictly in the order specified.
+
+
+Memory barriers are only required where there's a possibility of interaction
+between two CPUs or between a CPU and a device.  If it can be guaranteed that
+there won't be any such interaction in any particular piece of code, then
+memory barriers are unnecessary in that piece of code.
+
+
+Note that these are the _minimum_ guarantees.  Different architectures may give
+more substantial guarantees, but they may _not_ be relied upon outside of arch
+specific code.
+
+
+WHAT CAN'T BE ASSUMED ABOUT MEMORY BARRIERS?
+--------------------------------------------
+
+There are certain things that the Linux kernel memory barriers do not guarantee:
+
+ (*) There is no guarantee that any of the memory accesses specified before a
+     memory barrier will be _complete_ by the completion of a memory barrier
+     instruction; the barrier can be considered to draw a line in that CPU's
+     access queue that accesses of the appropriate type may not cross.
+
+ (*) There is no guarantee that issuing a memory barrier on one CPU will have
+     any direct effect on another CPU or any other hardware in the system.  The
+     indirect effect will be the order in which the second CPU sees the effects
+     of the first CPU's accesses occur.
+
+ (*) There is no guarantee that the a CPU will see the correct order of effects
+     from a second CPU's accesses, even _if_ the second CPU uses a memory
+     barrier, unless the first CPU _also_ uses a matching memory barrier (see
+     the subsection on "SMP Barrier Pairing").
+
+ (*) There is no guarantee that some intervening piece of off-the-CPU
+     hardware[*] will not reorder the memory accesses.  CPU cache coherency
+     mechanisms should propagate the indirect effects of a memory barrier
+     between CPUs, but may not do so in order.
+
+	[*] For information on bus mastering DMA and coherency please read:
+
+	    Documentation/pci.txt
+	    Documentation/DMA-mapping.txt
+	    Documentation/DMA-API.txt
+
+
+DATA DEPENDENCY BARRIERS
+------------------------
+
+The usage requirements of data dependency barriers are a little subtle, and
+it's not always obvious that they're needed.  To illustrate, consider the
+following sequence of events:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;
+	<write barrier>
+	P = &B
+			Q = P;
+			D = *Q;
+
+There's a clear data dependency here, and it would seem that by the end of the
+sequence, Q must be either &A or &B, and that:
+
+	(Q == &A) implies (D == 1)
+	(Q == &B) implies (D == 4)
+
+But! CPU 2's perception of P may be updated _before_ its perception of B, thus
+leading to the following situation:
+
+	(Q == &B) and (D == 2) ????
+
+Whilst this may seem like a failure of coherency or causality maintenance, it
+isn't, and this behaviour can be observed on certain real CPUs (such as the DEC
+Alpha).
+
+To deal with this, a data dependency barrier must be inserted between the
+address load and the data load:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ A == 1, B == 2, C = 3, P == &A, Q == &C }
+	B = 4;
+	<write barrier>
+	P = &B
+			Q = P;
+			<data dependency barrier>
+			D = *Q;
+
+This enforces the occurrence of one of the two implications, and prevents the
+third possibility from arising.
+
+
+Another example of where data dependency barriers might by required is where a
+number is read from memory and then used to calculate the index for an array
+access:
+
+	CPU 1		CPU 2
+	===============	===============
+	{ M[0] == 1, M[1] == 2, M[3] = 3, P == 0, Q == 3 }
+	M[1] = 4;
+	<write barrier>
+	P = 1
+			Q = P;
+			<data dependency barrier>
+			D = M[Q];
+
+
+The data dependency barrier is very important to the RCU system, for example.
+See rcu_dereference() in include/linux/rcupdate.h.  This permits the current
+target of an RCU'd pointer to be replaced with a new modified target, without
+the replacement target appearing to be incompletely initialised.
+
+Note that this extremely counterintuitive situation arises most easily on
+machines with split caches, so that, for example, one cache bank processes
+even-numbered cache lines and the other bank processes odd-numbered cache
+lines.  The pointer P might be stored in an odd-numbered cache line, and the
+variable B might be stored in an even-numbered cache line.  Then, if the
+even-numbered bank of the reading CPU's cache is extremely busy while the
+odd-numbered bank is idle, one can see the new value of the pointer (&b), but
+the old value of the variable (1).
+
+See also the subsection on "Cache Coherency" for a more thorough example.
+
+
+CONTROL DEPENDENCIES
+--------------------
+
+A control dependency requires a full read memory barrier, not simply a data
+dependency barrier to make it work correctly.  Consider the following bit of
+code:
+
+	q = &a;
+	if (p)
+		q = &b;
+	<data dependency barrier>
+	x = *q;
+
+This will not have the desired effect because there is no actual data
+dependency, but rather a control dependency that the CPU may short-circuit by
+attempting to predict the outcome in advance.  In such a case what's actually
+required is:
+
+	q = &a;
+	if (p)
+		q = &b;
+	<read barrier>
+	x = *q;
+
+
+SMP BARRIER PAIRING
+-------------------
+
+When dealing with CPU-CPU interactions, certain types of memory barrier should
+always be paired.  A lack of appropriate pairing is almost certainly an error.
+
+A write barrier should always be paired with a data dependency barrier or read
+barrier, though a general barrier would also be viable.  Similarly a read
+barrier or a data dependency barrier should always be paired with at least an
+write barrier, though, again, a general barrier is viable:
+
+	CPU 1		CPU 2
+	===============	===============
+	a = 1;
+	<write barrier>
+	b = 2;		x = a;
+			<read barrier>
+			y = b;
+
+Or:
+
+	CPU 1		CPU 2
+	===============	===============================
+	a = 1;
+	<write barrier>
+	b = &a;		x = b;
+			<data dependency barrier>
+			y = *x;
+
+Basically, the read barrier always has to be there, even though it can be of
+the "weaker" type.
+
+
+========================
+EXPLICIT KERNEL BARRIERS
+========================
+
+The Linux kernel has a variety of different barriers that act at different
+levels:
+
+  (*) Compiler barrier.
+
+  (*) CPU memory barriers.
+
+  (*) MMIO write barrier.
+
+
+COMPILER BARRIER
+----------------
+
+The Linux kernel has an explicit compiler barrier function that prevents the
+compiler from moving the memory accesses either side of it to the other side:
+
+	barrier();
+
+This a general barrier - lesser varieties of compiler barrier do not exist.
+
+The compiler barrier has no direct effect on the CPU, which may then reorder
+things however it wishes.
+
+
+CPU MEMORY BARRIERS
+-------------------
+
+The Linux kernel has eight basic CPU memory barriers:
+
+	TYPE		MANDATORY		SMP CONDITIONAL
+	===============	=======================	===========================
+	GENERAL		mb()			smp_mb()
+	WRITE		wmb()			smp_wmb()
+	READ		rmb()			smp_rmb()
+	DATA DEPENDENCY	read_barrier_depends()	smp_read_barrier_depends()
+
+
+All CPU memory barriers unconditionally imply compiler barriers.
+
+SMP memory barriers are reduced to compiler barriers on uniprocessor compiled
+systems because it is assumed that a CPU will be appear to be self-consistent,
+and will order overlapping accesses correctly with respect to itself.
+
+[!] Note that SMP memory barriers _must_ be used if they look like they might
+be needed on an SMP system.
+
+Mandatory barriers should not be used to control SMP effects; but may be used
+to control MMIO effects on accesses through relaxed memory I/O windows.
+
+
+There are some more advanced barrier functions:
+
+ (*) set_mb(var, value)
+ (*) set_wmb(var, value)
+
+     These assign the value to the variable and then insert at least a write
+     barrier after it, depending on the function.  They aren't guaranteed to
+     insert anything more than a compiler barrier in a UP compilation.
+
+
+ (*) smp_mb__before_atomic_dec();
+ (*) smp_mb__after_atomic_dec();
+ (*) smp_mb__before_atomic_inc();
+ (*) smp_mb__after_atomic_inc();
+
+     These are for use with atomic add, subtract, increment and decrement
+     functions, especially when used for reference counting.  These functions
+     do not imply memory barriers.
+
+     As an example, consider a piece of code that marks an object as being dead
+     and then decrements the object's reference count:
+
+	obj->dead = 1;
+	smp_mb__before_atomic_dec();
+	atomic_dec(&obj->ref_count);
+
+     This makes sure that the death mark on the object is perceived to be set
+     *before* the reference counter is decremented.
+
+     See Documentation/atomic_ops.txt for more information.
+
+
+ (*) smp_mb__before_clear_bit(void);
+ (*) smp_mb__after_clear_bit(void);
+
+     These are for use similar to the atomic inc/dec barriers.  These are
+     typically used for bitwise unlocking operations, so care must be taken as
+     there are no implicit memory barriers here either.
+
+     Consider implementing an unlock operation of some nature by clearing a
+     locking bit.  The clear_bit() would then need to be barriered like this:
+
+	smp_mb__before_clear_bit();
+	clear_bit( ... );
+
+     This prevents memory operations before the clear leaking to after it.  See
+     the subsection on "Locking Functions" with reference to UNLOCK operation
+     implications.
+
+     See Documentation/atomic_ops.txt for more information.
+
+
+MMIO WRITE BARRIER
+------------------
+
+The Linux kernel also has a special barrier for use with memory-mapped I/O
+writes:
+
+	mmiowb();
+
+This is a variation on the mandatory write barrier that causes writes to weakly
+ordered I/O regions to be partially ordered.  Its effects may go beyond the
+CPU->Hardware interface and actually affect the hardware at some level.
+
+See the subsection "Locks vs I/O accesses" for more information.
+
+
+===============================
+IMPLICIT KERNEL MEMORY BARRIERS
+===============================
+
+Some of the other functions in the linux kernel imply memory barriers, amongst
+which are locking, scheduling and memory allocation functions.
+
+This specification is a _minimum_ guarantee; any particular architecture may
+provide more substantial guarantees, but these may not be relied upon outside
+of arch specific code.
+
+
+LOCKING FUNCTIONS
+-----------------
+
+The Linux kernel has a number of locking constructs:
+
+ (*) spin locks
+ (*) R/W spin locks
+ (*) mutexes
+ (*) semaphores
+ (*) R/W semaphores
+
+In all cases there are variants on "LOCK" operations and "UNLOCK" operations
+for each construct.  These operations all imply certain barriers:
+
+ (1) LOCK operation implication:
+
+     Memory operations issued after the LOCK will be completed after the LOCK
+     operation has completed.
+
+     Memory operations issued before the LOCK may be completed after the LOCK
+     operation has completed.
+
+ (2) UNLOCK operation implication:
+
+     Memory operations issued before the UNLOCK will be completed before the
+     UNLOCK operation has completed.
+
+     Memory operations issued after the UNLOCK may be completed before the
+     UNLOCK operation has completed.
+
+ (3) LOCK vs LOCK implication:
+
+     All LOCK operations issued before another LOCK operation will be completed
+     before that LOCK operation.
+
+ (4) LOCK vs UNLOCK implication:
+
+     All LOCK operations issued before an UNLOCK operation will be completed
+     before the UNLOCK operation.
+
+     All UNLOCK operations issued before a LOCK operation will be completed
+     before the LOCK operation.
+
+ (5) Failed conditional LOCK implication:
+
+     Certain variants of the LOCK operation may fail, either due to being
+     unable to get the lock immediately, or due to receiving an unblocked
+     signal whilst asleep waiting for the lock to become available.  Failed
+     locks do not imply any sort of barrier.
+
+Therefore, from (1), (2) and (4) an UNLOCK followed by an unconditional LOCK is
+equivalent to a full barrier, but a LOCK followed by an UNLOCK is not.
+
+[!] Note: one of the consequence of LOCKs and UNLOCKs being only one-way
+    barriers is that the effects instructions outside of a critical section may
+    seep into the inside of the critical section.
+
+Locks and semaphores may not provide any guarantee of ordering on UP compiled
+systems, and so cannot be counted on in such a situation to actually achieve
+anything at all - especially with respect to I/O accesses - unless combined
+with interrupt disabling operations.
+
+See also the section on "Inter-CPU locking barrier effects".
+
+
+As an example, consider the following:
+
+	*A = a;
+	*B = b;
+	LOCK
+	*C = c;
+	*D = d;
+	UNLOCK
+	*E = e;
+	*F = f;
+
+The following sequence of events is acceptable:
+
+	LOCK, {*F,*A}, *E, {*C,*D}, *B, UNLOCK
+
+	[+] Note that {*F,*A} indicates a combined access.
+
+But none of the following are:
+
+	{*F,*A}, *B,	LOCK, *C, *D,	UNLOCK, *E
+	*A, *B, *C,	LOCK, *D,	UNLOCK, *E, *F
+	*A, *B,		LOCK, *C,	UNLOCK, *D, *E, *F
+	*B,		LOCK, *C, *D,	UNLOCK, {*F,*A}, *E
+
+
+INTERRUPT DISABLING FUNCTIONS
+-----------------------------
+
+Functions that disable interrupts (LOCK equivalent) and enable interrupts
+(UNLOCK equivalent) will act as compiler barriers only.  So if memory or I/O
+barriers are required in such a situation, they must be provided from some
+other means.
+
+
+MISCELLANEOUS FUNCTIONS
+-----------------------
+
+Other functions that imply barriers:
+
+ (*) schedule() and similar imply full memory barriers.
+
+ (*) Memory allocation and release functions imply full memory barriers.
+
+
+=================================
+INTER-CPU LOCKING BARRIER EFFECTS
+=================================
+
+On SMP systems locking primitives give a more substantial form of barrier: one
+that does affect memory access ordering on other CPUs, within the context of
+conflict on any particular lock.
+
+
+LOCKS VS MEMORY ACCESSES
+------------------------
+
+Consider the following: the system has a pair of spinlocks (N) and (Q), and
+three CPUs; then should the following sequence of events occur:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	*A = a;				*E = e;
+	LOCK M				LOCK Q
+	*B = b;				*F = f;
+	*C = c;				*G = g;
+	UNLOCK M			UNLOCK Q
+	*D = d;				*H = h;
+
+Then there is no guarantee as to what order CPU #3 will see the accesses to *A
+through *H occur in, other than the constraints imposed by the separate locks
+on the separate CPUs. It might, for example, see:
+
+	*E, LOCK M, LOCK Q, *G, *C, *F, *A, *B, UNLOCK Q, *D, *H, UNLOCK M
+
+But it won't see any of:
+
+	*B, *C or *D preceding LOCK M
+	*A, *B or *C following UNLOCK M
+	*F, *G or *H preceding LOCK Q
+	*E, *F or *G following UNLOCK Q
+
+
+However, if the following occurs:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	*A = a;
+	LOCK M		[1]
+	*B = b;
+	*C = c;
+	UNLOCK M	[1]
+	*D = d;				*E = e;
+					LOCK M		[2]
+					*F = f;
+					*G = g;
+					UNLOCK M	[2]
+					*H = h;
+
+CPU #3 might see:
+
+	*E, LOCK M [1], *C, *B, *A, UNLOCK M [1],
+		LOCK M [2], *H, *F, *G, UNLOCK M [2], *D
+
+But assuming CPU #1 gets the lock first, it won't see any of:
+
+	*B, *C, *D, *F, *G or *H preceding LOCK M [1]
+	*A, *B or *C following UNLOCK M [1]
+	*F, *G or *H preceding LOCK M [2]
+	*A, *B, *C, *E, *F or *G following UNLOCK M [2]
+
+
+LOCKS VS I/O ACCESSES
+---------------------
+
+Under certain circumstances (especially involving NUMA), I/O accesses within
+two spinlocked sections on two different CPUs may be seen as interleaved by the
+PCI bridge, because the PCI bridge does not necessarily participate in the
+cache-coherence protocol, and is therefore incapable of issuing the required
+read memory barriers.
+
+For example:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	writel(1, DATA);
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					writel(5, DATA);
+					spin_unlock(Q);
+
+may be seen by the PCI bridge as follows:
+
+	STORE *ADDR = 0, STORE *ADDR = 4, STORE *DATA = 1, STORE *DATA = 5
+
+which would probably cause the hardware to malfunction.
+
+
+What is necessary here is to intervene with an mmiowb() before dropping the
+spinlock, for example:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	writel(1, DATA);
+	mmiowb();
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					writel(5, DATA);
+					mmiowb();
+					spin_unlock(Q);
+
+this will ensure that the two stores issued on CPU #1 appear at the PCI bridge
+before either of the stores issued on CPU #2.
+
+
+Furthermore, following a store by a load to the same device obviates the need
+for an mmiowb(), because the load forces the store to complete before the load
+is performed:
+
+	CPU 1				CPU 2
+	===============================	===============================
+	spin_lock(Q)
+	writel(0, ADDR)
+	a = readl(DATA);
+	spin_unlock(Q);
+					spin_lock(Q);
+					writel(4, ADDR);
+					b = readl(DATA);
+					spin_unlock(Q);
+
+
+See Documentation/DocBook/deviceiobook.tmpl for more information.
+
+
+=================================
+WHERE ARE MEMORY BARRIERS NEEDED?
+=================================
+
+Under normal operation, memory operation reordering is generally not going to
+be a problem as a single-threaded linear piece of code will still appear to
+work correctly, even if it's in an SMP kernel.  There are, however, three
+circumstances in which reordering definitely _could_ be a problem:
+
+ (*) Interprocessor interaction.
+
+ (*) Atomic operations.
+
+ (*) Accessing devices (I/O).
+
+ (*) Interrupts.
+
+
+INTERPROCESSOR INTERACTION
+--------------------------
+
+When there's a system with more than one processor, more than one CPU in the
+system may be working on the same data set at the same time.  This can cause
+synchronisation problems, and the usual way of dealing with them is to use
+locks.  Locks, however, are quite expensive, and so it may be preferable to
+operate without the use of a lock if at all possible.  In such a case
+operations that affect both CPUs may have to be carefully ordered to prevent
+a malfunction.
+
+Consider, for example, the R/W semaphore slow path.  Here a waiting process is
+queued on the semaphore, by virtue of it having a piece of its stack linked to
+the semaphore's list of waiting processes:
+
+	struct rw_semaphore {
+		...
+		spinlock_t lock;
+		struct list_head waiters;
+	};
+
+	struct rwsem_waiter {
+		struct list_head list;
+		struct task_struct *task;
+	};
+
+To wake up a particular waiter, the up_read() or up_write() functions have to:
+
+ (1) read the next pointer from this waiter's record to know as to where the
+     next waiter record is;
+
+ (4) read the pointer to the waiter's task structure;
+
+ (3) clear the task pointer to tell the waiter it has been given the semaphore;
+
+ (4) call wake_up_process() on the task; and
+
+ (5) release the reference held on the waiter's task struct.
+
+In otherwords, it has to perform this sequence of events:
+
+	LOAD waiter->list.next;
+	LOAD waiter->task;
+	STORE waiter->task;
+	CALL wakeup
+	RELEASE task
+
+and if any of these steps occur out of order, then the whole thing may
+malfunction.
+
+Once it has queued itself and dropped the semaphore lock, the waiter does not
+get the lock again; it instead just waits for its task pointer to be cleared
+before proceeding.  Since the record is on the waiter's stack, this means that
+if the task pointer is cleared _before_ the next pointer in the list is read,
+another CPU might start processing the waiter and might clobber the waiter's
+stack before the up*() function has a chance to read the next pointer.
+
+Consider then what might happen to the above sequence of events:
+
+	CPU 1				CPU 2
+	===============================	===============================
+					down_xxx()
+					Queue waiter
+					Sleep
+	up_yyy()
+	LOAD waiter->task;
+	STORE waiter->task;
+					Woken up by other event
+	<preempt>
+					Resume processing
+					down_xxx() returns
+					call foo()
+					foo() clobbers *waiter
+	</preempt>
+	LOAD waiter->list.next;
+	--- OOPS ---
+
+This could be dealt with using the semaphore lock, but then the down_xxx()
+function has to needlessly get the spinlock again after being woken up.
+
+The way to deal with this is to insert a general SMP memory barrier:
+
+	LOAD waiter->list.next;
+	LOAD waiter->task;
+	smp_mb();
+	STORE waiter->task;
+	CALL wakeup
+	RELEASE task
+
+In this case, the barrier makes a guarantee that all memory accesses before the
+barrier will appear to happen before all the memory accesses after the barrier
+with respect to the other CPUs on the system.  It does _not_ guarantee that all
+the memory accesses before the barrier will be complete by the time the barrier
+instruction itself is complete.
+
+On a UP system - where this wouldn't be a problem - the smp_mb() is just a
+compiler barrier, thus making sure the compiler emits the instructions in the
+right order without actually intervening in the CPU.  Since there there's only
+one CPU, that CPU's dependency ordering logic will take care of everything
+else.
+
+
+ATOMIC OPERATIONS
+-----------------
+
+Though they are technically interprocessor interaction considerations, atomic
+operations are noted specially as they do _not_ generally imply memory
+barriers.  The possible offenders include:
+
+	xchg();
+	cmpxchg();
+	test_and_set_bit();
+	test_and_clear_bit();
+	test_and_change_bit();
+	atomic_cmpxchg();
+	atomic_inc_return();
+	atomic_dec_return();
+	atomic_add_return();
+	atomic_sub_return();
+	atomic_inc_and_test();
+	atomic_dec_and_test();
+	atomic_sub_and_test();
+	atomic_add_negative();
+	atomic_add_unless();
+
+These may be used for such things as implementing LOCK operations or controlling
+the lifetime of objects by decreasing their reference counts.
+
+The following may also be possible offenders as they may be used as UNLOCK
+operations.
+
+	set_bit();
+	clear_bit();
+	change_bit();
+	atomic_set();
+
+But the following should be safe as they can't be used for conditional
+processing since they don't return a result.
+
+	atomic_add();
+	atomic_sub();
+	atomic_inc();
+	atomic_dec();
+
+See Documentation/atomic_ops.txt for more information.
+
+
+ACCESSING DEVICES
+-----------------
+
+Many devices can be memory mapped, and so appear to the CPU as if they're just
+as set of memory locations.  However, to control the device, the driver
+usually has to make the right accesses in exactly the right order.
+
+Consider, for example, an ethernet chipset such as the AMD PCnet32.  It
+presents to the CPU an "address register" and a bunch of "data registers".  The
+way it's accessed is to write the index of the internal register to be accessed
+to the address register, and then read or write the appropriate data register
+to access the chip's internal register.  This could theoretically be done by:
+
+	*ADDR = 3;
+	reg = *DATA;
+
+Or:
+
+	*ADDR = 3;
+	*DATA = value;
+
+The problem with a clever CPU or a clever compiler is that the store to the
+address register is not guaranteed to happen before the operation on the data
+register, if the CPU or the compiler thinks it is more efficient to defer the
+address store:
+
+	LOAD *DATA, STORE *ADDR
+
+or:
+
+	STORE *DATA, STORE *ADDR
+
+which will cause the device or the driver to malfunction.
+
+
+In the Linux kernel, however, I/O should be done through the appropriate
+accessor routines - such as inb() or writel() - which know how to make such
+accesses appropriately sequential.
+
+On some systems, I/O stores are not strongly ordered across all CPUs, and so
+locking should be used and mmiowb() must be issued prior to unlocking the
+critical section.
+
+See Documentation/DocBook/deviceiobook.tmpl for more information.
+
+
+INTERRUPTS
+----------
+
+A driver may be interrupted by its own interrupt service routine, and thus the
+two parts of the driver may interfere with each other's attempts to control or
+access the device.
+
+This may be alleviated - at least in part - by disabling local interrupts (a
+form of locking), such that the critical operations are all contained within
+the interrupt-disabled section in the driver.  Whilst the driver's interrupt
+routine is executing, the driver's core may not run on the same CPU, and its
+interrupt is not permitted to happen again until the current interrupt has been
+handled, thus the interrupt handler does not need to lock against that.
+
+However, consider a driver that was talking to an ethernet card that sports an
+address register and a data register.  If that driver's core talks to the card
+under interrupt-disablement and then the driver's interrupt handler is invoked:
+
+	LOCAL IRQ DISABLE
+	writew(ADDR, 3);
+	writew(DATA, y);
+	LOCAL IRQ ENABLE
+	<interrupt>
+	writew(ADDR, 4);
+	q = readw(DATA);
+	</interrupt>
+
+The store to the data register might happen after the second store to the
+address register if ordering rules are sufficiently relaxed:
+
+	STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA
+
+
+If ordering rules are relaxed, it must be assumed that accesses done inside an
+interrupt disabled section may leak outside of it and may interleave with
+accesses performed in an interrupt - and vice versa - unless implicit or
+explicit barriers are used.
+
+Normally this won't be a problem because the I/O accesses done inside such
+sections will include synchronous load operations on strictly ordered I/O
+registers that form implicit I/O barriers. If this isn't sufficient then an
+mmiowb() may need to be used explicitly.
+
+
+A similar situation may occur between an interrupt routine and two routines
+running on separate CPUs that communicate with each other. If such a case is
+likely, then interrupt-disabling locks should be used to guarantee ordering.
+
+
+==========================
+KERNEL I/O BARRIER EFFECTS
+==========================
+
+When accessing I/O memory, drivers should use the appropriate accessor
+functions:
+
+ (*) inX(), outX():
+
+     These are intended to talk to I/O space rather than memory space, but
+     that's primarily a CPU-specific concept. The i386 and x86_64 processors do
+     indeed have special I/O space access cycles and instructions, but many
+     CPUs don't have such a concept.
+
+     The PCI bus, amongst others, defines an I/O space concept - which on such
+     CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O
+     space.  However, it may also mapped as a virtual I/O space in the CPU's
+     memory map, particularly on those CPUs that don't support alternate
+     I/O spaces.
+
+     Accesses to this space may be fully synchronous (as on i386), but
+     intermediary bridges (such as the PCI host bridge) may not fully honour
+     that.
+
+     They are guaranteed to be fully ordered with respect to each other.
+
+     They are not guaranteed to be fully ordered with respect to other types of
+     memory and I/O operation.
+
+ (*) readX(), writeX():
+
+     Whether these are guaranteed to be fully ordered and uncombined with
+     respect to each other on the issuing CPU depends on the characteristics
+     defined for the memory window through which they're accessing. On later
+     i386 architecture machines, for example, this is controlled by way of the
+     MTRR registers.
+
+     Ordinarily, these will be guaranteed to be fully ordered and uncombined,,
+     provided they're not accessing a prefetchable device.
+
+     However, intermediary hardware (such as a PCI bridge) may indulge in
+     deferral if it so wishes; to flush a store, a load from the same location
+     is preferred[*], but a load from the same device or from configuration
+     space should suffice for PCI.
+
+     [*] NOTE! attempting to load from the same location as was written to may
+     	 cause a malfunction - consider the 16550 Rx/Tx serial registers for
+     	 example.
+
+     Used with prefetchable I/O memory, an mmiowb() barrier may be required to
+     force stores to be ordered.
+
+     Please refer to the PCI specification for more information on interactions
+     between PCI transactions.
+
+ (*) readX_relaxed()
+
+     These are similar to readX(), but are not guaranteed to be ordered in any
+     way. Be aware that there is no I/O read barrier available.
+
+ (*) ioreadX(), iowriteX()
+
+     These will perform as appropriate for the type of access they're actually
+     doing, be it inX()/outX() or readX()/writeX().
+
+
+========================================
+ASSUMED MINIMUM EXECUTION ORDERING MODEL
+========================================
+
+It has to be assumed that the conceptual CPU is weakly-ordered but that it will
+maintain the appearance of program causality with respect to itself.  Some CPUs
+(such as i386 or x86_64) are more constrained than others (such as powerpc or
+frv), and so the most relaxed case (namely DEC Alpha) must be assumed outside
+of arch-specific code.
+
+This means that it must be considered that the CPU will execute its instruction
+stream in any order it feels like - or even in parallel - provided that if an
+instruction in the stream depends on the an earlier instruction, then that
+earlier instruction must be sufficiently complete[*] before the later
+instruction may proceed; in other words: provided that the appearance of
+causality is maintained.
+
+ [*] Some instructions have more than one effect - such as changing the
+     condition codes, changing registers or changing memory - and different
+     instructions may depend on different effects.
+
+A CPU may also discard any instruction sequence that winds up having no
+ultimate effect.  For example, if two adjacent instructions both load an
+immediate value into the same register, the first may be discarded.
+
+
+Similarly, it has to be assumed that compiler might reorder the instruction
+stream in any way it sees fit, again provided the appearance of causality is
+maintained.
+
+
+============================
+THE EFFECTS OF THE CPU CACHE
+============================
+
+The way cached memory operations are perceived across the system is affected to
+a certain extent by the caches that lie between CPUs and memory, and by the
+memory coherence system that maintains the consistency of state in the system.
+
+As far as the way a CPU interacts with another part of the system through the
+caches goes, the memory system has to include the CPU's caches, and memory
+barriers for the most part act at the interface between the CPU and its cache
+(memory barriers logically act on the dotted line in the following diagram):
+
+	    <--- CPU --->         :       <----------- Memory ----------->
+	                          :
+	+--------+    +--------+  :   +--------+    +-----------+
+	|        |    |        |  :   |        |    |           |    +--------+
+	|  CPU   |    | Memory |  :   | CPU    |    |           |    |	      |
+	|  Core  |--->| Access |----->| Cache  |<-->|           |    |	      |
+	|        |    | Queue  |  :   |        |    |           |--->| Memory |
+	|        |    |        |  :   |        |    |           |    |	      |
+	+--------+    +--------+  :   +--------+    |           |    | 	      |
+	                          :                 | Cache     |    +--------+
+	                          :                 | Coherency |
+	                          :                 | Mechanism |    +--------+
+	+--------+    +--------+  :   +--------+    |           |    |	      |
+	|        |    |        |  :   |        |    |           |    |        |
+	|  CPU   |    | Memory |  :   | CPU    |    |           |--->| Device |
+	|  Core  |--->| Access |----->| Cache  |<-->|           |    | 	      |
+	|        |    | Queue  |  :   |        |    |           |    | 	      |
+	|        |    |        |  :   |        |    |           |    +--------+
+	+--------+    +--------+  :   +--------+    +-----------+
+	                          :
+	                          :
+
+Although any particular load or store may not actually appear outside of the
+CPU that issued it since it may have been satisfied within the CPU's own cache,
+it will still appear as if the full memory access had taken place as far as the
+other CPUs are concerned since the cache coherency mechanisms will migrate the
+cacheline over to the accessing CPU and propagate the effects upon conflict.
+
+The CPU core may execute instructions in any order it deems fit, provided the
+expected program causality appears to be maintained.  Some of the instructions
+generate load and store operations which then go into the queue of memory
+accesses to be performed.  The core may place these in the queue in any order
+it wishes, and continue execution until it is forced to wait for an instruction
+to complete.
+
+What memory barriers are concerned with is controlling the order in which
+accesses cross from the CPU side of things to the memory side of things, and
+the order in which the effects are perceived to happen by the other observers
+in the system.
+
+[!] Memory barriers are _not_ needed within a given CPU, as CPUs always see
+their own loads and stores as if they had happened in program order.
+
+
+CACHE COHERENCY
+---------------
+
+Life isn't quite as simple as it may appear above, however: for while the
+caches are expected to be coherent, there's no guarantee that that coherency
+will be ordered.  This means that whilst changes made on one CPU will
+eventually become visible on all CPUs, there's no guarantee that they will
+become apparent in the same order on those other CPUs.
+
+
+Consider dealing with a system that has pair of CPUs (1 & 2), each of which has
+a pair of parallel data caches (CPU 1 has A/B, and CPU 2 has C/D):
+
+	            :
+	            :                          +--------+
+	            :      +---------+         |        |
+	+--------+  : +--->| Cache A |<------->|        |
+	|        |  : |    +---------+         |        |
+	|  CPU 1 |<---+                        |        |
+	|        |  : |    +---------+         |        |
+	+--------+  : +--->| Cache B |<------->|        |
+	            :      +---------+         |        |
+	            :                          | Memory |
+	            :      +---------+         | System |
+	+--------+  : +--->| Cache C |<------->|        |
+	|        |  : |    +---------+         |        |
+	|  CPU 2 |<---+                        |        |
+	|        |  : |    +---------+         |        |
+	+--------+  : +--->| Cache D |<------->|        |
+	            :      +---------+         |        |
+	            :                          +--------+
+	            :
+
+Imagine the system has the following properties:
+
+ (*) an odd-numbered cache line may be in cache A, cache C or it may still be
+     resident in memory;
+
+ (*) an even-numbered cache line may be in cache B, cache D or it may still be
+     resident in memory;
+
+ (*) whilst the CPU core is interrogating one cache, the other cache may be
+     making use of the bus to access the rest of the system - perhaps to
+     displace a dirty cacheline or to do a speculative load;
+
+ (*) each cache has a queue of operations that need to be applied to that cache
+     to maintain coherency with the rest of the system;
+
+ (*) the coherency queue is not flushed by normal loads to lines already
+     present in the cache, even though the contents of the queue may
+     potentially effect those loads.
+
+Imagine, then, that two writes are made on the first CPU, with a write barrier
+between them to guarantee that they will appear to reach that CPU's caches in
+the requisite order:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();			Make sure change to v visible before
+					 change to p
+	<A:modify v=2>			v is now in cache A exclusively
+	p = &v;
+	<B:modify p=&v>			p is now in cache B exclusively
+
+The write memory barrier forces the other CPUs in the system to perceive that
+the local CPU's caches have apparently been updated in the correct order.  But
+now imagine that the second CPU that wants to read those values:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+	...
+			q = p;
+			x = *q;
+
+The above pair of reads may then fail to happen in expected order, as the
+cacheline holding p may get updated in one of the second CPU's caches whilst
+the update to the cacheline holding v is delayed in the other of the second
+CPU's caches by some other cache event:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();
+	<A:modify v=2>	<C:busy>
+			<C:queue v=2>
+	p = &b;		q = p;
+			<D:request p>
+	<B:modify p=&v>	<D:commit p=&v>
+		  	<D:read p>
+			x = *q;
+			<C:read *q>	Reads from v before v updated in cache
+			<C:unbusy>
+			<C:commit v=2>
+
+Basically, whilst both cachelines will be updated on CPU 2 eventually, there's
+no guarantee that, without intervention, the order of update will be the same
+as that committed on CPU 1.
+
+
+To intervene, we need to interpolate a data dependency barrier or a read
+barrier between the loads.  This will force the cache to commit its coherency
+queue before processing any further requests:
+
+	CPU 1		CPU 2		COMMENT
+	===============	===============	=======================================
+					u == 0, v == 1 and p == &u, q == &u
+	v = 2;
+	smp_wmb();
+	<A:modify v=2>	<C:busy>
+			<C:queue v=2>
+	p = &b;		q = p;
+			<D:request p>
+	<B:modify p=&v>	<D:commit p=&v>
+		  	<D:read p>
+			smp_read_barrier_depends()
+			<C:unbusy>
+			<C:commit v=2>
+			x = *q;
+			<C:read *q>	Reads from v after v updated in cache
+
+
+This sort of problem can be encountered on DEC Alpha processors as they have a
+split cache that improves performance by making better use of the data bus.
+Whilst most CPUs do imply a data dependency barrier on the read when a memory
+access depends on a read, not all do, so it may not be relied on.
+
+
+CACHE COHERENCY VS DMA
+----------------------
+
+Not all systems maintain cache coherency with respect to devices doing DMA.  In
+such cases, a device attempting DMA may obtain stale data from RAM because
+dirty cache lines may be resident in the caches of various CPUs, and may not
+have been written back to RAM yet.  To deal with this, the appropriate part of
+the kernel must flush the overlapping bits of cache on each CPU (and maybe
+invalidate them as well).
+
+In addition, the data DMA'd to RAM by a device may be overwritten by dirty
+cache lines being written back to RAM from a CPU's cache after the device has
+installed its own data, or cache lines simply present in a CPUs cache may
+simply obscure the fact that RAM has been updated, until at such time as the
+cacheline is discarded from the CPU's cache and reloaded.  To deal with this,
+the appropriate part of the kernel must invalidate the overlapping bits of the
+cache on each CPU.
+
+See Documentation/cachetlb.txt for more information on cache management.
+
+
+CACHE COHERENCY VS MMIO
+-----------------------
+
+Memory mapped I/O usually takes place through memory locations that are part of
+a window in the CPU's memory space that have different properties assigned than
+the usual RAM directed window.
+
+Amongst these properties is usually the fact that such accesses bypass the
+caching entirely and go directly to the device buses.  This means MMIO accesses
+may, in effect, overtake accesses to cached memory that were emitted earlier.
+A memory barrier isn't sufficient in such a case, but rather the cache must be
+flushed between the cached memory write and the MMIO access if the two are in
+any way dependent.
+
+
+=========================
+THE THINGS CPUS GET UP TO
+=========================
+
+A programmer might take it for granted that the CPU will perform memory
+operations in exactly the order specified, so that if a CPU is, for example,
+given the following piece of code to execute:
+
+	a = *A;
+	*B = b;
+	c = *C;
+	d = *D;
+	*E = e;
+
+They would then expect that the CPU will complete the memory operation for each
+instruction before moving on to the next one, leading to a definite sequence of
+operations as seen by external observers in the system:
+
+	LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E.
+
+
+Reality is, of course, much messier.  With many CPUs and compilers, the above
+assumption doesn't hold because:
+
+ (*) loads are more likely to need to be completed immediately to permit
+     execution progress, whereas stores can often be deferred without a
+     problem;
+
+ (*) loads may be done speculatively, and the result discarded should it prove
+     to have been unnecessary;
+
+ (*) loads may be done speculatively, leading to the result having being
+     fetched at the wrong time in the expected sequence of events;
+
+ (*) the order of the memory accesses may be rearranged to promote better use
+     of the CPU buses and caches;
+
+ (*) loads and stores may be combined to improve performance when talking to
+     memory or I/O hardware that can do batched accesses of adjacent locations,
+     thus cutting down on transaction setup costs (memory and PCI devices may
+     both be able to do this); and
+
+ (*) the CPU's data cache may affect the ordering, and whilst cache-coherency
+     mechanisms may alleviate this - once the store has actually hit the cache
+     - there's no guarantee that the coherency management will be propagated in
+     order to other CPUs.
+
+So what another CPU, say, might actually observe from the above piece of code
+is:
+
+	LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B
+
+	(Where "LOAD {*C,*D}" is a combined load)
+
+
+However, it is guaranteed that a CPU will be self-consistent: it will see its
+_own_ accesses appear to be correctly ordered, without the need for a memory
+barrier.  For instance with the following code:
+
+	X = *A;
+	*A = Y;
+	Z = *A;
+
+and assuming no intervention by an external influence, it can be taken that:
+
+ (*) X will hold the old value of *A, and will never happen after the store and
+     thus end up being given the value that was assigned to *A from Y instead;
+     and
+
+ (*) Z will always be given the value in *A that was assigned there from Y, and
+     will never happen before the store, and thus end up with the same value
+     that was in *A initially.
+
+(This is ignoring the fact that the value initially in *A may appear to be the
+same as the value assigned to *A from Y).
+
+
+AND THEN THERE'S THE ALPHA
+--------------------------
+
+The DEC Alpha CPU is one of the most relaxed CPUs there is.  Not only that,
+some versions of the Alpha CPU have a split data cache, permitting them to have
+two semantically related cache lines updating at separate times.  This is where
+the data dependency barrier really becomes necessary as this synchronises both
+caches with the memory coherence system, thus making it seem like pointer
+changes vs new data occur in the right order.
+
+The Alpha defines the Linux's kernel's memory barrier model.
+
+See the subsection on "Cache Coherency" above.
+
+
+==========
+REFERENCES
+==========
+
+Alpha AXP Architecture Reference Manual, Second Edition (Sites & Witek,
+Digital Press)
+	Chapter 5.2: Physical Address Space Characteristics
+	Chapter 5.4: Caches and Write Buffers
+	Chapter 5.5: Data Sharing
+	Chapter 5.6: Read/Write Ordering
+
+AMD64 Architecture Programmer's Manual Volume 2: System Programming
+	Chapter 7.1: Memory-Access Ordering
+	Chapter 7.4: Buffering and Combining Memory Writes
+
+IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+System Programming Guide
+	Chapter 7.1: Locked Atomic Operations
+	Chapter 7.2: Memory Ordering
+	Chapter 7.4: Serializing Instructions
+
+The SPARC Architecture Manual, Version 9
+	Chapter 8: Memory Models
+	Appendix D: Formal Specification of the Memory Models
+	Appendix J: Programming with the Memory Models
+
+UltraSPARC Programmer Reference Manual
+	Chapter 5: Memory Accesses and Cacheability
+	Chapter 15: Sparc-V9 Memory Models
+
+UltraSPARC III Cu User's Manual
+	Chapter 9: Memory Models
+
+UltraSPARC IIIi Processor User's Manual
+	Chapter 8: Memory Models
+
+UltraSPARC Architecture 2005
+	Chapter 9: Memory
+	Appendix D: Formal Specifications of the Memory Models
+
+UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
+	Chapter 8: Memory Models
+	Appendix F: Caches and Cache Coherency
+
+Solaris Internals, Core Kernel Architecture, p63-68:
+	Chapter 3.3: Hardware Considerations for Locks and
+			Synchronization
+
+Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching
+for Kernel Programmers:
+	Chapter 13: Other Memory Models
+
+Intel Itanium Architecture Software Developer's Manual: Volume 1:
+	Section 2.6: Speculation
+	Section 4.4: Memory Access
diff -urN oldtree/Documentation/pcmcia/driver-changes.txt newtree/Documentation/pcmcia/driver-changes.txt
--- oldtree/Documentation/pcmcia/driver-changes.txt	2006-04-01 04:48:27.000000000 -0500
+++ newtree/Documentation/pcmcia/driver-changes.txt	2006-04-01 05:35:44.235384500 -0500
@@ -1,5 +1,11 @@
 This file details changes in 2.6 which affect PCMCIA card driver authors:
 
+* New release helper (as of 2.6.17)
+   Instead of calling pcmcia_release_{configuration,io,irq,win}, all that's
+   necessary now is calling pcmcia_disable_device. As there is no valid
+   reason left to call pcmcia_release_io and pcmcia_release_irq, the
+   exports for them were removed.
+
 * Unify detach and REMOVAL event code, as well as attach and INSERTION
   code (as of 2.6.16)
        void (*remove)          (struct pcmcia_device *dev);
diff -urN oldtree/Documentation/scsi/ChangeLog.arcmsr newtree/Documentation/scsi/ChangeLog.arcmsr
--- oldtree/Documentation/scsi/ChangeLog.arcmsr	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/scsi/ChangeLog.arcmsr	2006-04-01 05:35:45.807482750 -0500
@@ -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/scsi/arcmsr_spec.txt newtree/Documentation/scsi/arcmsr_spec.txt
--- oldtree/Documentation/scsi/arcmsr_spec.txt	1969-12-31 19:00:00.000000000 -0500
+++ newtree/Documentation/scsi/arcmsr_spec.txt	2006-04-01 05:35:45.839484750 -0500
@@ -0,0 +1,4406 @@
+************************************************************************************************************
+**						80331 PCI-to-PCI Bridge
+**						PCI Configuration Space
+**			@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+**						Programming Interface
+**					     ========================
+**			Configuration Register Address Space Groupings and Ranges
+**			=============================================================
+**			Register Group                      Configuration  Offset
+**			-------------------------------------------------------------
+**			Standard PCI Configuration                      00-3Fh
+**			-------------------------------------------------------------
+**			Device Specific Registers                      40-A7h
+**			-------------------------------------------------------------
+**			Reserved                                 A8-CBh
+**			-------------------------------------------------------------
+**			Enhanced Capability List                      CC-FFh
+** ==========================================================================================================
+**                         Standard PCI [Type 1] Configuration Space Address Map
+** **********************************************************************************************************
+** |    Byte 3              |         Byte 2         |        Byte 1          |       Byte 0              |Offset
+** ----------------------------------------------------------------------------------------------------------
+** |                    Device ID                    |                     Vendor ID                      | 00h
+** ----------------------------------------------------------------------------------------------------------
+** |                 Primary Status                  |                  Primary Command                   | 04h
+** ----------------------------------------------------------------------------------------------------------
+** |                   Class Code                                             |        RevID              | 08h
+** ----------------------------------------------------------------------------------------------------------
+** |        reserved        |      Header Type       |      Primary MLT       |      Primary CLS          | 0Ch
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 10h
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 14h
+** ----------------------------------------------------------------------------------------------------------
+** |     Secondary MLT      | Subordinate Bus Number |  Secondary Bus Number  |     Primary Bus Number    | 18h
+** ----------------------------------------------------------------------------------------------------------
+** |                 Secondary Status                |       I/O Limit        |        I/O Base           | 1Ch
+** ----------------------------------------------------------------------------------------------------------
+** |      Non-prefetchable Memory Limit Address      |       Non-prefetchable Memory Base Address         | 20h
+** ----------------------------------------------------------------------------------------------------------
+** |        Prefetchable Memory Limit Address        |           Prefetchable Memory Base Address         | 24h
+** ----------------------------------------------------------------------------------------------------------
+** |                          Prefetchable Memory Base Address Upper 32 Bits                              | 28h
+** ----------------------------------------------------------------------------------------------------------
+** |                          Prefetchable Memory Limit Address Upper 32 Bits                             | 2Ch
+** ----------------------------------------------------------------------------------------------------------
+** |             I/O Limit Upper 16 Bits             |                 I/O Base Upper 16                  | 30h
+** ----------------------------------------------------------------------------------------------------------
+** |                                Reserved                                  |   Capabilities Pointer    | 34h
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 38h
+** ----------------------------------------------------------------------------------------------------------
+** |                   Bridge Control                |  Primary Interrupt Pin | Primary Interrupt Line    | 3Ch
+**=============================================================================================================
+**=============================================================================================================
+**  0x03-0x00 :
+** Bit       Default             Description
+**31:16       0335h            Device ID (DID): Indicates the unique device ID that is assigned
+**								to bridge by the PCI SIG.
+**								ID is unique per product speed as indicated.
+**15:00       8086h            Vendor ID (VID): 16-bit field which indicates that Intel is the vendor.
+**=============================================================================================================
+**  0x05-0x04 : command register
+** Bit		Default 					Description
+**15:11	00h						Reserved
+** 10		0						Interrupt Disable: Disables/Enables the generation
+**											of Interrupts on the primary bus
+**											The bridge does not support interrupts.
+** 09		0						FB2B Enable: Enables/Disables the generation of
+**										fast back to back transactions on the primary bus
+**								The bridge does not generate fast back to back transactions
+**								on the primary bus.
+** 08		0						SERR# Enable (SEE): Enables primary bus SERR# assertions
+**											0=The bridge does not assert P_SERR#
+**											1=The bridge may assert P_SERR#,
+**											subject to other programmable criteria
+** 07		0						Wait Cycle Control (WCC): Always returns 0bzero indicating that
+**										bridge does not perform address or data stepping
+** 06		0						Parity Error Response (PER): Controls bridge response to a
+**												detected primary bus parity error
+**											0=When a data parity error is detected
+**												bridge does not assert S_PERR#
+**												Also bridge does not assert P_SERR#
+**												in response to a detected address or
+**												attribute parity error.
+**											1=When a data parity error is detected bridge
+**												asserts S_PERR#
+**								The bridge also asserts P_SERR# (when enabled globally via bit(8)
+**								of this register) in response to a detected address or attribute
+**								parity error.
+** 05		0						VGA Palette Snoop Enable (VGA_PSE): Controls bridge response to
+**								VGA-compatible palette write transactions.
+**								VGA palette write transactions are I/O transactions whose address
+**								bits are: P_AD[9:0] equal to 3C6h, 3C8h or 3C9h
+**								P_AD[15:10] are not decoded (i.e. aliases are claimed),
+**								or are fully decoding (i.e., must be all 0's depending upon the VGA
+**								aliasing bit in the Bridge Control Register, offset 3Eh
+**								P_AD[31:16] equal to 0000h
+**								0=The bridge ignores VGA palette write transactions, unless decoded
+**									by the standard I/O address range window
+**								1=The bridge responds to VGA palette write transactions with medium
+**									 DEVSEL# timing and forwards them to the secondary bus
+** 04		0						Memory Write and Invalidate Enable (MWIE): The bridge does not
+**								promote MW transactions to MWI transactions.
+**								MWI transactions targeting resources on the opposite side of the
+**								bridge, however, are forwarded as MWI transactions.
+** 03		0						Special Cycle Enable (SCE): The bridge ignores special cycle
+**								transactions
+**								This bit is read only and always returns 0 when read
+** 02		0						Bus Master Enable (BME): Enables bridge to initiate memory and I/O
+**								transactions on the primary interface
+**								Initiation of configuration transactions is not affected by the
+**								state of this bit
+**									0=The bridge does not initiate memory or I/O transactions on
+**										the primary interface.
+**									1=The bridge is enabled to function as an initiator on the
+**										primary interface.
+** 01		0						Memory Space Enable (MSE): Controls target response to memory
+**								transactions on the primary interface
+**									0=The bridge target response to memory transactions on the
+**										 primary interface is disabled.
+**									1=The bridge target response to memory transactions on the
+**										primary interface is enabled.
+** 00		0						I/O Space Enable (IOSE): Controls target response to
+**								I/O transactions on the primary interface.
+**									0=The bridge target response to I/O transactions
+**										on the primary interface is disabled
+**									1=The bridge target response to I/O transactions
+**										on the primary interface is enabled.
+**========================================================================
+**========================================================================
+**  0x07-0x06 : status register
+** Bit       Default					Description
+** 15		0						Detected Parity Error: The bridge sets this bit to a 1b
+**								whenever it detects an address, attribute or data parity error
+**								This bit is set regardless of the state of the PER bit in
+**								the command register.
+** 14		0						Signaled System Error: The bridge sets this bit to a 1b
+** 								whenever it asserts SERR# on the primary bus.
+** 13		0						Received Master Abort: The bridge sets this bit to a 1b when,
+**								acting as the initiator on the primary bus, its transaction
+**								(with the exception of special cycles) has been terminated
+**								with a Master Abort.
+** 12		0						Received Target Abort: The bridge sets this bit to a 1b when,
+**								acting as the initiator on the primary bus, its transaction
+**								has been terminated with a Target Abort.
+** 11		0						Signaled Target Abort: The bridge sets this bit to a 1b when it,
+**								as the target of a transaction, terminates it with a Target Abort
+**								In PCI-X mode this bit is also set when it forwards a SCM with
+**								a target abort error code
+** 10:09	01						DEVSEL# Timing: Indicates slowest response to
+**								a non-configuration command on the primary interface
+**								Returns 01b when read, indicating that bridge responds
+**								no slower than with medium timing.
+** 08		0						Master Data Parity Error: The bridge sets this bit to a 1b when
+**								all of the following conditions are true: The bridge is the
+**								current master on the primary bus
+**								S_PERR# is detected asserted or is asserted by bridge
+**								The Parity Error Response bit is set in the Command register
+** 07		1						Fast Back to Back Capable: Returns a 1b when read indicating
+**								that bridge is able to respond to fast back to back transactions
+**								on its primary interface.
+** 06		0						Reserved
+** 05		1						66 MHz Capable Indication: Returns a 1b when read indicating
+**								that bridge primary interface is 66 MHz capable.
+** 04		1						Capabilities List Enable: Returns 1b when read indicating
+**								that bridge supports PCI standard enhanced capabilities
+**								Offset 34h (Capability Pointer register) provides the offset
+**								for the first entry in the linked list of enhanced capabilities.
+** 03		0						Interrupt Status: Reflects the state of the interrupt in the
+**								device/function. The bridge does not support interrupts.
+** 02:00	000						Reserved
+**==============================================================================
+**==============================================================================
+**  0x08 : revision ID
+** Bit		Default					Description
+** 07:00	00000000					Revision ID (RID): '00h' indicating bridge A-0 stepping.
+**==============================================================================
+**==============================================================================
+**  0x0b-0x09 : 0180_00 (class code 1,native pci mode )
+** Bit		Default					Description
+** 23:16	06h						Base Class Code (BCC): Indicates that this is a bridge device.
+** 15:08	04h						Sub Class Code (SCC): Indicates this is of type PCI-to-PCI bridge.
+** 07:00	00h						Programming Interface (PIF): Indicates that this is standard
+**								(non-subtractive) PCI-PCI bridge.
+**==============================================================================
+**==============================================================================
+**  0x0c : cache line size
+** Bit		Default					Description
+** 07:00	00h						Cache Line Size (CLS): Designates the cache line size in 32-bit
+**								dword units.
+**								The contents of this register are factored into internal
+**								policy decisions associated with memory read prefetching,
+**								and the promotion of Memory Write transactions to MWI transactions
+**								Valid cache line sizes are 8 and 16 dwords
+**								When the cache line size is set to an invalid value,
+**								bridge behaves as though the cache line size was set to 00h
+**==============================================================================
+**==============================================================================
+**  0x0d : latency timer (number of pci clock 00-ff )
+** Bit		Default					Description
+**								Primary Latency Timer (PTV):
+** 07:00	00h			(Conventional PCI) Conventional PCI Mode: Primary bus Master latency timer.
+**								Indicates the number of PCI clock cycles,
+**								referenced from the assertion of FRAME# to the expiration of
+**								the timer, when bridge may continue as master of the current
+**								transaction. All bits are writable, resulting in
+**								a granularity of 1 PCI clock cycle.
+**								When the timer expires (i.e., equals 00h)
+**								bridge relinquishes the bus after the first data transfer
+**								when its PCI bus grant has been deasserted.
+**					or 40h (PCI-X)     PCI-X Mode: Primary bus Master latency timer.
+**								Indicates the number of PCI clock cycles,
+**								referenced from the assertion of FRAME# to the expiration
+**								of the timer, when bridge may continue as master of the current
+**								transaction.
+**								All bits are writable, resulting in a granularity
+**								of 1 PCI clock cycle
+**								When the timer expires (i.e., equals 00h)
+**								bridge relinquishes the bus at the next ADB.
+**								(Except in the case where MLT expires within 3 data phases of
+**								an ADB.In this case bridge continues on until it
+**								reaches the next ADB before relinquishing the bus.)
+**==============================================================================
+**==============================================================================
+**  0x0e : (header type,single function )
+** Bit		Default					Description
+** 07		0						Multi-function device (MVD): 80331 is a single-function device.
+** 06:00	01h						Header Type (HTYPE): Defines the layout of addresses 10h
+**								through 3Fh in configuration space.
+**								Returns 01h when read indicating that the register layout
+**								conforms to the standard PCI-to-PCI bridge layout.
+**==============================================================================
+**==============================================================================
+**     0x0f   :
+**==============================================================================
+**==============================================================================
+**  0x13-0x10 :
+**  PCI CFG Base Address #0 (0x10)
+**==============================================================================
+**==============================================================================
+**  0x17-0x14 :
+**  PCI CFG Base Address #1 (0x14)
+**==============================================================================
+**==============================================================================
+**  0x1b-0x18 :
+**  PCI CFG Base Address #2 (0x18)
+**-----------------0x1A,0x19,0x18--Bus Number Register - BNR
+** Bit		Default					Description
+** 23:16	00h						Subordinate Bus Number (SBBN): Indicates the highest PCI
+**								bus number below this bridge.
+**								Any Type 1 configuration cycle on the primary bus
+**								whose bus number is greater than the secondary bus number,
+**								and less than or equal to the subordinate bus number is
+**								forwarded unaltered as a Type 1 configuration cycle on
+**								the secondary PCI bus.
+** 15:08	00h						Secondary Bus Number (SCBN): Indicates the bus number of PCI
+**								to which the secondary interface is connected.
+**								Any Type 1 configuration cycle matching this bus number
+**								is translated to a Type 0 configuration cycle
+**								(or a Special Cycle) before being executed on bridge's
+**								secondary PCI bus.
+** 07:00	00h						Primary Bus Number (PBN): Indicates bridge primary bus number.
+**								Any Type 1 configuration cycle on the primary interface
+**								with a bus number that is less than the contents
+**								of this register field does not be claimed by bridge.
+**-----------------0x1B--Secondary Latency Timer Register - SLTR
+** Bit		Default					Description
+**								Secondary Latency Timer (STV):
+** 07:00	00h			(Conventional PCI) Conventional PCI Mode: Secondary bus Master latency timer.
+**								Indicates the number of PCI clock cycles,referenced from
+**								the assertion of FRAME# to the expiration of the timer,
+**								when bridge may continue as master of the current transaction.
+**								All bits are writable,
+**								resulting in a granularity of 1 PCI clock cycle.
+**								When the timer expires (i.e., equals 00h) bridge relinquishes
+**								the bus after the first data transfer when its PCI bus grant
+**								has been deasserted.
+**					or 40h (PCI-X)     PCI-X Mode: Secondary bus Master latency timer.
+**								Indicates the number of PCI clock cycles,referenced from
+**								the assertion of FRAME# to the expiration of the timer,
+**								when bridge may continue as master of the current transaction.
+**								All bits are writable,
+**								resulting in a granularity of 1 PCI clock cycle.
+**								When the timer expires (i.e., equals 00h) bridge relinquishes
+**								the bus at the next ADB.
+**								(Except in the case where MLT expires within 3 data phases
+**								of an ADB. In this case bridge continues on until it reaches
+**								the next ADB before relinquishing the bus)
+**==============================================================================
+**==============================================================================
+**  0x1f-0x1c :
+**  PCI CFG Base Address #3 (0x1C)
+**-----------------0x1D,0x1C--I/O Base and Limit Register - IOBL
+** Bit		Default					Description
+** 15:12	0h						I/O Limit Address Bits [15:12]: Defines the top address
+**								of an address range to determine when to forward I/O
+**								transactions from one interface to the other.
+**								These bits correspond to address lines 15:12 for 4KB alignment.
+**								Bits 11:0 are assumed to be FFFh.
+** 11:08	1h						I/O Limit Addressing Capability: This field is hard-wired
+**								to 1h, indicating support 32-bit I/O addressing.
+** 07:04	0h						I/O Base Address Bits [15:12]: Defines the bottom address
+**								of an address range to determine when to forward I/O
+**								transactions from one interface to the other.
+**								These bits correspond to address lines 15:12 for 4KB alignment.
+**								Bits 11:0 are assumed to be 000h.
+** 03:00	1h						I/O Base Addressing Capability: This is hard-wired to 1h,
+**								indicating support for 32-bit I/O addressing.
+**-----------------0x1F,0x1E--Secondary Status Register - SSR
+** Bit		Default					Description
+** 15		0b						Detected Parity Error: The bridge sets this bit to a 1b
+**								whenever it detects an address, attribute or data parity error
+**								on its secondary interface.
+** 14		0b						Received System Error: The bridge sets this bit when it
+**								samples SERR# asserted on its secondary bus interface.
+** 13		0b						Received Master Abort: The bridge sets this bit to a 1b when,
+**								acting as the initiator on the secondary bus,
+**								it's transaction (with the exception of special cycles) has
+**								been terminated with a Master Abort.
+** 12		0b						Received Target Abort: The bridge sets this bit to a 1b when,
+**								acting as the initiator on the secondary bus, it's transaction
+**								has been terminated with a Target Abort.
+** 11		0b						Signaled Target Abort: The bridge sets this bit to a 1b when it,
+**								as the target of a transaction, terminates it with a Target Abort.
+**								In PCI-X mode this bit is also set when it forwards a SCM
+**								with a target abort error code.
+** 10:09	01b						DEVSEL# Timing: Indicates slowest response to a
+**								non-configuration command on the secondary interface.
+**								Returns 01b when read, indicating that bridge responds
+**								no slower than with medium timing.
+** 08		0b						Master Data Parity Error: The bridge sets this bit to a 1b
+**								when all of the following conditions are true:
+**								The bridge is the current master on the secondary bus
+**								S_PERR# is detected asserted or is asserted by bridge
+**								The Parity Error Response bit is set in the Command register
+** 07		1b						Fast Back-to-Back Capable (FBC): Indicates that the
+**								secondary interface of bridge can receive fast back-to-back cycles.
+** 06		0b						Reserved
+** 05		1b						66 MHz Capable (C66): Indicates the secondary interface
+**								of the bridge is 66 MHz capable.
+** 04:00	00h						Reserved
+**==============================================================================
+**==============================================================================
+**  0x23-0x20 :
+**  PCI CFG Base Address #4 (0x20)
+**-----------------0x23,0x22,0x21,0x20--Memory Base and Limit Register - MBL
+** Bit		Default					Description
+** 31:20	000h						Memory Limit: These 12 bits are compared with P_AD[31:20]
+**								of the incoming address to determine
+**								the upper 1MB aligned value (exclusive) of the range.
+**								The incoming address must be less than or equal to this value.
+**								For the purposes of address decoding the lower 20 address
+**								bits (P_AD[19:0] are assumed to be F FFFFh.
+** 19:16	0h						Reserved.
+** 15:04	000h						Memory Base: These 12 bits are compared with bits P_AD[31:20]
+**								of the incoming address to determine the lower
+**								1MB aligned value (inclusive) of the range.
+**								The incoming address must be greater than or equal to this value.
+**								For the purposes of address decoding the lower 20 address bits
+**								(P_AD[19:0]) are assumed to be 0 0000h.
+** 03:00	0h						Reserved.
+**==============================================================================
+**==============================================================================
+**  0x27-0x24 :
+**  PCI CFG Base Address #5 (0x24)
+**-----------------0x27,0x26,0x25,0x24--Prefetchable Memory Base and Limit Register - PMBL
+** Bit		Default					Description
+** 31:20	000h						Prefetchable Memory Limit: These 12 bits are compared
+**								with P_AD[31:20] of the incoming address to determine
+**								the upper 1MB aligned value (exclusive) of the range.
+**								The incoming address must be less than or equal to this value.
+**								For the purposes of address decoding the lower 20 address
+**								bits (P_AD[19:0] are assumed to be F FFFFh.
+** 19:16	1h						64-bit Indicator: Indicates that 64-bit addressing is supported.
+** 15:04	000h						Prefetchable Memory Base: These 12 bits are compared
+**								with bits P_AD[31:20] of the incoming address to determine
+**								the lower 1MB aligned value (inclusive) of the range.
+**								The incoming address must be greater than or equal to this value.
+**								For the purposes of address decoding the lower 20 address bits
+**								(P_AD[19:0]) are assumed to be 0 0000h.
+** 03:00	1h						64-bit Indicator: Indicates that 64-bit addressing is supported.
+**==============================================================================
+**==============================================================================
+**  0x2b-0x28 :
+** Bit		Default					Description
+** 31:00    00000000h					Prefetchable Memory Base Upper Portion: All bits are read/writable
+**								bridge supports full 64-bit addressing.
+**==============================================================================
+**==============================================================================
+**  0x2f-0x2c :
+** Bit		Default					Description
+** 31:00	00000000h					Prefetchable Memory Limit Upper Portion: All bits are read/writable
+**								bridge supports full 64-bit addressing.
+**==============================================================================
+**==============================================================================
+**  0x33-0x30 :
+** Bit		Default					Description
+** 07:00	DCh						Capabilities Pointer: Pointer to the first CAP ID entry
+**								in the capabilities list is at DCh in PCI configuration
+**								space. (Power Management Capability Registers)
+**==============================================================================
+**==============================================================================
+**  0x3b-0x35 : reserved
+**==============================================================================
+**==============================================================================
+**  0x3d-0x3c :
+** Bit		Default					Description
+** 15:08	00h						Interrupt Pin (PIN): Bridges do not support the generation
+**								of interrupts.
+** 07:00	00h						Interrupt Line (LINE): The bridge does not generate interrupts,
+**								so this is reserved as '00h'.
+**==============================================================================
+**==============================================================================
+**  0x3f-0x3e :
+** Bit		Default					Description
+** 15:12	0h						Reserved
+** 11		0b						Discard Timer SERR# Enable: Controls the generation of SERR#
+**								on the primary interface (P_SERR#) in response
+**								to a timer discard on either the primary or secondary interface.
+**										0b=SERR# is not asserted.
+**										1b=SERR# is asserted.
+** 10		0b						Discard Timer Status (DTS): This bit is set to a '1b' when either
+**								the primary or secondary discard timer expires.
+**								The delayed completion is then discarded.
+** 09		0b						Secondary Discard Timer (SDT): Sets the maximum number of PCI
+**								clock cycles that bridge waits for an initiator on the secondary
+**								bus to repeat a delayed transaction request.
+**								The counter starts when the delayed transaction completion
+**								is ready to be returned to the initiator.
+**								When the initiator has not repeated the transaction
+**								at least once before the counter expires,bridge discards
+**								the delayed transaction from its queues.
+**									0b=The secondary master time-out counter
+**										is 2 15 PCI clock cycles.
+**									1b=The secondary master time-out counter
+**										is 2 10 PCI clock cycles.
+** 08		0b						Primary Discard Timer (PDT): Sets the maximum number
+**								of PCI clock cycles that bridge waits for an initiator
+**								on the primary bus to repeat a delayed transaction request.
+**								The counter starts when the delayed transaction completion
+**								is ready to be returned to the initiator.
+**								When the initiator has not repeated the transaction at least
+**								once before the counter expires, bridge discards the
+**								delayed transaction from its queues.
+**									0b=The primary master time-out counter
+**											is 2 15 PCI clock cycles.
+**									1b=The primary master time-out counter
+**											is 2 10 PCI clock cycles.
+** 07		0b						Fast Back-to-Back Enable (FBE): The bridge does not initiate back
+**								to back transactions.
+** 06		0b						Secondary Bus Reset (SBR):
+**									When cleared to 0b: The bridge deasserts S_RST#,
+**										when it had been asserted by writing this bit to a 1b.
+** 									When set to 1b: The bridge asserts S_RST#.
+** 05		0b						Master Abort Mode (MAM): Dictates bridge behavior on the
+**								initiator bus when a master abort termination occurs
+**								in response to a delayed transaction initiated by bridge
+**								on the target bus.
+**									0b=The bridge asserts TRDY# in response to a non-locked
+**										delayed transaction,and returns FFFF FFFFh when a read.
+**									1b=When the transaction had not yet been completed
+**										on the initiator bus (e.g.,delayed reads,
+**										or non-posted writes),
+**										then bridge returns a Target Abort in response
+**										to the original requester
+**										when it returns looking for its delayed completion
+**										on the initiator bus.
+**										When the transaction had completed on the initiator
+**										bus (e.g., a PMW), then bridge asserts P_SERR#
+**										(when enabled).
+**										For PCI-X transactions this bit is an enable
+**										for the assertion of P_SERR# due to a master abort
+**										while attempting to deliver a posted memory write
+**										on the destination bus.
+** 04		0b						VGA Alias Filter Enable: This bit dictates bridge behavior
+**								in conjunction with the VGA enable bit (also of this register),
+**								and the VGA Palette Snoop Enable bit (Command Register).
+**								When the VGA enable, or VGA Palette Snoop enable bits are on
+**								(i.e., 1b) the VGA Aliasing bit for the corresponding
+**								enabled functionality,:
+**									0b=Ignores address bits AD[15:10] when decoding
+**										VGA I/O addresses.
+**									1b=Ensures that address bits AD[15:10] equal 000000b
+**								when decoding VGA I/O addresses.
+**								When all VGA cycle forwarding is disabled,
+**								(i.e., VGA Enable bit =0b and VGA Palette Snoop bit =0b),
+**								then this bit has no impact on bridge behavior.
+** 03		0b						VGA Enable: Setting this bit enables address decoding
+**								and transaction forwarding of the following VGA transactions
+**								from the primary bus to the secondary bus:
+**								frame buffer memory addresses 000A0000h:000BFFFFh,
+**								VGA I/O addresses 3B0:3BBh and 3C0h:3DFh, where AD[31:16]=0000h
+**								and AD[15:10] are either not decoded (i.e., don't cares),
+**								or must be 000000b
+**								depending upon the state of the VGA Alias Filter Enable bit.
+**								(bit(4) of this register)
+**								I/O and Memory Enable bits must be set in the Command register
+**								to enable forwarding of VGA cycles.
+** 02		0b						ISA Enable: Setting this bit enables special handling
+**								for the forwarding of ISA I/O transactions that fall
+**								within the address range specified by the I/O Base
+**								and Limit registers, and are within the lowest 64Kbyte
+**								of the I/O address map (i.e., 0000 0000h - 0000 FFFFh).
+**									0b=All I/O transactions that fall within the I/O Base
+**										and Limit registers' specified range are forwarded
+**										from primary to secondary unfiltered.
+**									1b=Blocks the forwarding from primary to secondary
+**								of the top 768 bytes of each 1Kbyte alias. On the secondary
+**								the top 768 bytes of each 1K alias are inversely decoded
+**								and forwarded from secondary to primary.
+** 01		0b						SERR# Forward Enable:
+**									0b=The bridge does not assert P_SERR#
+**										as a result of an S_SERR# assertion.
+**									1b=The bridge asserts P_SERR# whenever S_SERR#
+**										is detected asserted provided the SERR# Enable bit
+**										is set (PCI Command Register bit(8)=1b).
+** 00		0b						Parity Error Response: This bit controls bridge response
+**								to a parity error that is detected on its secondary interface.
+**									0b=When a data parity error is detected bridge
+**										does not assert S_PERR#.
+**										Also bridge does not assert P_SERR# in response
+**										to a detected address or attribute parity error.
+**									1b=When a data parity error is detected bridge
+**										asserts S_PERR#. The bridge also asserts P_SERR#
+**										(when enabled globally via bit(8) of the Command
+**										register) in response to a detected address
+**										or attribute parity error.
+**==============================================================================
+**                  Device Specific Registers 40-A7h
+** ----------------------------------------------------------------------------------------------------------
+** |    Byte 3              |         Byte 2         |        Byte 1          |       Byte 0              | Offset
+** ----------------------------------------------------------------------------------------------------------
+** |    Bridge Control 0    |             Arbiter Control/Status              |      Reserved             | 40h
+** ----------------------------------------------------------------------------------------------------------
+** |                 Bridge Control 2                |                 Bridge Control 1                   | 44h
+** ----------------------------------------------------------------------------------------------------------
+** |                    Reserved                     |                 Bridge Status                      | 48h
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 4Ch
+** ----------------------------------------------------------------------------------------------------------
+** |                 Prefetch Policy                 |               Multi-Transaction Timer              | 50h
+** ----------------------------------------------------------------------------------------------------------
+** |       Reserved         |      Pre-boot Status   |             P_SERR# Assertion Control              | 54h
+** ----------------------------------------------------------------------------------------------------------
+** |       Reserved         |        Reserved        |             Secondary Decode Enable                | 58h
+** ----------------------------------------------------------------------------------------------------------
+** |                    Reserved                     |                 Secondary IDSEL                    | 5Ch
+** ----------------------------------------------------------------------------------------------------------
+** |                                              Reserved                                                | 5Ch
+** ----------------------------------------------------------------------------------------------------------
+** |                                              Reserved                                                | 68h:CBh
+** ----------------------------------------------------------------------------------------------------------
+**==============================================================================
+**  0x42-0x41: Secondary Arbiter Control/Status Register - SACSR
+** Bit		Default					Description
+** 15:12	1111b						Grant Time-out Violator: This field indicates the agent
+**								that violated the Grant Time-out rule (PCI=16 clocks,PCI-X=6 clocks)
+**								Note that this field is only meaningful when:
+**								# Bit[11] of this register is set to 1b, indicating
+**									that a Grant Time-out violation had occurred.
+**								# bridge internal arbiter is enabled.
+**								Bits[15:12] Violating Agent (REQ#/GNT# pair number)
+**								0000b REQ#/GNT#[0]
+**								0001b REQ#/GNT#[1]
+**								0010b REQ#/GNT#[2]
+**								0011b REQ#/GNT#[3]
+**								1111b Default Value (no violation detected)
+**								When bit[11] is cleared by software, this field reverts back
+**								to its default value. All other values are Reserved
+** 11		0b						Grant Time-out Occurred: When set to 1b,
+**								this indicates that a Grant Time-out error had occurred
+**								involving one of the secondary bus agents.
+**								Software clears this bit by writing a 1b to it.
+** 10		0b						Bus Parking Control: 0=During bus idle, bridge parks the bus
+**								on the last master to use the bus.
+**									1=During bus idle, bridge parks the bus on itself.
+**								The bus grant is removed from the last master and internally
+**								asserted to bridge.
+** 09:08	00b						Reserved
+** 07:00	0000 0000b					Secondary Bus Arbiter Priority Configuration:
+**								The bridge secondary arbiter provides two rings of arbitration
+**								priority. Each bit of this field assigns its corresponding secondary
+**								bus master to either the high priority arbiter ring (1b)
+**								or to the low priority arbiter ring (0b).
+**								Bits [3:0] correspond to request inputs S_REQ#[3:0], respectively.
+**								Bit [6] corresponds to the bridge internal secondary bus request
+**								while Bit [7] corresponds to the SATU secondary bus request.
+**								Bits [5:4] are unused.
+**									0b=Indicates that the master belongs to the low priority group.
+**									1b=Indicates that the master belongs to the high priority group
+**=================================================================================
+**  0x43: Bridge Control Register 0 - BCR0
+** Bit		Default					Description
+** 07		0b						Fully Dynamic Queue Mode: 0=The number of Posted write
+**								transactions is limited to eight and the Posted Write data is
+**								limited to 4KB.
+**									1=Operation in fully dynamic queue mode.
+**								The bridge enqueues up to 14 Posted Memory Write transactions
+**								and 8KB of posted write data.
+** 06:03	0H						Reserved.
+** 02		0b						Upstream Prefetch Disable: This bit disables bridge ability
+**								to perform upstream prefetch operations for Memory Read
+**								requests received on its secondary interface.
+**								This bit also controls the bridge's ability to generate advanced
+**								read commands when forwarding a Memory Read Block transaction
+**								request upstream from a PCI-X bus to a Conventional PCI bus.
+**									0b=bridge treats all upstream Memory Read requests as though
+**										they target prefetchable memory.
+**										The use of Memory Read Line and Memory Read
+**								Multiple is enabled when forwarding a PCI-X Memory Read
+**								Block request to an upstream bus operating in Conventional PCI mode.
+**									1b=bridge treats upstream PCI Memory Read requests as though
+**										they target non-prefetchable memory and forwards
+**										upstream PCI-X Memory Read Block commands as Memory Read
+**										when the primary bus is operating in Conventional
+**										PCI mode.
+**	NOTE: This bit does not affect bridge ability to perform read prefetching
+**		when the received command is Memory Read Line or Memory Read Multiple.
+**=================================================================================
+**  0x45-0x44: Bridge Control Register 1 - BCR1 (Sheet 2 of 2)
+** Bit		Default					Description
+** 15:08	0000000b					Reserved
+** 07:06	00b						Alias Command Mapping: This two bit field determines how bridge
+**								handles PCI-X Alias commands, specifically the Alias to Memory Read
+**								Block and Alias to Memory Write Block commands.
+**								The three options for handling these alias commands are to either
+**								pass it as is, re-map to the actual block memory read/write command
+**								encoding, or ignore the transaction forcing a Master Abort to occur
+**								on the Origination Bus.
+**								Bit (7:6) Handling of command
+**								0 0 Re-map to Memory Read/Write Block before forwarding
+**								0 1 Enqueue and forward the alias command code unaltered
+**								1 0 Ignore the transaction, forcing Master Abort
+**								1 1 Reserved
+** 05		1b						Watchdog Timers Disable: Disables or enables all 2 24 Watchdog Timers
+**								in both directions.
+**								The watchdog timers are used to detect prohibitively
+**								long latencies in the system.
+**								The watchdog timer expires
+**								when any Posted Memory Write (PMW), Delayed Request,
+**								or Split Requests (PCI-X mode) is not completed within 2 24 events
+**								(events are defined as PCI Clocks when operating in PCI-X mode,
+**								and as the number of times being
+**								retried when operating in Conventional PCI mode)
+**								0b=All 2 24 watchdog timers are enabled.
+**								1b=All 2 24 watchdog timers are disabled and there is no limits to the number
+**								of attempts bridge makes when initiating a PMW,
+**								transacting a Delayed Transaction,
+**								or how long it waits for a split completion
+**								corresponding to one of its requests.
+** 04            0b                  GRANT# time-out disable: This bit enables/disables the GNT# time-out mechanism.
+**								Grant time-out is 16 clocks for conventional PCI, and 6 clocks for PCI-X.
+**								0b=The Secondary bus arbiter times out an agent that does not assert
+**								FRAME# within 16/6 clocks of receiving its grant, once the bus has gone idle.
+**								The time-out counter begins as soon as
+**								the bus goes idle with the new GNT# asserted.
+**								An infringing agent does not receive a subsequent GNT# until it de-asserts its
+**								REQ# for at least one clock cycle.
+**								1b=GNT# time-out mechanism is disabled.
+** 03           00b                           Reserved.
+** 02            0b          Secondary Discard Timer Disable: This bit enables/disables
+**								bridge secondary delayed transaction discard mechanism.
+**								The time out mechanism is used to ensure that initiators of
+**								delayed transactions return for their delayed completion data/status
+**								within a reasonable amount of time after it is available from bridge.
+**								0b=The secondary master time-out counter is enabled and uses the value specified
+**								by the Secondary Discard Timer bit (see Bridge Control Register).
+**								1b=The secondary master time-out counter is disabled.
+**								The bridge waits indefinitely for
+**								a secondary bus master to repeat a delayed transaction.
+** 01            0b            Primary Discard Timer Disable: This bit
+**								enables/disables bridge primary delayed transaction discard mechanism.
+**								The time out mechanism is used to ensure that initiators of delayed
+**								transactions return for their delayed completion data/status within
+**								a reasonable amount of time after it is available from bridge.
+**								0b=The primary master time-out counter is enabled and uses the
+**								value specified by the Primary Discard Timer bit (see Bridge Control Register).
+**								1b=The secondary master time-out counter is disabled.
+**								The bridge waits indefinitely
+**								for a secondary bus master to repeat a delayed transaction.
+** 00            0b                           Reserved
+**=================================================================================
+**  0x47-0x46: Bridge Control Register 2 - BCR2
+** Bit       Default                       Description
+** 15:07      0000b                          Reserved.
+** 06            0b			 Global Clock Out Disable
+**								(External Secondary Bus Clock Source Enable):
+**								This bit disables all of the secondary
+**								PCI clock outputs including the feedback clock S_CLKOUT.
+**								This means that the user is required to provide an S_CLKIN input source.
+** 05:04        11 (66 MHz)                  Preserved.
+**              01 (100 MHz)
+**              00 (133 MHz)
+** 03:00        Fh (100 MHz & 66 MHz)
+**              7h (133 MHz)
+**					This 4 bit field provides individual enable/disable mask bits for each of bridge
+**					secondary PCI clock outputs. Some, or all secondary clock outputs (S_CLKO[3:0])
+**					default to being enabled following the rising edge of P_RST#, depending on the
+**					frequency of the secondary bus clock:
+**					E Designs with 100 MHz (or lower) Secondary PCI clock power
+**					up with all four S_CLKOs enabled by default.
+**					(SCLKO[3:0])P
+**					E Designs with 133 MHz Secondary PCI clock power up with
+**					the lower order 3 S_CLKOs enabled by default.
+**					(S_CLKO[2:0]) Only those SCLKs that power up enabled
+**					by can be connected to downstream device clock inputs.
+**=================================================================================
+**  0x49-0x48: Bridge Status Register - BSR
+** Bit       Default                       Description
+** 15           0b			Upstream Delayed Transaction Discard Timer Expired: This bit is set to a 1b and P_SERR# is
+**					conditionally asserted when the secondary discard timer expires.
+** 14           0b			Upstream Delayed/Split Read Watchdog Timer Expired:
+**					Conventional PCI Mode: This bit is set to a 1b and P_SERR# is conditionally asserted when
+**					bridge discards an upstream delayed read transaction
+**					request after 2 24 retries following the initial retry.
+**					PCI-X Mode: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted when bridge discards
+**					an upstream split read request after waiting in excess
+**					of 2 24 clocks for the corresponding Split Completion to arrive.
+** 13           0b			Upstream Delayed/Split Write Watchdog Timer Expired:
+**					Conventional PCI Mode: This bit is set to a 1b and P_SERR# is conditionally
+**					asserted when bridge discards an upstream delayed write transaction request after 2 24 retries
+**					following the initial retry.
+**					PCI-X Mode: This bit is set to a 1b and P_SERR# is conditionally asserted when bridge discards
+**					an upstream split write request after
+**					waiting in excess of 2 24 clocks for the corresponding Split Completion to arrive.
+** 12           0b			Master Abort during Upstream Posted Write: This bit is set to a 1b and P_SERR# is conditionally
+**					asserted when a Master Abort occurs as a result of an attempt,
+**					by bridge, to retire a PMW upstream.
+** 11           0b			Target Abort during Upstream Posted Write: This bit is set to a 1b and P_SERR# is conditionally
+**					asserted when a Target Abort occurs as a result of an attempt, by bridge, to retire a PMW upstream.
+** 10           0b			Upstream Posted Write Data Discarded: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted
+**					when bridge discards an upstream PMW transaction
+**					after receiving 2 24 target retries from the primary bus target
+** 09           0b			Upstream Posted Write Data Parity Error: This bit is set to a 1b and P_SERR# is conditionally
+**					asserted when a data parity error is detected by bridge while attempting to retire a PMW upstream
+** 08           0b			Secondary Bus Address Parity Error: This bit is set to a 1b and P_SERR# is conditionally asserted
+**					when bridge detects an address parity error on the secondary bus.
+** 07           0b			Downstream Delayed Transaction Discard Timer Expired:
+**					This bit is set to a 1b and P_SERR# is conditionally
+**					asserted when the primary bus discard timer expires.
+** 06           0b			Downstream Delayed/Split Read Watchdog Timer Expired:
+**					Conventional PCI Mode: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted when bridge discards
+**					a downstream delayed read transaction request
+**					after receiving 2 24 target retries from the secondary bus target.
+**					PCI-X Mode: This bit is set to a 1b and P_SERR# is conditionally asserted
+**					when bridge discards a downstream split read request after waiting in excess of 2 24 clocks
+**					for the corresponding Split Completion to arrive.
+** 05           0b			Downstream Delayed Write/Split Watchdog Timer Expired:
+**					Conventional PCI Mode: This bit is set to a 1b
+**					and P_SERR# is conditionally asserted when bridge discards
+**					a downstream delayed write transaction request
+**					after receiving 2 24 target retries from the secondary bus target.
+**					PCI-X Mode: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted when bridge discards
+**					a downstream split write request after waiting in excess
+**					of 2 24 clocks for the corresponding Split Completion to arrive.
+** 04           0b			Master Abort during Downstream Posted Write: This bit is set to
+**					a 1b and P_SERR# is conditionally asserted
+**					when a Master Abort occurs as a result of an attempt, by bridge, to retire a PMW downstream.
+** 03           0b			Target Abort during Downstream Posted Write: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted when a Target
+**					Abort occurs as a result of an attempt, by bridge, to retire a PMW downstream.
+** 02           0b			Downstream Posted Write Data Discarded: This bit is set
+**					to a 1b and P_SERR# is conditionally asserted when bridge
+**					discards a downstream PMW transaction after receiving 2 24 target
+**					retries from the secondary bus target
+** 01           0b			Downstream Posted Write Data Parity Error: This bit is set to a 1b and P_SERR#
+**					is conditionally asserted when a data parity error is
+**					detected by bridge while attempting to retire a PMW downstream.
+** 00           0b			Primary Bus Address Parity Error: This bit is set to a 1b and P_SERR# is conditionally asserted
+**					when bridge detects an address parity error on the primary bus.
+**==================================================================================
+**  0x51-0x50: Bridge Multi-Transaction Timer Register - BMTTR
+** Bit       Default                       Description
+** 15:13       000b			Reserved
+** 12:10       000b			GRANT# Duration: This field specifies the count (PCI clocks) that a secondary bus master
+**					has its grant maintained in order to enable multiple
+**					transactions to execute within the same arbitration cycle.
+**					Bit[02:00] GNT# Extended Duration
+**					000 MTT Disabled (Default=no GNT# extension)
+**					001 16 clocks
+**					010 32 clocks
+**					011 64 clocks
+**					100 128 clocks
+**					101 256 clocks
+**					110 Invalid (treated as 000)
+**					111 Invalid (treated as 000)
+** 09:08        00b			Reserved
+** 07:00        FFh			MTT Mask: This field enables/disables MTT usage for each REQ#/GNT#
+**					pair supported by bridge secondary arbiter.
+**					Bit(7) corresponds to SATU internal REQ#/GNT# pair,
+**					bit(6) corresponds to bridge internal REQ#/GNT# pair,
+**					bit(5) corresponds to REQ#/GNT#(5) pair, etc.
+**					When a given bit is set to 1b, its corresponding REQ#/GNT#
+**					pair is enabled for MTT functionality as determined
+**					by bits(12:10) of this register.
+**					When a given bit is cleared to 0b, its corresponding REQ#/GNT# pair is disabled from using the MTT.
+**==================================================================================
+**  0x53-0x52: Read Prefetch Policy Register - RPPR
+** Bit       Default                       Description
+** 15:13       000b			ReRead_Primary Bus: 3-bit field indicating the multiplication factor to be used in calculating
+**					the number of bytes to prefetch from the secondary bus interface on subsequent PreFetch operations
+**					given that the read demands were not satisfied using the FirstRead parameter.
+**					The default value of 000b correlates to: Command Type Hardwired pre-fetch amount Memory
+**					Read 4 DWORDs Memory Read Line 1 cache lines Memory Read Multiple 2 cache lines
+** 12:10       000b			FirstRead_Primary Bus: 3-bit field indicating the multiplication factor to be used in calculating
+**					the number of bytes to prefetch from the secondary bus interface on the initial PreFetch operation.
+**					The default value of 000b correlates to: Command Type Hardwired pre-fetch amount Memory
+**					Read 4 DWORDs Memory Read Line 1 cache line Memory Read Multiple 2 cache lines
+** 09:07       010b			ReRead_Secondary Bus: 3-bit field indicating the multiplication factor to be used in calculating
+**					the number of bytes to prefetch from the primary bus interface on subsequent PreFetch operations
+**					given that the read demands were not satisfied using the FirstRead parameter.
+**					The default value of 010b correlates to: Command Type Hardwired pre-fetch amount
+**					Memory Read 3 cache lines Memory Read Line 3 cache lines Memory Read Multiple 6 cache lines
+** 06:04       000b			FirstRead_Secondary Bus: 3-bit field indicating the multiplication factor to be used in
+**					calculating the number of bytes to prefetch from the
+**					primary bus interface on the initial PreFetch operation.
+**					The default value of 000b correlates to: Command Type Hardwired pre-fetch amount
+**					Memory Read 4 DWORDs Memory Read Line 1 cache line Memory Read Multiple 2 cache lines
+** 03:00      1111b			Staged Prefetch Enable: This field enables/disables the FirstRead/ReRead
+**					pre-fetch algorithm for the secondary and the primary bus interfaces.
+**					Bit(3) is a ganged enable bit for REQ#/GNT#[7:3], and bits(2:0) provide individual
+**					enable bits for REQ#/GNT#[2:0]. (bit(2) is the enable bit for REQ#/GNT#[2], etc...)
+**						1b: enables the staged pre-fetch feature
+**						0b: disables staged pre-fetch,
+**						and hardwires read pre-fetch policy to the following for
+**						Memory Read,
+**						Memory Read Line,
+**						and Memory Read Multiple commands:
+**						Command Type Hardwired Pre-Fetch Amount...
+**					Memory Read 4 DWORDs
+**					Memory Read Line 1 cache line
+**					Memory Read Multiple 2 cache lines
+**	NOTE: When the starting address is not cache line aligned, bridge pre-fetches Memory Read line commands only to the
+**		next higher cache line boundary.For non-cache line aligned Memory Read Multiple commands bridge
+**		pre-fetches only to the second cache line boundary encountered.
+**==================================================================================
+**  0x55-0x54: P_SERR# Assertion Control - SERR_CTL
+** Bit       Default                       Description
+**  15          0b			Upstream Delayed Transaction Discard Timer Expired:
+**					Dictates the bridge behavior in response to its discarding
+**					of a delayed transaction that was initiated from the primary bus.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  14          0b			Upstream Delayed/Split Read Watchdog Timer Expired: Dictates bridge behavior following
+**					expiration of the subject watchdog timer.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  13          0b			Upstream Delayed/Split Write Watchdog Timer Expired: Dictates bridge behavior following
+**					expiration of the subject watchdog timer.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  12          0b			Master Abort during Upstream Posted Write: Dictates bridge behavior following its having detected
+**					a Master Abort while attempting to retire one of its PMWs upstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  11          0b			Target Abort during Upstream Posted Write: Dictates bridge behavior following
+**					its having been terminated with Target Abort while attempting to retire one of its PMWs upstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  10          0b			Upstream Posted Write Data Discarded: Dictates bridge behavior in the event
+**					that it discards an upstream posted write transaction.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  09          0b			Upstream Posted Write Data Parity Error: Dictates bridge behavior when a data parity error
+**					is detected while attempting to retire on of its PMWs upstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  08          0b			Secondary Bus Address Parity Error: This bit dictates bridge behavior when
+**					it detects an address parity error on the secondary bus.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  07          0b			Downstream Delayed Transaction Discard Timer Expired: Dictates bridge behavior
+**					in response to its discarding of a delayed transaction that was initiated on the secondary bus.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  06          0b			Downstream Delayed/Split Read Watchdog Timer Expired: Dictates bridge
+**					behavior following expiration of the subject watchdog timer.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  05          0b			Downstream Delayed/Split Write Watchdog Timer Expired: Dictates bridge behavior
+**					following expiration of the subject watchdog timer.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  04          0b			Master Abort during Downstream Posted Write: Dictates bridge behavior following
+**					its having detected a Master Abort while attempting to retire one of its PMWs downstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  03          0b			Target Abort during Downstream Posted Write: Dictates bridge behavior
+**					following its having been terminated with Target Abort
+**					while attempting to retire one of its PMWs downstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  02          0b			Downstream Posted Write Data Discarded: Dictates bridge behavior in the event
+**					that it discards a downstream posted write transaction.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  01          0b			Downstream Posted Write Data Parity Error: Dictates bridge behavior when a data parity error
+**					is detected while attempting to retire on of its PMWs downstream.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**  00          0b			Primary Bus Address Parity Error: This bit dictates bridge behavior when it detects an
+**					address parity error on the primary bus.
+**					0b=bridge asserts P_SERR#.
+**					1b=bridge does not assert P_SERR#
+**===============================================================================
+**  0x56: Pre-Boot Status Register - PBSR
+** Bit       Default							Description
+** 07           1							 Reserved
+** 06           -							 Reserved - value indeterminate
+** 05:02        0							 Reserved
+** 01      Varies with External State of S_133EN at PCI Bus Reset
+**									Secondary Bus Max Frequency Setting: This bit reflect captured S_133EN strap,
+**									indicating the maximum secondary bus clock frequency when in PCI-X mode.
+**									Max Allowable Secondary Bus Frequency
+**									S_133EN PCI-X Mode
+**									0 100 MHz
+**									1 133 MH
+** 00          0b							Reserved
+**===============================================================================
+**  0x59-0x58: Secondary Decode Enable Register - SDER
+** Bit       Default							Description
+** 15:03      FFF1h							 Preserved.
+** 02     Varies with External State of PRIVMEM at PCI Bus Reset	Private Memory Space Enable - when set,
+**									bridge overrides its secondary inverse decode logic and not
+**									forward upstream any secondary bus initiated
+**									DAC Memory transactions with AD(63)=1b.
+**									This creates a private memory space on the Secondary PCI bus
+**									that allows peer-to-peer transactions.
+** 01:00      10 2							Preserved.
+**===============================================================================
+**  0x5D-0x5C: Secondary IDSEL Select Register - SISR
+** Bit       Default							Description
+** 15:10     000000 2							Reserved.
+** 09    Varies with External State of PRIVDEV at PCI Bus Reset		AD25- IDSEL Disable -
+**									When this bit is set, AD25 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD25 is asserted when Primary addresses
+**									AD[15:11]=01001 2 during a Type 1 to Type 0 conversion.
+** 08    Varies with External State of PRIVDEV at PCI Bus Reset		AD24- IDSEL Disable -
+**									When this bit is set, AD24 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD24 is asserted when Primary addresses
+**									AD[15:11]=01000 2 during a Type 1 to Type 0 conversion.
+** 07    Varies with External State of PRIVDEV at PCI Bus Reset		AD23- IDSEL Disable -
+**									When this bit is set, AD23 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD23 is asserted
+**									when Primary addresses AD[15:11]=00111 2 during a Type 1 to Type 0 conversion.
+** 06    Varies with External State of PRIVDEV at PCI Bus Reset		AD22- IDSEL Disable -
+**									When this bit is set, AD22 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD22 is asserted
+**									when Primary addresses AD[15:11]=00110 2 during a Type 1 to Type 0 conversion.
+** 05    Varies with External State of PRIVDEV at PCI Bus Reset		AD21- IDSEL Disable -
+**									When this bit is set, AD21 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD21 is asserted when Primary addresses
+**									AD[15:11]=00101 2 during a Type 1 to Type 0 conversion.
+** 04    Varies with External State of PRIVDEV at PCI Bus Reset		AD20- IDSEL Disable -
+**									When this bit is set, AD20 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD20 is asserted when Primary addresses
+**									AD[15:11]=00100 2 during a Type 1 to Type 0 conversion.
+** 03    Varies with External State of PRIVDEV at PCI Bus Reset		AD19- IDSEL Disable -
+**									When this bit is set, AD19 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD19 is asserted when Primary addresses
+**									AD[15:11]=00011 2 during a Type 1 to Type 0 conversion.
+** 02    Varies with External State of PRIVDEV at PCI Bus Reset		AD18- IDSEL Disable -
+**									When this bit is set, AD18 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD18 is asserted when Primary addresses
+**									AD[15:11]=00010 2 during a Type 1 to Type 0 conversion.
+** 01    Varies with External State of PRIVDEV at PCI Bus Reset		AD17- IDSEL Disable - When this bit is set, AD17 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD17 is asserted when Primary addresses
+**									AD[15:11]=00001 2 during a Type 1 to Type 0 conversion.
+** 00    Varies with External State of PRIVDEV at PCI Bus Reset		AD16- IDSEL Disable - When this bit is set, AD16 is deasserted
+**									for any possible Type 1 to Type 0 conversion.
+**									When this bit is clear, AD16 is asserted when Primary addresses
+**									AD[15:11]=00000 2 during a Type 1 to Type 0 conversion.
+**************************************************************************
+**************************************************************************
+**                 Reserved      A8-CBh
+**************************************************************************
+**************************************************************************
+**                  PCI Extended Enhanced Capabilities List CC-FFh
+**************************************************************************
+** ----------------------------------------------------------------------------------------------------------
+** |    Byte 3              |         Byte 2         |        Byte 1          |       Byte 0              | Configu-ration Byte Offset
+** ----------------------------------------------------------------------------------------------------------
+** |           Power Management Capabilities         |        Next Item Ptr   |     Capability ID         | DCh
+** ----------------------------------------------------------------------------------------------------------
+** |        PM Data         |       PPB Support      |            Extensions Power Management CSR         | E0h
+** ----------------------------------------------------------------------------------------------------------
+** |                    Reserved                     |        Reserved        |        Reserved           | E4h
+** ----------------------------------------------------------------------------------------------------------
+** |                                              Reserved                                                | E8h
+** ----------------------------------------------------------------------------------------------------------
+** |       Reserved         |        Reserved        |        Reserved        |         Reserved          | ECh
+** ----------------------------------------------------------------------------------------------------------
+** |              PCI-X Secondary Status             |       Next Item Ptr    |       Capability ID       | F0h
+** ----------------------------------------------------------------------------------------------------------
+** |                                         PCI-X Bridge Status                                          | F4h
+** ----------------------------------------------------------------------------------------------------------
+** |                                PCI-X Upstream Split Transaction Control                              | F8h
+** ----------------------------------------------------------------------------------------------------------
+** |                               PCI-X Downstream Split Transaction Control                             | FCh
+** ----------------------------------------------------------------------------------------------------------
+**===============================================================================
+**  0xDC: Power Management Capabilities Identifier - PM_CAPID
+** Bit       Default                       Description
+** 07:00       01h                        Identifier (ID): PCI SIG assigned ID for PCI-PM register block
+**===============================================================================
+**  0xDD: Next Item Pointer - PM_NXTP
+** Bit       Default                       Description
+** 07:00       F0H                Next Capabilities Pointer (PTR): The register defaults to
+**									F0H pointing to the PCI-X Extended Capability Header.
+**===============================================================================
+**  0xDF-0xDE: Power Management Capabilities Register - PMCR
+** Bit       Default                       Description
+** 15:11       00h                     PME Supported (PME): PME# cannot be asserted by bridge.
+** 10           0h                 State D2 Supported (D2): Indicates no support for state D2. No power management action in this state.
+** 09           1h                 State D1 Supported (D1): Indicates support for state D1. No power management action in this state.
+** 08:06        0h                Auxiliary Current (AUXC): This 3 bit field reports the 3.3Vaux
+**									auxiliary current requirements for the PCI function.
+**                                                          This returns 000b as PME# wake-up for bridge is not implemented.
+** 05           0   Special Initialization Required (SINT): Special initialization is not required for bridge.
+** 04:03       00                            Reserved
+** 02:00       010                            Version (VS): Indicates that this supports
+**									PCI Bus Power Management Interface Specification, Revision 1.1.
+**===============================================================================
+**  0xE1-0xE0: Power Management Control / Status - Register - PMCSR
+** Bit       Default                       Description
+** 15:09       00h                          Reserved
+** 08          0b                          PME_Enable: This bit, when set to 1b enables bridge to assert PME#.
+**  Note that bridge never has occasion to assert PME# and implements this dummy R/W bit
+**  							only for the purpose of working around an OS PCI-PM bug.
+** 07:02       00h                          Reserved
+** 01:00       00                Power State (PSTATE): This 2-bit field is used both to determine
+**  the current power state of a function and to set the Function into a new power state.
+**  													00 - D0 state
+**  													01 - D1 state
+**  													10 - D2 state
+**  													11 - D3 hot state
+**===============================================================================
+**  0xE2: Power Management Control / Status PCI to PCI Bridge Support - PMCSR_BSE
+** Bit       Default                       Description
+** 07          0 		Bus Power/Clock Control Enable (BPCC_En): Indicates that
+**				the bus power/clock control policies have been disabled.
+** 06          0		B2/B3 support for D3 Hot (B2_B3#): The state of this bit determines the action
+**				that is to occur as a direct result of programming the function to D3 hot.
+**				This bit is only meaningful when bit 7 (BPCC_En) is a 1.
+** 05:00     00h                            Reserved
+**===============================================================================
+**  0xE3: Power Management Data Register - PMDR
+** Bit       Default                       Description
+** 07:00       00h                          Reserved
+**===============================================================================
+**  0xF0: PCI-X Capabilities Identifier - PX_CAPID
+** Bit       Default                       Description
+** 07:00       07h                       Identifier (ID): Indicates this is a PCI-X capabilities list.
+**===============================================================================
+**  0xF1: Next Item Pointer - PX_NXTP
+** Bit       Default                       Description
+** 07:00       00h			Next Item Pointer: Points to the next capability in
+**					the linked list The power on default value of this
+**					register is 00h indicating that this is the last entry in the linked list of capabilities.
+**===============================================================================
+**  0xF3-0xF2: PCI-X Secondary Status - PX_SSTS
+** Bit       Default                       Description
+** 15:09       00h                          Reserved
+** 08:06       Xxx		Secondary Clock Frequency (SCF): This field is set with the frequency of the secondary bus.
+**									The values are:
+**									BitsMax FrequencyClock Period
+**									000PCI ModeN/A
+**									00166 15
+**									01010010
+**									0111337.5
+**									1xxreservedreserved
+**									The default value for this register is
+**									the operating frequency of the secondary bus
+** 05           0b		Split Request Delayed. (SRD):  This bit is supposed to be set by a bridge
+**				when it cannot forward a transaction on the
+**				secondary bus to the primary bus because there is not enough room within the limit specified in
+**				the Split Transaction Commitment Limit field in the Downstream Split Transaction Control register.
+**				The bridge does not set this bit.
+** 04           0b		Split Completion Overrun (SCO): This bit is supposed to be set when a bridge terminates
+**				a Split Completion on the secondary bus with retry or Disconnect at next ADB because its buffers are full.
+**				The bridge does not set this bit.
+** 03           0b		Unexpected Split Completion (USC): This bit is set when an unexpected split completion
+**				with a requester ID equal to bridge secondary bus number, device number 00h,
+**				and function number 0 is received on the secondary interface. This bit is cleared by software writing a '1'.
+** 02           0b		Split Completion Discarded (SCD): This bit is set when bridge discards a split completion
+**				moving toward the secondary bus because the requester
+**				would not accept it. This bit cleared by software writing a '1'.
+** 01           1b		133 MHz Capable: Indicates that bridge is capable of running its secondary bus at 133 MHz
+** 00           1b		64-bit Device (D64): Indicates the width of the secondary bus as 64-bits.
+**===============================================================================
+**  0xF7-0xF6-0xf5-0xF4: PCI-X Bridge Status - PX_BSTS
+** Bit       Default			Description
+** 31:22        0			Reserved
+** 21           0			Split Request Delayed (SRD): This bit does not be set by bridge.
+** 20           0			Split Completion Overrun (SCO): This bit does not be set by
+**					bridge because bridge throttles traffic
+**					on the completion side.
+** 19           0			Unexpected Split Completion (USC): The bridge sets this bit to 1b when it encounters
+**					a corrupted Split Completion, possibly with an inconsistent remaining byte count.
+**					Software clears this bit by writing a 1b to it.
+** 18           0			Split Completion Discarded (SCD): The bridge sets this bit to 1b
+**					when it has discarded a Split Completion.
+**					Software clears this bit by writing a 1b to it.
+** 17           1			133 MHz Capable: This bit indicates that the bridge
+**					primary interface is capable of 133 MHz operation in PCI-X mode.
+**					0=The maximum operating frequency is 66 MHz.
+**					1=The maximum operating frequency is 133 MHz.
+** 16 Varies with the external state of P_32BITPCI# at PCI Bus Reset    64-bit Device (D64): Indicates bus width
+**					of the Primary PCI bus interface.
+**					0=Primary Interface is connected as a 32-bit PCI bus.
+**					1=Primary Interface is connected as a 64-bit PCI bus.
+** 15:08       00h			Bus Number (BNUM): This field is simply an alias to the PBN field of the BNUM register at offset 18h.
+**					Apparently it was deemed necessary reflect it here for diagnostic purposes.
+** 07:03       1fh			Device Number (DNUM): Indicates which IDSEL bridge consumes. May be updated whenever a PCI-X
+** 					configuration write cycle that targets bridge scores a hit.
+** 02:00        0h			Function Number (FNUM): The bridge Function #
+**===============================================================================
+**  0xFB-0xFA-0xF9-0xF8: PCI-X Upstream Split Transaction Control - PX_USTC
+** Bit       Default                       Description
+** 31:16      003Eh			Split Transaction Limit (STL): This register indicates
+**					the size of the commitment limit in units of ADQs.
+**					Software is permitted to program this register to any value greater than or equal to
+**					the contents of the Split Transaction Capacity register. A value less than the contents
+**					of the Split Transaction Capacity register causes unspecified results.
+**					A value of 003Eh or greater enables the bridge to forward all Split Requests of any
+**					size regardless of the amount of buffer space available.
+** 15:00      003Eh			Split Transaction Capacity (STC): This read-only field
+**					indicates the size of the buffer (number of ADQs) for storing
+**					split completions. This register controls behavior of the bridge buffers for forwarding
+**					Split Transactions from a primary bus requester to a secondary bus completer.
+**					The default value of 003Eh indicates there is available buffer space for 62 ADQs (7936 bytes).
+**===============================================================================
+**  0xFF-0xFE-0xFD-0xFC: PCI-X Downstream Split Transaction Control - PX_DSTC
+** Bit       Default                       Description
+** 31:16      003Eh			Split Transaction Limit (STL):  This register indicates
+**					the size of the commitment limit in units of ADQs.
+**					Software is permitted to program this register to any value greater than or equal to
+**					the contents of the Split Transaction Capacity register. A value less than the contents
+**					of the Split Transaction Capacity register causes unspecified results.
+**					A value of 003Eh or greater enables the bridge to forward all Split Requests of any
+**					size regardless of the amount of buffer space available.
+** 15:00      003Eh              Split Transaction Capacity (STC): This read-only
+**					field indicates the size of the buffer (number of ADQs) for storing
+**					split completions. This register controls behavior of the bridge buffers for forwarding
+**					Split Transactions from a primary bus requester to a secondary bus completer.
+**					The default value of 003Eh indicates there is available buffer space for 62 ADQs (7936 bytes).
+**************************************************************************
+*************************************************************************************************************************************
+**                       80331 Address Translation Unit Register Definitions
+**                               ATU Interface Configuration Header Format
+**               The ATU is programmed via a [Type 0] configuration command on the PCI interface.
+*************************************************************************************************************************************
+** |    Byte 3              |         Byte 2         |        Byte 1          |       Byte 0              | Configuration Byte Offset
+**===================================================================================================================================
+** |                ATU Device ID                    |                     Vendor ID                      | 00h
+** ----------------------------------------------------------------------------------------------------------
+** |                     Status                      |                     Command                        | 04H
+** ----------------------------------------------------------------------------------------------------------
+** |                              ATU Class Code                              |       Revision ID         | 08H
+** ----------------------------------------------------------------------------------------------------------
+** |         ATUBISTR       |     Header Type        |      Latency Timer     |      Cacheline Size       | 0CH
+** ----------------------------------------------------------------------------------------------------------
+** |                                     Inbound ATU Base Address 0                                       | 10H
+** ----------------------------------------------------------------------------------------------------------
+** |                               Inbound ATU Upper Base Address 0                                       | 14H
+** ----------------------------------------------------------------------------------------------------------
+** |                                     Inbound ATU Base Address 1                                       | 18H
+** ----------------------------------------------------------------------------------------------------------
+** |                               Inbound ATU Upper Base Address 1                                       | 1CH
+** ----------------------------------------------------------------------------------------------------------
+** |                                     Inbound ATU Base Address 2                                       | 20H
+** ----------------------------------------------------------------------------------------------------------
+** |                               Inbound ATU Upper Base Address 2                                       | 24H
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 28H
+** ----------------------------------------------------------------------------------------------------------
+** |                ATU Subsystem ID                 |                ATU Subsystem Vendor ID             | 2CH
+** ----------------------------------------------------------------------------------------------------------
+** |                                       Expansion ROM Base Address                                     | 30H
+** ----------------------------------------------------------------------------------------------------------
+** |                                    Reserved Capabilities Pointer                                     | 34H
+** ----------------------------------------------------------------------------------------------------------
+** |                                             Reserved                                                 | 38H
+** ----------------------------------------------------------------------------------------------------------
+** |     Maximum Latency    |     Minimum Grant      |       Interrupt Pin    |      Interrupt Line       | 3CH
+** ----------------------------------------------------------------------------------------------------------
+*********************************************************************************************************************
+***********************************************************************************
+**  ATU Vendor ID Register - ATUVID
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:00      8086H (0x17D3)               ATU Vendor ID - This is a 16-bit value assigned to Intel.
+**					This register, combined with the DID, uniquely identify the PCI device.
+**					Access type is Read/Write to allow the 80331 to configure the register
+**					as a different vendor ID to simulate the interface of a standard
+**					mechanism currently used by existing application software.
+***********************************************************************************
+***********************************************************************************
+**  ATU Device ID Register - ATUDID
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:00      0336H (0x1110)               ATU Device ID - This is a 16-bit value assigned to the ATU. This ID,
+**						combined with the VID, uniquely identify any PCI device.
+***********************************************************************************
+***********************************************************************************
+**  ATU Command Register - ATUCMD
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:11      000000 2                     Reserved
+**  10           0			Interrupt Disable - This bit disables 80331 from asserting the ATU interrupt signal.
+**						0=enables the assertion of interrupt signal.
+**						1=disables the assertion of its interrupt signal.
+**  09          0 2			Fast Back to Back Enable - When cleared, the ATU interface is not allowed
+**					to generate fast back-to-back cycles on its bus. Ignored when operating in the PCI-X mode.
+**  08          0 2			SERR# Enable - When cleared, the ATU interface is not allowed to assert SERR# on the PCI interface.
+**  07          1 2			Address/Data Stepping Control - Address stepping is implemented for configuration transactions. The
+**					ATU inserts 2 clock cycles of address stepping for Conventional Mode
+**					and 4 clock cycles of address stepping for PCI-X mode.
+**  06          0 2			Parity Error Response - When set, the ATU takes normal action when a parity error is detected.
+**					When cleared, parity checking is disabled.
+**  05          0 2			VGA Palette Snoop Enable - The ATU interface does not support I/O writes and therefore,
+**					does not perform VGA palette snooping.
+**  04          0 2			Memory Write and Invalidate Enable - When set, ATU may generate MWI commands.
+**					When clear, ATU use Memory Write commands instead of MWI. Ignored when operating in the PCI-X mode.
+**  03          0 2			Special Cycle Enable - The ATU interface does not respond to special cycle commands in any way.
+**					Not implemented and a reserved bit field.
+**  02          0 2			Bus Master Enable - The ATU interface can act as a master on the PCI bus.
+**					When cleared, disables the device from generating PCI accesses.
+**					When set, allows the device to behave as a PCI bus master.
+**					When operating in the PCI-X mode, ATU initiates a split completion
+**					transaction regardless of the state of this bit.
+**  01          0 2			Memory Enable - Controls the ATU interfaces response to PCI memory addresses.
+**					When cleared, the ATU interface does not respond to any memory access on the PCI bus.
+**  00          0 2			I/O Space Enable - Controls the ATU interface response to I/O transactions.
+**					Not implemented and a reserved bit field.
+***********************************************************************************
+***********************************************************************************
+**  ATU Status Register - ATUSR (Sheet 1 of 2)
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15          0 2			Detected Parity Error - set when a parity error is
+**					detected in data received by the ATU on the PCI bus even
+**					when the ATUCMD registers Parity Error Response bit is cleared. Set under the following conditions:
+**					E Write Data Parity Error when the ATU is a target (inbound write).
+**					E Read Data Parity Error when the ATU is a requester (outbound read).
+**					E Any Address or Attribute (PCI-X Only) Parity Error on the Bus (including one generated by the ATU).
+**  14          0 2			SERR# Asserted - set when SERR# is asserted on the PCI bus by the ATU.
+**  13          0 2			Master Abort - set when a transaction initiated by the ATU PCI master interface, ends in a Master-Abort
+**					or when the ATU receives a Master Abort Split Completion Error Message in PCI-X mode.
+**  12          0 2			Target Abort (master) - set when a transaction
+**					initiated by the ATU PCI master interface, ends in a target
+**					abort or when the ATU receives a Target Abort Split Completion Error Message in PCI-X mode.
+**  11          0 2			Target Abort (target) - set when the ATU interface, acting as a target,
+**					terminates the transaction on the PCI bus with a target abort.
+**  10:09       01 2			DEVSEL# Timing - These bits are read-only and define the slowest
+**					DEVSEL# timing for a target device in Conventional PCI Mode
+**					regardless of the operating mode (except configuration accesses).
+**					00 2=Fast
+**					01 2=Medium
+**					10 2=Slow
+**					11 2=Reserved
+**					The ATU interface uses Medium timing.
+**  08           0 2			Master Parity Error - The ATU interface sets this bit under the following conditions:
+**					E The ATU asserted PERR# itself or the ATU observed PERR# asserted.
+**					E And the ATU acted as the requester for the operation in which the error occurred.
+**					E And the ATUCMD registers Parity Error Response bit is set
+**					E Or (PCI-X Mode Only) the ATU received a Write Data Parity Error Message
+**					E And the ATUCMD registers Parity Error Response bit is set
+**  07           1 2  (Conventional mode)
+**               0 2  (PCI-X mode)
+**					Fast Back-to-Back - The ATU/Messaging Unit interface is capable of accepting fast back-to-back
+**					transactions in Conventional PCI mode when the transactions are not to the same target. Since fast
+**					back-to-back transactions do not exist in PCI-X mode, this bit is forced to 0 in the PCI-X mode.
+**  06           0 2			UDF Supported - User Definable Features are not supported
+**  05           1 2			66 MHz. Capable - 66 MHz operation is supported.
+**  04           1 2			Capabilities - When set, this function implements extended capabilities.
+**  03             0			Interrupt Status - reflects the state of the ATU interrupt when the
+**					Interrupt Disable bit in the command register is a 0.
+**									0=ATU interrupt signal deasserted.
+**									1=ATU interrupt signal asserted.
+**	NOTE: Setting the Interrupt Disable bit to a 1 has no effect on the state of this bit. Refer to
+**		Section 3.10.23, ATU Interrupt Pin Register - ATUIPR on page 236 for details on the ATU
+**  										interrupt signal.
+**  02:00      00000 2                      Reserved.
+***********************************************************************************
+***********************************************************************************
+**  ATU Revision ID Register - ATURID
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00        00H                        ATU Revision - identifies the 80331 revision number.
+***********************************************************************************
+***********************************************************************************
+**  ATU Class Code Register - ATUCCR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  23:16        05H                        Base Class - Memory Controller
+**  15:08        80H                        Sub Class - Other Memory Controller
+**  07:00        00H                        Programming Interface - None defined
+***********************************************************************************
+***********************************************************************************
+**  ATU Cacheline Size Register - ATUCLSR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00        00H                        ATU Cacheline Size - specifies the system cacheline size in DWORDs.
+**								Cacheline size is restricted to either 0, 8 or 16 DWORDs.
+***********************************************************************************
+***********************************************************************************
+**  ATU Latency Timer Register - ATULT
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:03     00000 2	(for Conventional mode)
+**            01000 2	(for PCI-X mode)
+**			Programmable Latency Timer - This field varies the latency timer for the interface from 0 to 248 clocks.
+**			The default value is 0 clocks for Conventional PCI mode, and 64 clocks for PCI-X mode.
+**  02:00       000 2	Latency Timer Granularity - These Bits are read only
+**				giving a programmable granularity of 8 clocks for the latency timer.
+***********************************************************************************
+***********************************************************************************
+**  ATU Header Type Register - ATUHTR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07           0 2			Single Function/Multi-Function Device - Identifies the 80331 as a single-function PCI device.
+**  06:00   000000 2			PCI Header Type - This bit field indicates the type of PCI header implemented. The ATU interface
+**					header conforms to PCI Local Bus Specification, Revision 2.3.
+***********************************************************************************
+***********************************************************************************
+**  ATU BIST Register - ATUBISTR
+**
+**  The ATU BIST Register controls the functions the Intel XScale core performs when BIST is
+**  initiated. This register is the interface between the host processor requesting BIST functions and
+**  the 80331 replying with the results from the software implementation of the BIST functionality.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07           0 2			BIST Capable - This bit value is always equal to the ATUCR ATU BIST Interrupt Enable bit.
+**  06           0 2			Start BIST - When the ATUCR BIST Interrupt Enable bit is set:
+**					Setting this bit generates an interrupt to the Intel XScale core to perform a software BIST function.
+**					The Intel XScale core clears this bit when the BIST software has completed with the BIST results
+**					found in ATUBISTR register bits [3:0].
+**					When the ATUCR BIST Interrupt Enable bit is clear:
+**					Setting this bit does not generate an interrupt
+**					to the Intel XScale core and no BIST functions is performed.
+**					The Intel XScale core does not clear this bit.
+**  05:04       00 2			Reserved
+**  03:00     0000 2			BIST Completion Code - when the ATUCR
+**					BIST Interrupt Enable bit is set and the ATUBISTR Start BIST bit is set (bit 6):
+**					The Intel XScale  core places the results of the software BIST in these bits.
+**					A nonzero value indicates a device-specific error.
+***********************************************************************************
+***************************************************************************************
+**            ATU Base Registers and Associated Limit Registers
+***************************************************************************************
+**           Base Address                         Register Limit                          Register Description
+**  Inbound ATU Base Address Register 0           Inbound ATU Limit Register 0	Defines the inbound translation window 0 from the PCI bus.
+**  Inbound ATU Upper Base Address Register 0     N/A					Together with ATU Base Address Register 0
+**												defines the inbound
+**												translation window 0 from the PCI bus for DACs.
+**  Inbound ATU Base Address Register 1           Inbound ATU Limit Register 1	Defines inbound window 1 from the PCI bus.
+**  Inbound ATU Upper Base Address Register 1     N/A					Together with ATU Base Address Register 1
+**												defines inbound window 1 from the PCI bus for DACs.
+**  Inbound ATU Base Address Register 2           Inbound ATU Limit Register 2	Defines the inbound translation window 2 from the PCI bus.
+**  Inbound ATU Upper Base Address Register 2     N/A					Together with ATU Base Address Register 2
+**												defines the inbound translation
+**												window 2 from the PCI bus for DACs.
+**  Inbound ATU Base Address Register 3           Inbound ATU Limit Register 3	Defines the inbound translation window 3 from the PCI bus.
+**  Inbound ATU Upper Base Address Register 3     N/A					Together with ATU Base Address Register 3
+**												defines the inbound translation window 3
+**												from the PCI bus for DACs.
+**	NOTE: This is a private BAR that resides outside of the standard PCI configuration header space (offsets 00H-3FH).
+**  Expansion ROM Base Address Register           Expansion ROM Limit Register	Defines the window of addresses used by a bus master
+**												for reading from an Expansion ROM.
+**--------------------------------------------------------------------------------------
+**  ATU Inbound Window 1 is not a translate window.
+**  The ATU does not claim any PCI accesses that fall within this range.
+**  This window is used to allocate host memory for use by Private Devices.
+**  When enabled, the ATU interrupts the Intel  XScale core when either the IABAR1 register or the IAUBAR1 register is written from the PCI bus.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Base Address Register 0 - IABAR0
+**
+**  . The Inbound ATU Base Address Register 0 (IABAR0) together with the Inbound ATU Upper Base Address Register 0
+**  		(IAUBAR0) defines the block of memory addresses where the inbound translation window 0 begins.
+**  . The inbound ATU decodes and forwards the bus request to the 80331 internal bus with a translated address to map into 80331 local memory.
+**  . The IABAR0 and IAUBAR0 define the base address and describes the required memory block size.
+**  . Bits 31 through 12 of the IABAR0 is either read/write bits or read only with a value of 0
+**    depending on the value located within the IALR0.
+**    This configuration allows the IABAR0 to be programmed per PCI Local Bus Specification.
+**    The first 4 Kbytes of memory defined by the IABAR0, IAUBAR0 and the IALR0 is reserved for the Messaging Unit.
+**    The programmed value within the base address register must comply with the PCI programming requirements for address alignment.
+**  Warning:
+**    When IALR0 is cleared prior to host configuration:
+**                          the user should also clear the Prefetchable Indicator and the Type Indicator.
+**    Assuming IALR0 is not cleared:
+**                          a. Since non prefetchable memory windows can never be placed above the 4 Gbyte address boundary,
+**                             when the Prefetchable Indicator is cleared prior to host configuration,
+**                             the user should also set the Type Indicator for 32 bit addressability.
+**                          b. For compliance to the PCI-X Addendum to the PCI Local Bus Specification,
+**                             when the Prefetchable Indicator is set prior to host configuration, the user
+**                             should also set the Type Indicator for 64 bit addressability.
+**                             This is the default for IABAR0.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Translation Base Address 0 - These bits define the actual location
+**  					the translation function is to respond to when addressed from the PCI bus.
+**  11:04        00H			Reserved.
+**  03           1 2			Prefetchable Indicator - When set, defines the memory space as prefetchable.
+**  02:01       10 2			Type Indicator - Defines the width of the addressability for this memory window:
+**  						00 - Memory Window is locatable anywhere in 32 bit address space
+**  						10 - Memory Window is locatable anywhere in 64 bit address space
+**  00           0 2			Memory Space Indicator - This bit field describes memory or I/O space base address.
+**  					The ATU does not occupy I/O space, thus this bit must be zero.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Upper Base Address Register 0 - IAUBAR0
+**
+**  This register contains the upper base address when decoding PCI addresses beyond 4 GBytes.
+**  Together with the Translation Base Address this register defines the actual location the translation
+**  function is to respond to when addressed from the PCI bus for addresses > 4GBytes (for DACs).
+**  The programmed value within the base address register must comply with the PCI programming requirements for address alignment.
+**  Note:
+**      When the Type indicator of IABAR0 is set to indicate 32 bit addressability,
+**      the IAUBAR0 register attributes are read-only.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:0      00000H			Translation Upper Base Address 0 - Together with the Translation Base Address 0 these bits define the
+**					actual location the translation function is to respond
+**					to when addressed from the PCI bus for addresses > 4GBytes.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Base Address Register 1 - IABAR1
+**
+**  . The Inbound ATU Base Address Register (IABAR1) together with the Inbound ATU Upper Base Address Register 1
+**  	(IAUBAR1) defines the block of memory addresses where the inbound translation window 1 begins.
+**  . This window is used merely to allocate memory on the PCI bus and, the ATU does not process any PCI bus transactions to this memory range.
+**  . The programmed value within the base address register must comply with the PCI programming requirements for address alignment.
+**  . When enabled, the ATU interrupts the Intel XScale core when the IABAR1 register is written from the PCI bus.
+**  Warning:
+**    When a non-zero value is not written to IALR1 prior to host configuration,
+**                          the user should not set either the Prefetchable Indicator or the Type Indicator for 64 bit addressability.
+**                          This is the default for IABAR1.
+**    Assuming a non-zero value is written to IALR1,
+**  			the user may set the Prefetchable Indicator
+**  			              or the Type         Indicator:
+**  						a. Since non prefetchable memory windows can never be placed above the 4 Gbyte address
+**  							boundary, when the Prefetchable Indicator is not set prior to host configuration,
+**  							he user should also leave the Type Indicator set for 32 bit addressability.
+**  							This is the default for IABAR1.
+**  						b. when the Prefetchable Indicator is set prior to host configuration,
+**  							the user should also set the Type Indicator for 64 bit addressability.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Translation Base Address 1 - These bits define the actual location of window 1 on the PCI bus.
+**  11:04        00H			Reserved.
+**  03           0 2			Prefetchable Indicator - When set, defines the memory space as prefetchable.
+**  02:01       00 2			Type Indicator - Defines the width of the addressability for this memory window:
+**  					00 - Memory Window is locatable anywhere in 32 bit address space
+**  					10 - Memory Window is locatable anywhere in 64 bit address space
+**  00           0 2			Memory Space Indicator - This bit field describes memory or I/O space base address.
+**  					The ATU does not occupy I/O space, thus this bit must be zero.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Upper Base Address Register 1 - IAUBAR1
+**
+**  This register contains the upper base address when locating this window for PCI addresses beyond 4 GBytes.
+**  Together with the IABAR1 this register defines the actual location for this memory window for addresses > 4GBytes (for DACs).
+**  This window is used merely to allocate memory on the PCI bus and, the ATU does not process any PCI bus transactions to this memory range.
+**  The programmed value within the base address register must comply with the PCI programming
+**  requirements for address alignment.
+**  When enabled, the ATU interrupts the Intel XScale core when the IAUBAR1 register is written
+**  from the PCI bus.
+**  Note:
+**      When the Type indicator of IABAR1 is set to indicate 32 bit addressability,
+**      the IAUBAR1 register attributes are read-only.
+**      This is the default for IABAR1.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:0      00000H			Translation Upper Base Address 1 - Together with the Translation Base Address 1
+**  					these bits define the actual location for this memory window on the PCI bus for addresses > 4GBytes.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Base Address Register 2 - IABAR2
+**
+**  . The Inbound ATU Base Address Register 2 (IABAR2) together with the Inbound ATU Upper Base Address Register 2
+**  	(IAUBAR2) defines the block of memory addresses where the inbound translation window 2 begins.
+**  . The inbound ATU decodes and forwards the bus request to the 80331 internal bus with a translated address to map into 80331 local memory.
+**  . The IABAR2 and IAUBAR2 define the base address and describes the required memory block size
+**  . Bits 31 through 12 of the IABAR2 is either read/write bits or read only with a value of 0 depending on the value located within the IALR2.
+**    The programmed value within the base address register must comply with the PCI programming requirements for address alignment.
+**  Warning:
+**    When a non-zero value is not written to IALR2 prior to host configuration,
+**                          the user should not set either the Prefetchable Indicator
+**                                                      or the Type         Indicator for 64 bit addressability.
+**                          This is the default for IABAR2.
+**  Assuming a non-zero value is written to IALR2,
+**                          the user may set the Prefetchable Indicator
+**                                        or the Type         Indicator:
+**  						a. Since non prefetchable memory windows can never be placed above the 4 Gbyte address boundary,
+**                             when the Prefetchable Indicator is not set prior to host configuration,
+**                             the user should also leave the Type Indicator set for 32 bit addressability.
+**                             This is the default for IABAR2.
+**  						b. when the Prefetchable Indicator is set prior to host configuration,
+**                             the user should also set the Type Indicator for 64 bit addressability.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Translation Base Address 2 - These bits define the actual location
+**  					the translation function is to respond to when addressed from the PCI bus.
+**  11:04        00H			Reserved.
+**  03           0 2			Prefetchable Indicator - When set, defines the memory space as prefetchable.
+**  02:01       00 2			Type Indicator - Defines the width of the addressability for this memory window:
+**  					00 - Memory Window is locatable anywhere in 32 bit address space
+**  					10 - Memory Window is locatable anywhere in 64 bit address space
+**  00           0 2			Memory Space Indicator - This bit field describes memory or I/O space base address.
+**					The ATU does not occupy I/O space, thus this bit must be zero.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Upper Base Address Register 2 - IAUBAR2
+**
+**  This register contains the upper base address when decoding PCI addresses beyond 4 GBytes.
+**  Together with the Translation Base Address this register defines the actual location
+**  the translation function is to respond to when addressed from the PCI bus for addresses > 4GBytes (for DACs).
+**  The programmed value within the base address register must comply with the PCI programming
+**  requirements for address alignment.
+**  Note:
+**      When the Type indicator of IABAR2 is set to indicate 32 bit addressability,
+**      the IAUBAR2 register attributes are read-only.
+**      This is the default for IABAR2.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:0      00000H                        Translation Upper Base Address 2 - Together with the Translation Base Address 2
+**  these bits define the actual location the translation function is to respond to when addressed from the PCI bus for addresses > 4GBytes.
+***********************************************************************************
+***********************************************************************************
+**  ATU Subsystem Vendor ID Register - ASVIR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:0      0000H                         Subsystem Vendor ID - This register uniquely identifies the add-in board or subsystem vendor.
+***********************************************************************************
+***********************************************************************************
+**  ATU Subsystem ID Register - ASIR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:0      0000H                         Subsystem ID - uniquely identifies the add-in board or subsystem.
+***********************************************************************************
+***********************************************************************************
+**  Expansion ROM Base Address Register -ERBAR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H                        Expansion ROM Base Address - These bits define the actual location
+**  where the Expansion ROM address window resides when addressed from the PCI bus on any 4 Kbyte boundary.
+**  11:01     000H                          Reserved
+**  00        0 2                           Address Decode Enable - This bit field shows the ROM address
+**  decoder is enabled or disabled. When cleared, indicates the address decoder is disabled.
+***********************************************************************************
+***********************************************************************************
+**  ATU Capabilities Pointer Register - ATU_CAP_PTR
+**  -----------------------------------------------------------------
+**  Bit Default Description
+**  07:00     C0H                           Capability List Pointer - This provides an offset in this
+**  functions configuration space that points to the 80331 PCl Bus Power Management extended capability.
+***********************************************************************************
+***********************************************************************************
+**  Determining Block Sizes for Base Address Registers
+**  The required address size and type can be determined by writing ones to a base address register and
+**  reading from the registers. By scanning the returned value from the least-significant bit of the base
+**  address registers upwards, the programmer can determine the required address space size. The
+**  binary-weighted value of the first non-zero bit found indicates the required amount of space.
+**  Table 105 describes the relationship between the values read back and the byte sizes the base
+**  address register requires.
+**  As an example, assume that FFFF.FFFFH is written to the ATU Inbound Base Address Register 0
+**  (IABAR0) and the value read back is FFF0.0008H. Bit zero is a zero, so the device requires
+**  memory address space. Bit three is one, so the memory does supports prefetching. Scanning
+**  upwards starting at bit four, bit twenty is the first one bit found. The binary-weighted value of this
+**  bit is 1,048,576, indicated that the device requires 1 Mbyte of memory space.
+**  The ATU Base Address Registers and the Expansion ROM Base Address Register use their
+**  associated limit registers to enable which bits within the base address register are read/write and
+**  which bits are read only (0). This allows the programming of these registers in a manner similar to
+**  other PCI devices even though the limit is variable.
+**  Table 105. Memory Block Size Read Response
+**  Response After Writing all 1s
+**  to the Base Address Register
+**  Size
+**  (Bytes)
+**  Response After Writing all 1s
+**  to the Base Address Register
+**  Size
+**  (Bytes)
+**  FFFFFFF0H 16 FFF00000H 1 M
+**  FFFFFFE0H 32 FFE00000H 2 M
+**  FFFFFFC0H 64 FFC00000H 4 M
+**  FFFFFF80H 128 FF800000H 8 M
+**  FFFFFF00H 256 FF000000H 16 M
+**  FFFFFE00H 512 FE000000H 32 M
+**  FFFFFC00H 1K FC000000H 64 M
+**  FFFFF800H 2K F8000000H 128 M
+**  FFFFF000H 4K F0000000H 256 M
+**  FFFFE000H 8K E0000000H 512 M
+**  FFFFC000H 16K C0000000H 1 G
+**  FFFF8000H 32K 80000000H 2 G
+**  FFFF0000H 64K
+**  00000000H
+**  Register not
+**  imple-mented,
+**  no
+**  address
+**  space
+**  required.
+**  FFFE0000H 128K
+**  FFFC0000H 256K
+**  FFF80000H 512K
+**
+***************************************************************************************
+***********************************************************************************
+**  ATU Interrupt Line Register - ATUILR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       FFH		Interrupt Assigned - system-assigned value identifies which system interrupt controllers interrupt
+**				request line connects to the device's PCI interrupt request lines (as specified in the interrupt pin register).
+**				A value of FFH signifies no connection or unknown.
+***********************************************************************************
+***********************************************************************************
+**  ATU Interrupt Pin Register - ATUIPR
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       01H		Interrupt Used - A value of 01H signifies that the ATU interface unit uses INTA# as the interrupt pin.
+***********************************************************************************
+***********************************************************************************
+**  ATU Minimum Grant Register - ATUMGNT
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       80H		This register specifies how long a burst period the device needs in increments of 8 PCI clocks.
+***********************************************************************************
+***********************************************************************************
+**  ATU Maximum Latency Register - ATUMLAT
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       00H		Specifies frequency (how often) the device needs to access the PCI bus in increments of 8 PCI clocks.
+**				A zero value indicates the device has no stringent requirement.
+***********************************************************************************
+***********************************************************************************
+**  Inbound Address Translation
+**
+**  The ATU allows external PCI bus initiators to directly access the internal bus.
+**  These PCI bus initiators can read or write 80331 memory-mapped registers or 80331 local memory space.
+**  The process of inbound address translation involves two steps:
+**  1. Address Detection.
+**             E Determine when the 32-bit PCI address (64-bit PCI address during DACs) is
+**                within the address windows defined for the inbound ATU.
+**             E Claim the PCI transaction with medium DEVSEL# timing in the conventional PCI
+**                mode and with Decode A DEVSEL# timing in the PCI-X mode.
+**  2. Address Translation.
+**             E Translate the 32-bit PCI address (lower 32-bit PCI address during DACs) to a 32-bit 80331 internal bus address.
+**  				The ATU uses the following registers in inbound address window 0 translation:
+**  				E Inbound ATU Base Address Register 0
+**  				E Inbound ATU Limit Register 0
+**  				E Inbound ATU Translate Value Register 0
+**  				The ATU uses the following registers in inbound address window 2 translation:
+**  				E Inbound ATU Base Address Register 2
+**  				E Inbound ATU Limit Register 2
+**  				E Inbound ATU Translate Value Register 2
+**  				The ATU uses the following registers in inbound address window 3 translation:
+**  				E Inbound ATU Base Address Register 3
+**  				E Inbound ATU Limit Register 3
+**  				E Inbound ATU Translate Value Register 3
+**    Note: Inbound Address window 1 is not a translate window.
+**          Instead, window 1 may be used to allocate host memory for Private Devices.
+**          Inbound Address window 3 does not reside in the standard section of the configuration header (offsets 00H - 3CH),
+**          thus the host BIOS does not configure window 3.
+**          Window 3 is intended to be used as a special window into local memory for private PCI
+**          agents controlled by the 80331 in conjunction with the Private Memory Space of the bridge.
+**          PCI-to-PCI Bridge in 80331 or
+**          Inbound address detection is determined from the 32-bit PCI address,
+**          (64-bit PCI address during DACs) the base address register and the limit register.
+**          In the case of DACs none of the upper 32-bits of the address is masked during address comparison.
+**
+**  The algorithm for detection is:
+**
+**  Equation 1. Inbound Address Detection
+**              When (PCI_Address [31:0] & Limit_Register[31:0])
+**  			== (Base_Register[31:0] & PCI_Address [63:32])
+**  			== Base_Register[63:32] (for DACs only)
+**              the PCI Address is claimed by the Inbound ATU.
+**
+**  			The incoming 32-bit PCI address (lower 32-bits of the address in case of DACs) is bitwise ANDed
+**  			with the associated inbound limit register.
+**              When the result matches the base register (and upper base address matches upper PCI address in case of DACs),
+**              the inbound PCI address is detected as being within the inbound translation window and is claimed by the ATU.
+**
+**  			Note:   The first 4 Kbytes of the ATU inbound address translation window 0 are reserved for the Messaging Unit.
+**  					Once the transaction is claimed, the address must be translated from a PCI address to a 32-bit
+**  					internal bus address. In case of DACs upper 32-bits of the address is simply discarded and only the
+**  					lower 32-bits are used during address translation.
+**              		The algorithm is:
+**  Equation 2. Inbound Translation
+**              Intel I/O processor Internal Bus Address=(PCI_Address[31:0] & ~Limit_Register[31:0]) | ATU_Translate_Value_Register[31:0].
+**
+**  			The incoming 32-bit PCI address (lower 32-bits in case of DACs) is first bitwise ANDed with the
+**  			bitwise inverse of the limit register. This result is bitwise ORed with the ATU Translate Value and
+**  			the result is the internal bus address. This translation mechanism is used for all inbound memory
+**  			read and write commands excluding inbound configuration read and writes.
+**  			In the PCI mode for inbound memory transactions, the only burst order supported is Linear
+**  			Incrementing. For any other burst order, the ATU signals a Disconnect after the first data phase.
+**  			The PCI-X supports linear incrementing only, and hence above situation is not encountered in the PCI-X mode.
+**  example:
+**  	    Register Values
+**  		         Base_Register=3A00 0000H
+**  		        Limit_Register=FF80 0000H (8 Mbyte limit value)
+**  		        Value_Register=B100 0000H
+**  		        Inbound Translation Window ranges from 3A00 0000H to 3A7F FFFFH (8 Mbytes)
+**
+**  		Address Detection (32-bit address)
+**
+**  						PCI_Address & Limit_Register == Base_Register
+**  						3A45 012CH  &   FF80 0000H   ==  3A00 0000H
+**
+**  					ANS: PCI_Address is in the Inbound Translation Window
+**  		Address Translation (to get internal bus address)
+**
+**  						IB_Address=(PCI_Address & ~Limit_Register) | Value_Reg
+**  						IB_Address=(3A45 012CH & 007F FFFFH) | B100 0000H
+**
+**  					ANS:IB_Address=B145 012CH
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Limit Register 0 - IALR0
+**
+**  Inbound address translation for memory window 0 occurs for data transfers occurring from the PCI
+**  bus (originated from the PCI bus) to the 80331 internal bus. The address translation block converts
+**  PCI addresses to internal bus addresses.
+**  The 80331 translate value registers programmed value must be naturally aligned with the base
+**  address registers programmed value. The limit register is used as a mask; thus, the lower address
+**  bits programmed into the 80331 translate value register are invalid. Refer to the PCI Local Bus
+**  Specification, Revision 2.3 for additional information on programming base address registers.
+**  Bits 31 to 12 within the IALR0 have a direct effect on the IABAR0 register, bits 31 to 12, with a
+**  one to one correspondence. A value of 0 in a bit within the IALR0 makes the corresponding bit
+**  within the IABAR0 a read only bit which always returns 0. A value of 1 in a bit within the IALR0
+**  makes the corresponding bit within the IABAR0 read/write from PCI. Note that a consequence of
+**  this programming scheme is that unless a valid value exists within the IALR0, all writes to the
+**  IABAR0 has no effect since a value of all zeros within the IALR0 makes the IABAR0 a read only  register.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     FF000H			Inbound Translation Limit 0 - This readback value determines the memory block size required for
+**					inbound memory window 0 of the address translation unit. This defaults to an inbound window of 16MB.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Translate Value Register 0 - IATVR0
+**
+**  The Inbound ATU Translate Value Register 0 (IATVR0) contains the internal bus address used to
+**  convert PCI bus addresses. The converted address is driven on the internal bus as a result of the
+**  inbound ATU address translation.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     FF000H			Inbound ATU Translation Value 0 - This value is used to convert the PCI address to internal bus addresses.
+**					This value must be 64-bit aligned on the internal bus.
+**					The default address allows the ATU to access the internal 80331 memory-mapped registers.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Expansion ROM Limit Register - ERLR
+**
+**  The Expansion ROM Limit Register (ERLR) defines the block size of addresses the ATU defines
+**  as Expansion ROM address space. The block size is programmed by writing a value into the ERLR.
+**  Bits 31 to 12 within the ERLR have a direct effect on the ERBAR register, bits 31 to 12, with a one
+**  to one correspondence. A value of 0 in a bit within the ERLR makes the corresponding bit within
+**  the ERBAR a read only bit which always returns 0. A value of 1 in a bit within the ERLR makes
+**  the corresponding bit within the ERBAR read/write from PCI.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     000000H		Expansion ROM Limit - Block size of memory required
+**					for the Expansion ROM translation unit. Default
+**					value is 0, which indicates no Expansion ROM address space
+**					and all bits within the ERBAR are read only with a value of 0.
+**  11:00        000H                       Reserved.
+***********************************************************************************
+***********************************************************************************
+**  Expansion ROM Translate Value Register - ERTVR
+**
+**  The Expansion ROM Translate Value Register contains the 80331 internal bus address which the
+**  ATU converts the PCI bus access. This address is driven on the internal bus as a result of the
+**  Expansion ROM address translation.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Expansion ROM Translation Value - Used to convert PCI addresses to 80331 internal bus addresses
+**					for Expansion ROM accesses. The Expansion ROM address
+**					translation value must be word aligned on the internal bus.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Limit Register 1 - IALR1
+**
+**  Bits 31 to 12 within the IALR1 have a direct effect on the IABAR1 register, bits 31 to 12, with a
+**  one to one correspondence. A value of 0 in a bit within the IALR1 makes the corresponding bit
+**  within the IABAR1 a read only bit which always returns 0. A value of 1 in a bit within the IALR1
+**  makes the corresponding bit within the IABAR1 read/write from PCI. Note that a consequence of
+**  this programming scheme is that unless a valid value exists within the IALR1, all writes to the
+**  IABAR1 has no effect since a value of all zeros within the IALR1 makes the IABAR1 a read only
+**  register.
+**  The inbound memory window 1 is used merely to allocate memory on the PCI bus. The ATU does
+**  not process any PCI bus transactions to this memory range.
+**  Warning: The ATU does not claim any PCI accesses that fall within the range defined by IABAR1,
+**  IAUBAR1, and IALR1.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Inbound Translation Limit 1 - This readback value determines
+**					the memory block size required for the ATUs memory window 1.
+**  11:00       000H			Reserved
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Limit Register 2 - IALR2
+**
+**  Inbound address translation for memory window 2 occurs for data transfers occurring from the PCI
+**  bus (originated from the PCI bus) to the 80331 internal bus. The address translation block converts
+**  PCI addresses to internal bus addresses.
+**  The inbound translation base address for inbound window 2 is specified in Section 3.10.15. When
+**  determining block size requirements X as described in Section 3.10.21 X the translation limit
+**  register provides the block size requirements for the base address register. The remaining registers
+**  used for performing address translation are discussed in Section 3.2.1.1.
+**  The 80331 translate value registers programmed value must be naturally aligned with the base
+**  address registers programmed value. The limit register is used as a mask; thus, the lower address
+**  bits programmed into the 80331 translate value register are invalid. Refer to the PCI Local Bus
+**  Specification, Revision 2.3 for additional information on programming base address registers.
+**  Bits 31 to 12 within the IALR2 have a direct effect on the IABAR2 register, bits 31 to 12, with a
+**  one to one correspondence. A value of 0 in a bit within the IALR2 makes the corresponding bit
+**  within the IABAR2 a read only bit which always returns 0. A value of 1 in a bit within the IALR2
+**  makes the corresponding bit within the IABAR2 read/write from PCI. Note that a consequence of
+**  this programming scheme is that unless a valid value exists within the IALR2, all writes to the
+**  IABAR2 has no effect since a value of all zeros within the IALR2 makes the IABAR2 a read only
+**  register.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Inbound Translation Limit 2 - This readback value determines
+**					the memory block size required for the ATUs memory window 2.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Translate Value Register 2 - IATVR2
+**
+**  The Inbound ATU Translate Value Register 2 (IATVR2) contains the internal bus address used to
+**  convert PCI bus addresses. The converted address is driven on the internal bus as a result of the
+**  inbound ATU address translation.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Inbound ATU Translation Value 2 - This value is used to
+**					convert the PCI address to internal bus addresses.
+**					This value must be 64-bit aligned on the internal bus.
+**					The default address allows the ATU to access the internal 80331 memory-mapped registers.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Outbound I/O Window Translate Value Register - OIOWTVR
+**
+**  The Outbound I/O Window Translate Value Register (OIOWTVR) contains the PCI I/O address
+**  used to convert the internal bus access to a PCI address. This address is driven on the PCI bus as a
+**  result of the outbound ATU address translation.
+**  The I/O window is from 80331 internal bus address 9000 000H to 9000 FFFFH with the fixed
+**  length of 64 Kbytes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:16     0000H				Outbound I/O Window Translate Value - Used to convert
+**						internal bus addresses to PCI addresses.
+**  15:00     0000H                         Reserved
+***********************************************************************************
+***********************************************************************************
+**  Outbound Memory Window Translate Value Register 0 -OMWTVR0
+**
+**  The Outbound Memory Window Translate Value Register 0 (OMWTVR0) contains the PCI
+**  address used to convert 80331 internal bus addresses for outbound transactions. This address is
+**  driven on the PCI bus as a result of the outbound ATU address translation.
+**  The memory window is from internal bus address 8000 000H to 83FF FFFFH with the fixed length
+**  of 64 Mbytes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:26       00H                         Outbound MW Translate Value - Used to convert
+**						80331 internal bus addresses to PCI addresses.
+**  25:02     00 0000H                      Reserved
+**  01:00      00 2                         Burst Order - This bit field shows the address sequence
+**						during a memory burst. Only linear incrementing mode is supported.
+***********************************************************************************
+***********************************************************************************
+**  Outbound Upper 32-bit Memory Window Translate Value Register 0 - OUMWTVR0
+**
+**  The Outbound Upper 32-bit Memory Window Translate Value Register 0 (OUMWTVR0) defines
+**  the upper 32-bits of address used during a dual address cycle. This enables the outbound ATU to
+**  directly address anywhere within the 64-bit host address space. When this register is all-zero, then
+**  a SAC is generated on the PCI bus.
+**  The memory window is from internal bus address 8000 000H to 83FF FFFFH with the fixed
+**  length of 64 Mbytes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00     0000 0000H                    These bits define the upper 32-bits
+**						 of address driven during the dual address cycle (DAC).
+***********************************************************************************
+***********************************************************************************
+**  Outbound Memory Window Translate Value Register 1 -OMWTVR1
+**
+**  The Outbound Memory Window Translate Value Register 1 (OMWTVR1) contains the PCI
+**  address used to convert 80331 internal bus addresses for outbound transactions. This address is
+**  driven on the PCI bus as a result of the outbound ATU address translation.
+**  The memory window is from internal bus address 8400 000H to 87FF FFFFH with the fixed length
+**  of 64 Mbytes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:26       00H			Outbound MW Translate Value - Used to convert 80331
+**					internal bus addresses to PCI addresses.
+**  25:02     00 0000H		Reserved
+**  01:00       00 2			Burst Order - This bit field shows the address sequence during a memory burst.
+**					Only linear incrementing mode is supported.
+***********************************************************************************
+***********************************************************************************
+**  Outbound Upper 32-bit Memory Window Translate Value Register 1 - OUMWTVR1
+**
+**  The Outbound Upper 32-bit Memory Window Translate Value Register 1 (OUMWTVR1) defines
+**  the upper 32-bits of address used during a dual address cycle. This enables the outbound ATU to
+**  directly address anywhere within the 64-bit host address space. When this register is all-zero, then
+**  a SAC is generated on the PCI bus.
+**  The memory window is from internal bus address 8400 000H to 87FF FFFFH with the fixed length
+**  of 64 Mbytes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00    0000 0000H			These bits define the upper 32-bits
+**						of address driven during the dual address cycle (DAC).
+***********************************************************************************
+***********************************************************************************
+**  Outbound Upper 32-bit Direct Window Translate Value Register - OUDWTVR
+**
+**  The Outbound Upper 32-bit Direct Window Translate Value Register (OUDWTVR) defines the
+**  upper 32-bits of address used during a dual address cycle for the transactions via Direct Addressing
+**  Window. This enables the outbound ATU to directly address anywhere within the 64-bit host
+**  address space. When this register is all-zero, then a SAC is generated on the PCI bus.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00    0000 0000H			These bits define the upper 32-bits of address driven during the dual address cycle (DAC).
+***********************************************************************************
+***********************************************************************************
+**  ATU Configuration Register - ATUCR
+**
+**  The ATU Configuration Register controls the outbound address translation for address translation
+**  unit. It also contains bits for Conventional PCI Delayed Read Command (DRC) aliasing, discard
+**  timer status, SERR# manual assertion, SERR# detection interrupt masking, and ATU BIST
+**  interrupt enabling.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20       00H                         Reserved
+**  19          0 2			ATU DRC Alias - when set, the ATU does not distinguish read commands when attempting to match a
+**					current PCI read transaction with read data
+**					enqueued within the DRC buffer. When clear, a current read
+**					transaction must have the exact same read command as the DRR for the ATU to deliver DRC data. Not
+**					applicable in the PCI-X mode.
+**  18          0 2			Direct Addressing Upper 2Gbytes Translation Enable - When set,
+**					with Direct Addressing enabled (bit 7 of the ATUCR set),
+**					the ATU forwards internal bus cycles with an address between 0000.0040H and
+**					7FFF.FFFFH to the PCI bus with bit 31 of the address set (8000.0000H - FFFF.FFFFH).
+**					When clear, no translation occurs.
+**  17          0 2			Reserved
+**  16          0 2			SERR# Manual Assertion - when set, the ATU asserts SERR# for one clock on the PCI interface. Until
+**					cleared, SERR# may not be manually asserted again. Once cleared, operation proceeds as specified.
+**  15          0 2			ATU Discard Timer Status - when set, one of the 4 discard timers within the ATU has expired and
+**					discarded the delayed completion transaction within the queue. When clear, no timer has expired.
+**  14:10    00000 2			Reserved
+**  09          0 2			SERR# Detected Interrupt Enable - When set, the Intel XScale core is signalled an HPI# interrupt
+**					when the ATU detects that SERR# was asserted.
+**					When clear, the Intel XScale core is not interrupted when SERR# is detected.
+**  08          0 2			Direct Addressing Enable - Setting this bit enables direct outbound addressing through the ATU.
+**					Internal bus cycles with an address between 0000.0040H and 7FFF.FFFFH automatically forwards to
+**					the PCI bus with or without translation of address bit 31 based on the setting of bit 18 of the ATUCR.
+**  07:04    0000 2			Reserved
+**  03          0 2			ATU BIST Interrupt Enable - When set, enables an interrupt
+**					to the Intel XScale core when the start
+**					BIST bit is set in the ATUBISTR register. This bit
+**					is also reflected as the BIST Capable bit 7 in the ATUBISTR register.
+**  02          0 2			Reserved
+**  01          0 2			Outbound ATU Enable - When set, enables the outbound address translation unit.
+**					When cleared, disables the outbound ATU.
+**  00          0 2			Reserved
+***********************************************************************************
+***********************************************************************************
+**  PCI Configuration and Status Register - PCSR
+**
+**  The PCI Configuration and Status Register has additional bits for controlling and monitoring
+**  various features of the PCI bus interface.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:19      0000H			Reserved
+**  18          0 2			Detected Address or Attribute Parity Error -
+**  					set when a parity error is detected during either the address
+**  					or attribute phase of a transaction on the PCI bus even when the ATUCMD register Parity Error
+**  					Response bit is cleared. Set under the following conditions:
+**  					E Any Address or Attribute (PCI-X Only) Parity Error on the Bus (including one generated by the ATU).
+**  17:16  Varies with			external state of DEVSEL#, STOP#, and TRDY#, during P_RST#
+**  					PCI-X capability - These two bits define the mode of the PCI bus (conventional or PCI-X) as well as the
+**  					operating frequency in the case of PCI-X mode.
+**  					00 - Conventional PCI mode
+**  					01 - PCI-X 66
+**  					10 - PCI-X 100
+**  					11 - PCI-X 133
+**  					As defined by the PCI-X Addendum to the PCI Local Bus Specification, Revision 1.0a, the operating
+**  					mode is determined by an initialization pattern on the PCI bus during P_RST# assertion:
+**  					DEVSEL# STOP# TRDY# Mode
+**  					Deasserted Deasserted Deasserted Conventional
+**  						Deasserted Deasserted Asserted PCI-X 66
+**  						Deasserted Asserted Deasserted PCI-X 100
+**  						Deasserted Asserted Asserted PCI-X 133
+**  						All other patterns are reserved.
+**  15          0 2
+**  					Outbound Transaction Queue Busy:
+**  					0=Outbound Transaction Queue Empty
+**  					1=Outbound Transaction Queue Busy
+**  14          0 2
+**  					Inbound Transaction Queue Busy:
+**  					0=Inbound Transaction Queue Empty
+**  					1=Inbound Transaction Queue Busy
+**  13          0 2			Reserved.
+**  12          0 2
+**  					Discard Timer Value - This bit controls the time-out value
+**  					for the four discard timers attached to the queues holding read data.
+**  					A value of 0 indicates the time-out value is 2 15 clocks.
+**  					A value of 1 indicates the time-out value is 2 10 clocks.
+**  11          0 2			Reserved.
+**  10      Varies with external state of M66EN during P_RST# Bus Operating at 66 MHz -
+**					When set,
+**  					the interface has been initialized to function at 66 MHz in
+**  					Conventional PCI mode by the assertion of M66EN during bus initialization.
+**  					When clear,
+**  					the interface has been initialized as a 33 MHz bus.
+**  	NOTE: When PCSR bits 17:16 are not equal to zero, then this bit is meaningless since the 80331 is operating in PCI-X mode.
+**  09          0 2                         Reserved
+**  08      Varies with external state of REQ64# during P_RST# PCI Bus 64-Bit Capable -
+**  					When clear,
+**  					the PCI bus interface has been configured as 64-bit capable by
+**  					the assertion of REQ64# on the rising edge of P_RST#.
+**  					When set, the PCI interface is configured as 32-bit only.
+**  07:06      00 2			Reserved.
+**  05         0 2			Reset Internal Bus - This bit controls the reset of the Intel XScale core and all units on the internal
+**  					bus. In addition to the internal bus initialization, this bit triggers the assertion of the M_RST# pin for
+**  					initialization of registered DIMMs. When set:
+**  					When operating in the conventional PCI mode:
+**  					E All current PCI transactions being mastered by the ATU completes, and the ATU master interfaces
+**  					proceeds to an idle state. No additional transactions is mastered by these units until the internal bus
+**  					reset is complete.
+**  					E All current transactions being slaved by the ATU on either the PCI bus or the internal bus
+**  					completes, and the ATU target interfaces proceeds to an idle state. All future slave transactions
+**  					master aborts, with the exception of the completion cycle for the transaction that set the Reset
+**  					Internal Bus bit in the PCSR.
+**  					E When the value of the Core Processor Reset bit in the PCSR (upon P_RST# assertion) is set, the
+**  					Intel XScale core is held in reset when the internal bus reset is complete.
+**  					E The ATU ignores configuration cycles, and they appears as master aborts for: 32 Internal Bus clocks.
+**  					E The 80331 hardware clears this bit after the reset operation completes.
+**  					When operating in the PCI-X mode:
+**  					The ATU hardware responds the same as in Conventional PCI-X mode. However, this may create a
+**  					problem in PCI-X mode for split requests in that there may still be an outstanding split completion that the
+**  					ATU is either waiting to receive (Outbound Request) or initiate (Inbound Read Request). For a cleaner
+**  					internal bus reset, host software can take the following steps prior to asserting Reset Internal bus:
+**  					1. Clear the Bus Master (bit 2 of the ATUCMD) and the Memory Enable (bit 1 of the ATUCMD) bits in
+**  					the ATUCMD. This ensures that no new transactions, either outbound or inbound are enqueued.
+**  					2. Wait for both the Outbound (bit 15 of the PCSR) and Inbound Read (bit 14 of the PCSR) Transaction
+**  					queue busy bits to be clear.
+**  					3. Set the Reset Internal Bus bit
+**  					As a result, the ATU hardware resets the internal bus using the same logic as in conventional mode,
+**  					however the user is now assured that the ATU no longer has any pending inbound or outbound split
+**  													completion transactions.
+**  	NOTE: Since the Reset Internal Bus bit is set using an inbound configuration cycle, the user is
+**  		guaranteed that any prior configuration cycles have properly completed since there is only a one
+**  		deep transaction queue for configuration transaction requests. The ATU sends the appropriate
+**  		Split Write Completion Message to the Requester prior to the onset of Internal Bus Reset.
+**  04      0 2				Bus Master Indicator Enable: Provides software control for the Bus Master Indicator signal P_BMI used
+**  					for external RAIDIOS logic control of private devices. Only valid when operating with the bridge and
+**  					central resource/arbiter disabled (BRG_EN =low, ARB_EN=low).
+**  03		Varies with 		external state of PRIVDEV during P_RST#
+**  					Private Device Enable - This bit indicates the state of the reset strap which enables the private device
+**  					control mechanism within the PCI-to-PCI Bridge SISR configuration register.
+**  					0=Private Device control Disabled - SISR register bits default to zero
+**  					1=Private Device control Enabled - SISR register bits default to one
+**  02		Varies with external state of RETRY during P_RST# Configuration Cycle Retry -
+**  					When this bit is set,
+**  					the PCI interface of the 80331 responds to all configuration cycles with a Retry condition.
+**  					When clear, the 80331 responds to the appropriate configuration cycles.
+**  					The default condition for this bit is based on the external
+**  					state of the RETRY pin at the rising edge of P_RST#.
+**  					When the external state of the pin is high, the bit is set.
+**  					When the external state of the pin is low, the bit is cleared.
+**  01		Varies with external state of CORE_RST# during P_RST#
+**  					Core Processor Reset - This bit is set to its default value by the hardware when either P_RST# is
+**  					asserted or the Reset Internal Bus bit in PCSR is set. When this bit is set, the Intel XScale core is
+**  					being held in reset. Software cannot set this bit. Software is required to clear this bit to deassert Intel
+**  					XScale  core reset.
+**  					The default condition for this bit is based on the external state of the CORE_RST# pin at the rising edge
+**  					of P_RST#. When the external state of the pin is low, the bit is set. When the external state of the pin is
+**  					high, the bit is clear.
+**  00		Varies with external state of PRIVMEM during P_RST#
+**  					Private Memory Enable - This bit indicates the state of the reset strap which enables the private device
+**  					control mechanism within the PCI-to-PCI Bridge SDER configuration register.
+**  					0=Private Memory control Disabled - SDER register bit 2 default to zero
+**  					1=Private Memory control Enabled - SDER register bits 2 default to one
+***********************************************************************************
+***********************************************************************************
+**  ATU Interrupt Status Register - ATUISR
+**
+**  The ATU Interrupt Status Register is used to notify the core processor of the source of an ATU
+**  interrupt. In addition, this register is written to clear the source of the interrupt to the interrupt unit
+**  of the 80331. All bits in this register are Read/Clear.
+**  Bits 4:0 are a direct reflection of bits 14:11 and bit 8 (respectively) of the ATU Status Register
+**  (these bits are set at the same time by hardware but need to be cleared independently). Bit 7 is set
+**  by an error associated with the internal bus of the 80331. Bit 8 is for software BIST. The
+**  conditions that result in an ATU interrupt are cleared by writing a 1 to the appropriate bits in this
+**  register.
+**  Note: Bits 4:0, and bits 15 and 13:7 can result in an interrupt being driven to the Intel XScale core.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:18      0000H                        Reserved
+**  17          0 2			VPD Address Register Updated -
+**  					This bit is set when a PCI bus configuration write occurs to the VPDAR register.
+**  					Configuration register writes to the VPDAR does NOT result in bit 15 also being set. When set,
+**  					this bit results in the assertion of the ATU Configure Register Write Interrupt.
+**  16          0 2			Reserved
+**  15          0 2			ATU Configuration Write - This bit is set when a PCI bus configuration write occurs to any ATU register.
+**  					When set, this bit results in the assertion of the ATU Configure Register Write Interrupt.
+**  14          0 2			ATU Inbound Memory Window 1 Base Updated - This bit is set when a PCI bus configuration write
+**  					occurs to either the IABAR1 register or the IAUBAR1 register. Configuration register writes to these
+**  					registers deos NOT result in bit 15 also being set. When set, this bit results in the assertion of the ATU
+**  					Configure Register Write Interrupt.
+**  13          0 2			Initiated Split Completion Error Message - This bit is set when the device initiates a Split Completion
+**  					Message on the PCI Bus with the Split Completion Error attribute bit set.
+**  12          0 2			Received Split Completion Error Message - This bit is set when the device receives a Split Completion
+**  					Message from the PCI Bus with the Split Completion Error attribute bit set.
+**  11          0 2			Power State Transition - When the Power State Field of the ATU Power Management Control/Status
+**  					Register is written to transition the ATU function Power State from D0 to D3, D0 to D1, or D3 to D0 and
+**  					the ATU Power State Transition Interrupt mask bit is cleared, this bit is set.
+**  10          0 2			P_SERR# Asserted - set when P_SERR# is asserted on the PCI bus by the ATU.
+**  09          0 2			Detected Parity Error - set when a parity error is detected on the PCI bus even when the ATUCMD
+**  					registers Parity Error Response bit is cleared. Set under the following conditions:
+**  					E Write Data Parity Error when the ATU is a target (inbound write).
+**  					E Read Data Parity Error when the ATU is an initiator (outbound read).
+**  					E Any Address or Attribute (PCI-X Only) Parity Error on the Bus.
+**  08          0 2			ATU BIST Interrupt - When set, generates the ATU BIST Start Interrupt and indicates the host processor
+**  					has set the Start BIST bit (ATUBISTR register bit 6), when the ATU BIST interrupt is enabled (ATUCR
+**  					register bit 3). The Intel XScale core can initiate the software BIST and store the result in ATUBISTR
+**  					register bits 3:0.
+**  					Configuration register writes to the ATUBISTR does NOT result in bit 15 also being set or the assertion
+**  					of the ATU Configure Register Write Interrupt.
+**  07          0 2			Internal Bus Master Abort - set when a transaction initiated
+**  					by the ATU internal bus initiator interface ends in a Master-abort.
+**  06:05      00 2			Reserved.
+**  04          0 2			P_SERR# Detected - set when P_SERR# is detected on the PCI bus by the ATU.
+**  03          0 2			PCI Master Abort - set when a transaction initiated by
+**  					the ATU PCI initiator interface ends in a Master-abort.
+**  02          0 2			PCI Target Abort (master) - set when a transaction
+**  					initiated by the ATU PCI master interface ends in a Target-abort.
+**  01          0 2			PCI Target Abort (target) - set when the ATU interface, acting as a target,
+**  					terminates the transaction on the PCI bus with a target abort.
+**  00          0 2			PCI Master Parity Error - Master Parity Error - The ATU interface sets this bit under the following
+**  					conditions:
+**  					E The ATU asserted PERR# itself or the ATU observed PERR# asserted.
+**  					E And the ATU acted as the requester for the operation in which the error occurred.
+**  					E And the ATUCMD registers Parity Error Response bit is set
+**  					E Or (PCI-X Mode Only) the ATU received a Write Data Parity Error Message
+**  					E And the ATUCMD registers Parity Error Response bit is set
+***********************************************************************************
+***********************************************************************************
+**  ATU Interrupt Mask Register - ATUIMR
+**
+**  The ATU Interrupt Mask Register contains the control bit to enable and disable interrupts
+**  generated by the ATU.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:15     0 0000H			Reserved
+**  14        0 2			VPD Address Register Updated Mask - Controls the setting of bit 17 of the ATUISR and generation of the
+**  					ATU Configuration Register Write interrupt when a PCI bus write occurs to the VPDAR register.
+**  										0=Not Masked
+**  										1=Masked
+**  13        0 2			Reserved
+**  12        0 2			Configuration Register Write Mask - Controls the setting of bit 15 of the ATUISR and generation of the
+**  					ATU Configuration Register Write interrupt when a PCI bus write occurs to any ATU configuration register
+**  					except those covered by mask bit 11 and bit 14 of this register, and ATU BIST enable bit 3 of the ATUCR.
+**  					0=Not Masked
+**  					1=Masked
+**  11        1 2			ATU Inbound Memory Window 1 Base Updated Mask - Controls the setting of bit 14 of the ATUISR and
+**  					generation of the ATU Configuration Register Write interrupt when a PCI bus write occurs to either the
+**  					IABAR1 register or the IAUBAR1 register.
+**  					0=Not Masked
+**  					1=Masked
+**  10        0 2			Initiated Split Completion Error Message Interrupt Mask - Controls the setting of bit 13 of the ATUISR and
+**  					generation of the ATU Error interrupt when the ATU initiates a Split Completion Error Message.
+**  					0=Not Masked
+**  					1=Masked
+**  09        0 2			Received Split Completion Error Message Interrupt Mask- Controls the setting of bit 12 of the ATUISR
+**  					and generation of the ATU Error interrupt when a Split Completion Error Message results in bit 29 of the
+**  					PCIXSR being set.
+**  					0=Not Masked
+**  					1=Masked
+**  08        1 2			Power State Transition Interrupt Mask - Controls the setting of bit 12 of the ATUISR and generation of the
+**  					ATU Error interrupt when ATU Power Management Control/Status Register is written to transition the
+**  					ATU Function Power State from D0 to D3, D0 to D1, D1 to D3 or D3 to D0.
+**  					0=Not Masked
+**  					1=Masked
+**  07        0 2			ATU Detected Parity Error Interrupt Mask - Controls the setting of bit 9 of the ATUISR and generation of
+**  					the ATU Error interrupt when a parity error detected on the PCI bus that sets bit 15 of the ATUSR.
+**  					0=Not Masked
+**  					1=Masked
+**  06        0 2			ATU SERR# Asserted Interrupt Mask - Controls the setting of bit 10 of the ATUISR and generation of the
+**  					ATU Error interrupt when SERR# is asserted on the PCI interface resulting in bit 14 of the ATUSR being set.
+**  					0=Not Masked
+**  					1=Masked
+**  		NOTE: This bit is specific to the ATU asserting SERR# and not detecting SERR# from another master.
+**  05        0 2			ATU PCI Master Abort Interrupt Mask - Controls the setting of bit 3 of the ATUISR and generation of the
+**  					ATU Error interrupt when a master abort error resulting in bit 13 of the ATUSR being set.
+**  					0=Not Masked
+**  					1=Masked
+**  04        0 2			ATU PCI Target Abort (Master) Interrupt Mask- Controls the setting of bit 12 of the ATUISR and ATU Error
+**  					generation of the interrupt when a target abort error resulting in bit 12 of the ATUSR being set
+**  					0=Not Masked
+**  					1=Masked
+**  03        0 2			ATU PCI Target Abort (Target) Interrupt Mask- Controls the setting of bit 1 of the ATUISR and generation
+**  					of the ATU Error interrupt when a target abort error resulting in bit 11 of the ATUSR being set.
+**  					0=Not Masked
+**  					1=Masked
+**  02        0 2			ATU PCI Master Parity Error Interrupt Mask - Controls the setting of bit 0 of the ATUISR and generation
+**  					of the ATU Error interrupt when a parity error resulting in bit 8 of the ATUSR being set.
+**  					0=Not Masked
+**  					1=Masked
+**  01        0 2			ATU Inbound Error SERR# Enable - Controls when the ATU asserts (when enabled through the
+**  					ATUCMD) SERR# on the PCI interface in response to a master abort on the internal bus during an
+**  					inbound write transaction.
+**  					0=SERR# Not Asserted due to error
+**  					1=SERR# Asserted due to error
+**  00        0 2			ATU ECC Target Abort Enable - Controls the ATU response on the PCI interface to a target abort (ECC
+**  					error) from the memory controller on the internal bus. In conventional mode, this action only occurs
+**  					during an inbound read transaction where the data phase that was target aborted on the internal bus is
+**  					actually requested from the inbound read queue.
+**  					0=Disconnect with data (the data being up to 64 bits of 1s)
+**  					1=Target Abort
+**  	NOTE: In PCI-X Mode, The ATU initiates a Split Completion Error Message (with message class=2h -
+**  		completer error and message index=81h - 80331 internal bus target abort) on the PCI bus,
+**  		independent of the setting of this bit.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Base Address Register 3 - IABAR3
+**
+**  . The Inbound ATU Base Address Register 3 (IABAR3) together with the Inbound ATU Upper Base Address Register 3
+**    (IAUBAR3) defines the block of memory addresses where the inbound translation window 3 begins.
+**  . The inbound ATU decodes and forwards the bus request to the 80331 internal bus with a translated address to map into 80331 local memory.
+**  . The IABAR3 and IAUBAR3 define the base address and describes the required memory block size.
+**  . Bits 31 through 12 of the IABAR3 is either read/write bits or read only with a value of 0 depending on the value located within the IALR3.
+**    The programmed value within the base address register must comply with the PCI programming requirements for address alignment.
+**  Note:
+**      Since IABAR3 does not appear in the standard PCI configuration header space (offsets 00H - 3CH),
+**      IABAR3 is not configured by the host during normal system initialization.
+**  Warning:
+**    When a non-zero value is not written to IALR3,
+**                          the user should not set either the Prefetchable Indicator
+**                                                      or the Type         Indicator for 64 bit addressability.
+**                          This is the default for IABAR3.
+**  Assuming a non-zero value is written to IALR3,
+**                          the user may set the Prefetchable Indicator
+**                                        or the Type         Indicator:
+**  						a. Since non prefetchable memory windows can never be placed above the 4 Gbyte address boundary,
+**                             when the Prefetchable Indicator is not set,
+**                             the user should also leave the Type Indicator set for 32 bit addressability.
+**                             This is the default for IABAR3.
+**  						b. when the Prefetchable Indicator is set,
+**                             the user should also set the Type Indicator for 64 bit addressability.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Translation Base Address 3 - These bits define the actual location
+**  					the translation function is to respond to when addressed from the PCI bus.
+**  11:04        00H			Reserved.
+**  03           0 2			Prefetchable Indicator - When set, defines the memory space as prefetchable.
+**  02:01       00 2			Type Indicator - Defines the width of the addressability for this memory window:
+**  					00 - Memory Window is locatable anywhere in 32 bit address space
+**  					10 - Memory Window is locatable anywhere in 64 bit address space
+**  00           0 2			Memory Space Indicator - This bit field describes memory or I/O space base address.
+**  					The ATU does not occupy I/O space, thus this bit must be zero.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Upper Base Address Register 3 - IAUBAR3
+**
+**  This register contains the upper base address when decoding PCI addresses beyond 4 GBytes.
+**  Together with the Translation Base Address this register defines the actual location
+**  the translation function is to respond to when addressed from the PCI bus for addresses > 4GBytes (for DACs).
+**  The programmed value within the base address register must comply with the PCI programming
+**  requirements for address alignment.
+**  Note:
+**      When the Type indicator of IABAR3 is set to indicate 32 bit addressability,
+**      the IAUBAR3 register attributes are read-only.
+**      This is the default for IABAR3.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:0      00000H                        Translation Upper Base Address 3 -
+**  					Together with the Translation Base Address 3 these bits define the actual location
+**  					the translation function is to respond to when addressed from the PCI bus for addresses > 4GBytes.
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Limit Register 3 - IALR3
+**
+**  Inbound address translation for memory window 3 occurs for data transfers occurring from the PCI
+**  bus (originated from the PCI bus) to the 80331 internal bus. The address translation block converts
+**  PCI addresses to internal bus addresses.
+**  The inbound translation base address for inbound window 3 is specified in Section 3.10.15. When
+**  determining block size requirements X as described in Section 3.10.21 X the translation limit
+**  register provides the block size requirements for the base address register. The remaining registers
+**  used for performing address translation are discussed in Section 3.2.1.1.
+**  The 80331 translate value registers programmed value must be naturally aligned with the base
+**  address registers programmed value. The limit register is used as a mask; thus, the lower address
+**  bits programmed into the 80331 translate value register are invalid. Refer to the PCI Local Bus
+**  Specification, Revision 2.3 for additional information on programming base address registers.
+**  Bits 31 to 12 within the IALR3 have a direct effect on the IABAR3 register, bits 31 to 12, with a
+**  one to one correspondence. A value of 0 in a bit within the IALR3 makes the corresponding bit
+**  within the IABAR3 a read only bit which always returns 0. A value of 1 in a bit within the IALR3
+**  makes the corresponding bit within the IABAR3 read/write from PCI. Note that a consequence of
+**  this programming scheme is that unless a valid value exists within the IALR3, all writes to the
+**  IABAR3 has no effect since a value of all zeros within the IALR3 makes the IABAR3 a read only
+**  register.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Inbound Translation Limit 3 - This readback value determines
+**  					the memory block size required for the ATUs memory window 3.
+**  11:00       000H                        Reserved
+***********************************************************************************
+***********************************************************************************
+**  Inbound ATU Translate Value Register 3 - IATVR3
+**
+**  The Inbound ATU Translate Value Register 3 (IATVR3) contains the internal bus address used to
+**  convert PCI bus addresses. The converted address is driven on the internal bus as a result of the
+**  inbound ATU address translation.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     00000H			Inbound ATU Translation Value 3 - This value is used to
+**  					convert the PCI address to internal bus addresses.
+**  					This value must be 64-bit aligned on the internal bus. The default address allows the ATU to
+**  					access the internal 80331 memory-mapped registers.
+**  11:00       000H			Reserved
+***********************************************************************************
+***********************************************************************************
+**  Outbound Configuration Cycle Address Register - OCCAR
+**
+**  The Outbound Configuration Cycle Address Register is used to hold the 32-bit PCI configuration
+**  cycle address. The Intel XScale core writes the PCI configuration cycles address which then
+**  enables the outbound configuration read or write. The Intel XScale core then performs a read or
+**  write to the Outbound Configuration Cycle Data Register to initiate the configuration cycle on the
+**  PCI bus.
+**  Note: Bits 15:11 of the configuration cycle address for Type 0 configuration cycles are defined differently
+**  for Conventional versus PCI-X modes. When 80331 software programs the OCCAR to initiate a
+**  Type 0 configuration cycle, the OCCAR should always be loaded based on the PCI-X definition for
+**  the Type 0 configuration cycle address. When operating in Conventional mode, the 80331 clears
+**  bits 15:11 of the OCCAR prior to initiating an outbound Type 0 configuration cycle. See the PCI-X
+**  Addendum to the PCI Local Bus Specification, Revision 1.0a for details on the two formats.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00    0000 0000H		Configuration Cycle Address -
+**  					These bits define the 32-bit PCI address used
+**  					during an outbound configuration read or write cycle.
+***********************************************************************************
+***********************************************************************************
+**  Outbound Configuration Cycle Data Register - OCCDR
+**
+**  The Outbound Configuration Cycle Data Register is used to initiate a configuration read or write
+**  on the PCI bus. The register is logical rather than physical meaning that it is an address not a
+**  register. The Intel XScale core reads or writes the data registers memory-mapped address to
+**  initiate the configuration cycle on the PCI bus with the address found in the OCCAR. For a
+**  configuration write, the data is latched from the internal bus and forwarded directly to the OWQ.
+**  For a read, the data is returned directly from the ORQ to the Intel XScale core and is never
+**  actually entered into the data register (which does not physically exist).
+**  The OCCDR is only visible from 80331 internal bus address space and appears as a reserved value
+**  within the ATU configuration space.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00    0000 0000H            Configuration Cycle Data - These bits define the data used
+**					during an outbound configuration read or write cycle.
+***********************************************************************************
+***********************************************************************************
+**  VPD Capability Identifier Register - VPD_CAPID
+**
+**  The Capability Identifier Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register in the PCI Extended Capability header identifies the type of Extended
+**  Capability contained in that header. In the case of the 80331, this is the VPD extended capability
+**  with an ID of 03H as defined by the PCI Local Bus Specification, Revision 2.3.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       03H			Cap_Id - This field with its 03H value
+**  					identifies this item in the linked list of Extended Capability
+**  					Headers as being the VPD capability registers.
+***********************************************************************************
+***********************************************************************************
+**  VPD Next Item Pointer Register - VPD_NXTP
+**
+**  The Next Item Pointer Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register describes the location of the next item in the functions capability list.
+**  For the 80331, this the final capability list, and hence, this register is set to 00H.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       00H			Next_ Item_ Pointer - This field provides an offset into
+**  					the functions configuration space pointing to the
+**  					next item in the functions capability list. Since the VPD
+**  					capabilities are the last in the linked list of
+**  					extended capabilities in the 80331, the register is set to 00H.
+***********************************************************************************
+***********************************************************************************
+**  VPD Address Register - VPD_AR
+**
+**  The VPD Address register (VPDAR) contains the DWORD-aligned byte address of the VPD to be
+**  accessed. The register is read/write and the initial value at power-up is indeterminate.
+**  A PCI Configuration Write to the VPDAR interrupts the Intel XScale core. Software can use
+**  the Flag setting to determine whether the configuration write was intended to initiate a read or
+**  write of the VPD through the VPD Data Register.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15          0 2			Flag - A flag is used to indicate when a transfer of data
+**  					between the VPD Data Register and the storage
+**  					component has completed. Please see Section 3.9,
+**  					Vital Product Data on page 201 for more details on
+**  					how the 80331 handles the data transfer.
+**  14:0       0000H			VPD Address - This register is written to set the DWORD-aligned
+**  					byte address used to read or write
+**  					Vital Product Data from the VPD storage component.
+***********************************************************************************
+***********************************************************************************
+**  VPD Data Register - VPD_DR
+**
+**  This register is used to transfer data between the 80331 and the VPD storage component.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00      0000H			VPD Data - Four bytes are always read or written through
+**					this register to/from the VPD storage component.
+***********************************************************************************
+***********************************************************************************
+**  Power Management Capability Identifier Register -PM_CAPID
+**
+**  The Capability Identifier Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register in the PCI Extended Capability header identifies the type of Extended
+**  Capability contained in that header. In the case of the 80331, this is the PCI Bus Power
+**  Management extended capability with an ID of 01H as defined by the PCI Bus Power Management
+**  Interface Specification, Revision 1.1.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       01H			Cap_Id - This field with its 01H value identifies this item in the linked list
+**  					of Extended Capability Headers as being the PCI Power Management Registers.
+***********************************************************************************
+***********************************************************************************
+**  Power Management Next Item Pointer Register - PM_NXTP
+**
+**  The Next Item Pointer Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register describes the location of the next item in the functions capability list.
+**  For the 80331, the next capability (MSI capability list) is located at off-set D0H.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       D0H			Next_ Item_ Pointer - This field provides an offset into the functions
+**  					configuration space pointing to the
+**  					next item in the functions capability list which in
+**  					the 80331 is the MSI extended capabilities header.
+***********************************************************************************
+***********************************************************************************
+**  Power Management Capabilities Register - PM_CAP
+**
+**  Power Management Capabilities bits adhere to the definitions in the PCI Bus Power Management
+**  Interface Specification, Revision 1.1. This register is a 16-bit read-only register which provides
+**  information on the capabilities of the ATU function related to power management.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:11   00000 2                         PME_Support - This function is not capable of asserting
+**						  the PME# signal in any state, since PME# is not supported by the 80331.
+**  10          0 2                         D2_Support - This bit is set to 0 2 indicating that the 80331
+**						  does not support the D2 Power Management State
+**  9           1 2                         D1_Support - This bit is set to 1 2 indicating that the 80331
+**						  supports the D1 Power Management State
+**  8:6       000 2                         Aux_Current - This field is set to 000 2 indicating that the 80331
+**						  has no current requirements for the
+**						  3.3Vaux signal as defined in the PCI Bus Power Management
+**						  Interface Specification, Revision 1.1
+**  5           0 2                         DSI - This field is set to 0 2 meaning that this function
+**						  requires a device specific initialization sequence
+**						  following the transition to the D0 uninitialized state.
+**  4           0 2                         Reserved.
+**  3           0 2                         PME Clock - Since the 80331 does not support PME# signal
+**						  generation this bit is cleared to 0 2 .
+**  2:0       010 2                         Version - Setting these bits to 010 2 means that
+**						  this function complies with PCI Bus Power Management
+**						  Interface Specification, Revision 1.1
+***********************************************************************************
+***********************************************************************************
+**  Power Management Control/Status Register - PM_CSR
+**
+**  Power Management Control/Status bits adhere to the definitions in the PCI Bus Power
+**  Management Interface Specification, Revision 1.1. This 16-bit register is the control and status
+**  interface for the power management extended capability.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15          0 2                       PME_Status - This function is not capable of
+**  						asserting the PME# signal in any state, since PME## is not supported by the 80331.
+**  14:9        00H                       Reserved
+**  8           0 2                       PME_En - This bit is hardwired to read-only 0 2 since
+**  						this function does not support PME# generation from any power state.
+**  7:2    000000 2                       Reserved
+**  1:0        00 2                       Power State - This 2-bit field is used both
+**  						to determine the current power state of a function
+**  						and to set the function into a new power state. The definition of the values is:
+**  									00 2 - D0
+**  									01 2 - D1
+**  									10 2 - D2 (Unsupported)
+**  									11 2 - D3 hot
+**  									The 80331 supports only the D0 and D3 hot states.
+**
+***********************************************************************************
+***********************************************************************************
+**  PCI-X Capability Identifier Register - PX_CAPID
+**
+**  The Capability Identifier Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register in the PCI Extended Capability header identifies the type of Extended
+**  Capability contained in that header. In the case of the 80331, this is the PCI-X extended capability with
+**  an ID of 07H as defined by the PCI-X Addendum to the PCI Local Bus Specification, Revision 1.0a.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       07H                       Cap_Id - This field with its 07H value
+**  						identifies this item in the linked list of Extended Capability
+**  						Headers as being the PCI-X capability registers.
+***********************************************************************************
+***********************************************************************************
+**  PCI-X Next Item Pointer Register - PX_NXTP
+**
+**  The Next Item Pointer Register bits adhere to the definitions in the PCI Local Bus Specification,
+**  Revision 2.3. This register describes the location of the next item in the functions capability list.
+**  By default, the PCI-X capability is the last capabilities list for the 80331, thus this register defaults
+**  to 00H.
+**  However, this register may be written to B8H prior to host configuration to include the VPD
+**  capability located at off-set B8H.
+**  Warning: Writing this register to any value other than 00H (default) or B8H is not supported and may
+**  produce unpredictable system behavior.
+**  In order to guarantee that this register is written prior to host configuration, the 80331 must be
+**  initialized at P_RST# assertion to Retry Type 0 configuration cycles (bit 2 of PCSR). Typically,
+**  the Intel XScale core would be enabled to boot immediately following P_RST# assertion in
+**  this case (bit 1 of PCSR), as well. Please see Table 125, PCI Configuration and Status Register -
+**  PCSR on page 253 for more details on the 80331 initialization modes.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  07:00       00H                       Next_ Item_ Pointer - This field provides an offset
+**  						into the functions configuration space pointing to the
+**  						next item in the functions capability list.
+**  						Since the PCI-X capabilities are the last in the linked list of
+**  						extended capabilities in the 80331, the register is set to 00H.
+**  						However, this field may be written prior to host configuration
+**  						with B8H to extend the list to include the
+**  						VPD extended capabilities header.
+***********************************************************************************
+***********************************************************************************
+**  PCI-X Command Register - PX_CMD
+**
+**  This register controls various modes and features of ATU and Message Unit when operating in the
+**  PCI-X mode.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  15:7     000000000 2                  Reserved.
+**  6:4        011 2                      Maximum Outstanding Split Transactions - This register
+**  						sets the maximum number of Split Transactions
+**  						the device is permitted to have outstanding at one time.
+**  						Register Maximum Outstanding
+**  						0 1
+**  						1 2
+**  						2 3
+**  						3 4
+**  						4 8
+**  						5 12
+**  						6 16
+**  						7 32
+**  3:2        00 2                       Maximum Memory Read Byte Count - This register sets
+**  						the maximum byte count the device uses when
+**  						initiating a Sequence with one of the burst memory read commands.
+**  						Register Maximum Byte Count
+**  						0 512
+**  						1 1024
+**  						2 2048
+**  						3 4096
+**  						1 0 2
+**  						Enable Relaxed Ordering - The 80331 does not set
+**  						the relaxed ordering bit in the Requester Attributes of Transactions.
+**  0          0 2                        Data Parity Error Recovery Enable - The device driver sets
+**  						this bit to enable the device to attempt to
+**  						recover from data parity errors. When this bit is 0
+**  						and the device is in PCI-X mode, the device asserts
+**  						SERR# (when enabled) whenever the Master Data Parity Error bit
+**  						(Status register, bit 8) is set.
+***********************************************************************************
+***********************************************************************************
+**  PCI-X Status Register - PX_SR
+**
+**  This register identifies the capabilities and current operating mode of ATU, DMAs and Message
+**  Unit when operating in the PCI-X mode.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:30       00 2                      Reserved
+**  29           0 2                      Received Split Completion Error Message -
+**  						This bit is set when the device receives a Split Completion
+**  						Message with the Split Completion Error attribute bit set.
+**  						Once set, this bit remains set until software
+**  						writes a 1 to this location.
+**  							0=no Split Completion error message received.
+**  							1=a Split Completion error message has been received.
+**  28:26      001 2                      Designed Maximum Cumulative Read Size (DMCRS) -
+**  						The value of this register depends on the setting
+**  						of the Maximum Memory Read Byte Count field of the PCIXCMD register:
+**  						DMCRS Max ADQs Maximum Memory Read Byte Count Register Setting
+**  										1 16 512 (Default)
+**  										2 32 1024
+**  										2 32 2048
+**  										2 32 4096
+**  25:23      011 2                      Designed Maximum Outstanding Split Transactions -
+**  						The 80331 can have up to four outstanding split transactions.
+**  22:21       01 2                      Designed Maximum Memory Read Byte Count -
+**  						The 80331 can generate memory reads with byte counts up to 1024 bytes.
+**  20           1 2                      80331 is a complex device.
+**  19           0 2                      Unexpected Split Completion -
+**  						This bit is set when an unexpected Split Completion with this devices
+**  						Requester ID is received. Once set, this bit
+**  						remains set until software writes a 1 to this location.
+**  							0=no unexpected Split Completion has been received.
+**  							1=an unexpected Split Completion has been received.
+**  18           0 2                      Split Completion Discarded - This bit is set
+**  						when the device discards a Split Completion because the
+**  						requester would not accept it.
+**  						See Section 5.4.4 of the PCI-X Addendum to the PCI Local Bus
+**  						Specification, Revision 1.0a for details. Once set,
+**  						this bit remains set until software writes a 1 to this
+**  								location.
+**  								0=no Split Completion has been discarded.
+**  								1=a Split Completion has been discarded.
+**  		NOTE: The 80331 does not set this bit since there is no Inbound address responding
+**  			to Inbound Read Requests with Split Responses (Memory or Register) that has read side effects.
+**  17           1 2                      80331 is a 133 MHz capable device.
+**  16           1 2 or P_32BITPCI#	80331 with bridge enabled (BRG_EN=1)
+**  						implements the ATU with a 64-bit interface
+**  						on the secondary PCI bus, therefore this bit is always set.
+**                              		80331 with no bridge and central resource disabled (BRG_EN=0, ARB_EN=0),
+**  						use this bit to identify the add-in card to the system
+**  						as 64-bit or 32-bit wide via a user-configurable strap (P_32BITPCI#).
+**  						This strap, by default, identifies the add in card based
+**  						on 80331 with bridge disabled as 64-bit unless
+**  						the user attaches the appropriate pull-down resistor to the strap.
+**  						0=The bus is 32 bits wide.
+**  						1=The bus is 64 bits wide.
+**  15:8         FFH                      Bus Number - This register is read for diagnostic purposes only.
+**  						It indicates the number of the bus
+**  						segment for the device containing this function.
+**  						The function uses this number as part of its Requester
+**  						ID and Completer ID. For all devices other than the source bridge,
+**  						each time the function is addressed
+**  						by a Configuration Write transaction,
+**  						the function must update this register with the contents of AD[7::0]
+**  						of the attribute phase of the Configuration Write,
+**  						regardless of which register in the function is
+**  						addressed by the transaction.
+**  						The function is addressed by a Configuration
+**  						Write transaction when all of the following are true:
+**  						1. The transaction uses a Configuration Write command.
+**  						2. IDSEL is asserted during the address phase.
+**  						3. AD[1::0] are 00b (Type 0 configuration transaction).
+**  						4. AD[10::08] of the configuration address contain the appropriate function number.
+**  7:3          1FH                      Device Number - This register is read for diagnostic purposes only.
+**  						It indicates the number of the device
+**  						containing this function, i.e.,
+**  						the number in the Device Number field (AD[15::11])
+**  						of the address of a Type 0 configuration transaction
+**  						that is assigned to the device containing this function by the connection
+**  						of the system hardware. The system must assign
+**  						a device number other than 00h (00h is reserved for
+**  						the source bridge). The function uses this number as part of
+**  						its Requester ID and Completer ID. Each time the
+**  						function is addressed by a Configuration Write transaction,
+**  						the device must update this register
+**  						with the contents of AD[15::11] of the address phase
+**  						of the Configuration Write, regardless of which
+**  						register in the function is addressed by the transaction.
+**  						The function is addressed by a Configuration
+**  						Write transaction when all of the following are true:
+**  						1. The transaction uses a Configuration Write command.
+**  						2. IDSEL is asserted during the address phase.
+**  						3. AD[1::0] are 00b (Type 0 configuration transaction).
+**  						4. AD[10::08] of the configuration address contain the appropriate function number.
+**  2:0        000 2                      Function Number - This register is read for
+**  						diagnostic purposes only. It indicates the number of this
+**  						function; i.e.,
+**  						the number in the Function Number field (AD[10::08])
+**  						of the address of a Type 0 configuration transaction
+**  						to which this function responds. The function uses this number as part of its
+**  						Requester ID and Completer ID.
+**
+**************************************************************************
+**************************************************************************
+**                 Inbound Read Transaction
+**  ========================================================================
+**	An inbound read transaction is initiated by a PCI initiator and is targeted at either 80331 local
+**	memory or a 80331 memory-mapped register space. The read transaction is propagated through
+**	the inbound transaction queue (ITQ) and read data is returned through the inbound read queue
+**	(IRQ).
+**	When operating in the conventional PCI mode, all inbound read transactions are processed as
+**	delayed read transactions. When operating in the PCI-X mode, all inbound read transactions are
+**	processed as split transactions. The ATUs PCI interface claims the read transaction and forwards
+**	the read request through to the internal bus and returns the read data to the PCI bus. Data flow for
+**	an inbound read transaction on the PCI bus is summarized in the following statements:
+**	E The ATU claims the PCI read transaction when the PCI address is within the inbound
+**	translation window defined by ATU Inbound Base Address Register (and Inbound Upper Base
+**	Address Register during DACs) and Inbound Limit Register.
+**	E When operating in the conventional PCI mode, when the ITQ is currently holding transaction
+**	information from a previous delayed read, the current transaction information is compared to
+**	the previous transaction information (based on the setting of the DRC Alias bit in
+**	Section 3.10.39, ATU Configuration Register - ATUCR on page 252). When there is a
+**	match and the data is in the IRQ, return the data to the master on the PCI bus. When there is a
+**	match and the data is not available, a Retry is signaled with no other action taken. When there
+**	is not a match and when the ITQ has less than eight entries, capture the transaction
+**	information, signal a Retry and initiate a delayed transaction. When there is not a match and
+**	when the ITQ is full, then signal a Retry with no other action taken.
+**	X When an address parity error is detected, the address parity response defined in
+**	Section 3.7 is used.
+**	E When operating in the conventional PCI mode, once read data is driven onto the PCI bus from
+**	the IRQ, it continues until one of the following is true:
+**	X The initiator completes the PCI transaction. When there is data left unread in the IRQ, the
+**	data is flushed.
+**	X An internal bus Target Abort was detected. In this case, the QWORD associated with the
+**	Target Abort is never entered into the IRQ, and therefore is never returned.
+**	X Target Abort or a Disconnect with Data is returned in response to the Internal Bus Error.
+**	X The IRQ becomes empty. In this case, the PCI interface signals a Disconnect with data to
+**	the initiator on the last data word available.
+**	E When operating in the PCI-X mode, when ITQ is not full, the PCI address, attribute and
+**	command are latched into the available ITQ and a Split Response Termination is signalled to
+**	the initiator.
+**	E When operating in the PCI-X mode, when the transaction does not cross a 1024 byte aligned
+**	boundary, then the ATU waits until it receives the full byte count from the internal bus target
+**	before returning read data by generating the split completion transaction on the PCI-X bus.
+**	When the read requested crosses at least one 1024 byte boundary, then ATU completes the
+**	transfer by returning data in 1024 byte aligned chunks.
+**	E When operating in the PCI-X mode, once a split completion transaction has started, it
+**	continues until one of the following is true:
+**	X The requester (now the target) generates a Retry Termination, or a Disconnection at Next
+**	ADB (when the requester is a bridge)
+**	X The byte count is satisfied.
+**	X An internal bus Target Abort was detected. The ATU generates a Split Completion
+**	Message (message class=2h - completer error, and message index=81h - target abort) to
+**	inform the requester about the abnormal condition. The ITQ for this transaction is flushed.
+**	Refer to Section 3.7.1.
+**	X An internal bus Master Abort was detected. The ATU generates a Split Completion
+**	Message (message class=2h - completer error, and message index=80h - Master abort) to
+**	inform the requester about the abnormal condition. The ITQ for this transaction is flushed.
+**	Refer to Section 3.7.1
+**	E When operating in the conventional PCI mode, when the master inserts wait states on the PCI
+**	bus, the ATU PCI slave interface waits with no premature disconnects.
+**	E When a data parity error occurs signified by PERR# asserted from the initiator, no action is
+**	taken by the target interface. Refer to Section 3.7.2.5.
+**	E When operating in the conventional PCI mode, when the read on the internal bus is
+**	target-aborted, either a target-abort or a disconnect with data is signaled to the initiator. This is
+**	based on the ATU ECC Target Abort Enable bit (bit 0 of the ATUIMR for ATU). When set, a
+**	target abort is used, when clear, a disconnect is used.
+**	E When operating in the PCI-X mode (with the exception of the MU queue ports at offsets 40h
+**	and 44h), when the transaction on the internal bus resulted in a target abort, the ATU generates
+**	a Split Completion Message (message class=2h - completer error, and message index=81h -
+**	internal bus target abort) to inform the requester about the abnormal condition. For the MU
+**	queue ports, the ATU returns either a target abort or a single data phase disconnect depending
+**	on the ATU ECC Target Abort Enable bit (bit 0 of the ATUIMR for ATU). The ITQ for this
+**	transaction is flushed. Refer to Section 3.7.1.
+**	E When operating in the conventional PCI mode, when the transaction on the internal bus
+**	resulted in a master abort, the ATU returns a target abort to inform the requester about the
+**	abnormal condition. The ITQ for this transaction is flushed. Refer to Section 3.7.1
+**	E When operating in the PCI-X mode, when the transaction on the internal bus resulted in a
+**	master abort, the ATU generates a Split Completion Message (message class=2h - completer
+**	error, and message index=80h - internal bus master abort) to inform the requester about the
+**	abnormal condition. The ITQ for this transaction is flushed. Refer to Section 3.7.1.
+**	E When operating in the PCI-X mode, when the Split Completion transaction completes with
+**	either Master-Abort or Target-Abort, the requester is indicating a failure condition that
+**	prevents it from accepting the completion it requested. In this case, since the Split Request
+**	addresses a location that has no read side effects, the completer must discard the Split
+**	Completion and take no further action.
+**	The data flow for an inbound read transaction on the internal bus is summarized in the following
+**	statements:
+**	E The ATU internal bus master interface requests the internal bus when a PCI address appears in
+**		an ITQ and transaction ordering has been satisfied. When operating in the PCI-X mode the
+**		ATU does not use the information provided by the Relax Ordering Attribute bit. That is, ATU
+**		always uses conventional PCI ordering rules.
+**	E Once the internal bus is granted, the internal bus master interface drives the translated address
+**		onto the bus and wait for IB_DEVSEL#. When a Retry is signaled, the request is repeated.
+**		When a master abort occurs, the transaction is considered complete and a target abort is loaded
+**		into the associated IRQ for return to the PCI initiator (transaction is flushed once the PCI
+**		master has been delivered the target abort).
+**	E Once the translated address is on the bus and the transaction has been accepted, the internal
+**		bus target starts returning data with the assertion of IB_TRDY#. Read data is continuously
+**		received by the IRQ until one of the following is true:
+**	X The full byte count requested by the ATU read request is received. The ATU internal bus
+**	    initiator interface performs a initiator completion in this case.
+**	X When operating in the conventional PCI mode, a Target Abort is received on the internal
+**		bus from the internal bus target. In this case, the transaction is aborted and the PCI side is
+**		informed.
+**	X When operating in the PCI-X mode, a Target Abort is received on the internal bus from
+**		the internal bus target. In this case, the transaction is aborted. The ATU generates a Split
+**		Completion Message (message class=2h - completer error, and message index=81h -
+**		target abort) on the PCI bus to inform the requester about the abnormal condition. The
+**		ITQ for this transaction is flushed.
+**	X When operating in the conventional PCI mode, a single data phase disconnection is
+**		received from the internal bus target. When the data has not been received up to the next
+**		QWORD boundary, the ATU internal bus master interface attempts to reacquire the bus.
+**		When not, the bus returns to idle.
+**	X When operating in the PCI-X mode, a single data phase disconnection is received from
+**		the internal bus target. The ATU IB initiator interface attempts to reacquire the bus to
+**		obtain remaining data.
+**	X When operating in the conventional PCI mode, a disconnection at Next ADB is received
+**	    from the internal bus target. The bus returns to idle.
+**	X When operating in the PCI-X mode, a disconnection at Next ADB is received from the
+**		internal bus target. The ATU IB initiator interface attempts to reacquire the bus to obtain
+**		remaining data.
+**		To support PCI Local Bus Specification, Revision 2.0 devices, the ATU can be programmed to
+**		ignore the memory read command (Memory Read, Memory Read Line, and Memory Read
+**		Multiple) when trying to match the current inbound read transaction with data in a DRC queue
+**		which was read previously (DRC on target bus). When the Read Command Alias Bit in the
+**		ATUCR register is set, the ATU does not distinguish the read commands on transactions. For
+**		example, the ATU enqueues a DRR with a Memory Read Multiple command and performs the read
+**		on the internal bus. Some time later, a PCI master attempts a Memory Read with the same address
+**		as the previous Memory Read Multiple. When the Read Command Bit is set, the ATU would return
+**		the read data from the DRC queue and consider the Delayed Read transaction complete. When the
+**		Read Command bit in the ATUCR was clear, the ATU would not return data since the PCI read
+**		commands did not match, only the address.
+**************************************************************************
+**************************************************************************
+**                    Inbound Write Transaction
+**========================================================================
+**	  An inbound write transaction is initiated by a PCI master and is targeted at either 80331 local
+**	  memory or a 80331 memory-mapped register.
+**	Data flow for an inbound write transaction on the PCI bus is summarized as:
+**	E The ATU claims the PCI write transaction when the PCI address is within the inbound
+**	  translation window defined by the ATU Inbound Base Address Register (and Inbound Upper
+**	  Base Address Register during DACs) and Inbound Limit Register.
+**	E When the IWADQ has at least one address entry available and the IWQ has at least one buffer
+**	  available, the address is captured and the first data phase is accepted.
+**	E The PCI interface continues to accept write data until one of the following is true:
+**	  X The initiator performs a disconnect.
+**	  X The transaction crosses a buffer boundary.
+**	E When an address parity error is detected during the address phase of the transaction, the
+**	  address parity error mechanisms are used. Refer to Section 3.7.1 for details of the address
+**	  parity error response.
+**	E When operating in the PCI-X mode when an attribute parity error is detected, the attribute
+**	  parity error mechanism described in Section 3.7.1 is used.
+**	E When a data parity error is detected while accepting data, the slave interface sets the
+**	  appropriate bits based on PCI specifications. No other action is taken. Refer to Section 3.7.2.6
+**	  for details of the inbound write data parity error response.
+**	  Once the PCI interface places a PCI address in the IWADQ, when IWQ has received data sufficient
+**	  to cross a buffer boundary or the master disconnects on the PCI bus, the ATUs internal bus
+**	  interface becomes aware of the inbound write. When there are additional write transactions ahead
+**	  in the IWQ/IWADQ, the current transaction remains posted until ordering and priority have been
+**	  satisfied (Refer to Section 3.5.3) and the transaction is attempted on the internal bus by the ATU
+**	  internal master interface. The ATU does not insert target wait states nor do data merging on the PCI
+**	  interface, when operating in the PCI mode.
+**	  In the PCI-X mode memory writes are always executed as immediate transactions, while
+**	  configuration write transactions are processed as split transactions. The ATU generates a Split
+**	  Completion Message, (with Message class=0h - Write Completion Class and Message index =
+**	  00h - Write Completion Message) once a configuration write is successfully executed.
+**	  Also, when operating in the PCI-X mode a write sequence may contain multiple write transactions.
+**	  The ATU handles such transactions as independent transactions.
+**	  Data flow for the inbound write transaction on the internal bus is summarized as:
+**	E The ATU internal bus master requests the internal bus when IWADQ has at least one entry
+**	  with associated data in the IWQ.
+**	E When the internal bus is granted, the internal bus master interface initiates the write
+**	  transaction by driving the translated address onto the internal bus. For details on inbound
+**	  address translation.
+**	E When IB_DEVSEL# is not returned, a master abort condition is signaled on the internal bus.
+**	  The current transaction is flushed from the queue and SERR# may be asserted on the PCI
+**	  interface.
+**	E The ATU initiator interface asserts IB_REQ64# to attempt a 64-bit transfer. When
+**	  IB_ACK64# is not returned, a 32-bit transfer is used. Transfers of less than 64-bits use the
+**	  IB_C/BE[7:0]# to mask the bytes not written in the 64-bit data phase. Write data is transferred
+**	  from the IWQ to the internal bus when data is available and the internal bus interface retains
+**	  internal bus ownership.
+**	E The internal bus interface stops transferring data from the current transaction to the internal
+**	  bus when one of the following conditions becomes true:
+**	X The internal bus initiator interface loses bus ownership. The ATU internal initiator
+**	  terminates the transfer (initiator disconnection) at the next ADB (for the internal bus ADB
+**	  is defined as a naturally aligned 128-byte boundary) and attempt to reacquire the bus to
+**	  complete the delivery of remaining data using the same sequence ID but with the
+**	  modified starting address and byte count.
+**	X A Disconnect at Next ADB is signaled on the internal bus from the internal target. When
+**	  the transaction in the IWQ completes at that ADB, the initiator returns to idle. When the
+**	  transaction in the IWQ is not complete, the initiator attempts to reacquire the bus to
+**	  complete the delivery of remaining data using the same sequence ID but with the
+**	  modified starting address and byte count.
+**	X A Single Data Phase Disconnect is signaled on the internal bus from the internal target.
+**	  When the transaction in the IWQ needs only a single data phase, the master returns to idle.
+**	  When the transaction in the IWQ is not complete, the initiator attempts to reacquire the
+**	  bus to complete the delivery of remaining data using the same sequence ID but with the
+**	  modified starting address and byte count.
+**	X The data from the current transaction has completed (satisfaction of byte count). An
+**	  initiator termination is performed and the bus returns to idle.
+**	X A Master Abort is signaled on the internal bus. SERR# may be asserted on the PCI bus.
+**	  Data is flushed from the IWQ.
+*****************************************************************
+**************************************************************************
+**               Inbound Read Completions Data Parity Errors
+**========================================================================
+**	As an initiator, the ATU may encounter this error condition when operating in the PCI-X mode.
+**	When as the completer of a Split Read Request the ATU observes PERR# assertion during the split
+**	completion transaction, the ATU attempts to complete the transaction normally and no further
+**	action is taken.
+**************************************************************************
+**************************************************************************
+**               Inbound Configuration Write Completion Message Data Parity Errors
+**========================================================================
+**  As an initiator, the ATU may encounter this error condition when operating in the PCI-X mode.
+**  When as the completer of a Configuration (Split) Write Request the ATU observes PERR#
+**  assertion during the split completion transaction, the ATU attempts to complete the transaction
+**  normally and no further action is taken.
+**************************************************************************
+**************************************************************************
+**              Inbound Read Request Data Parity Errors
+**===================== Immediate Data Transfer ==========================
+**  As a target, the ATU may encounter this error when operating in the Conventional PCI or PCI-X modes.
+**  Inbound read data parity errors occur when read data delivered from the IRQ is detected as having
+**  bad parity by the initiator of the transaction who is receiving the data. The initiator may optionally
+**  report the error to the system by asserting PERR#. As a target device in this scenario, no action is
+**  required and no error bits are set.
+**=====================Split Response Termination=========================
+**  As a target, the ATU may encounter this error when operating in the PCI-X mode.
+**  Inbound read data parity errors occur during the Split Response Termination. The initiator may
+**  optionally report the error to the system by asserting PERR#. As a target device in this scenario, no
+**  action is required and no error bits are set.
+**************************************************************************
+**************************************************************************
+**              Inbound Write Request Data Parity Errors
+**========================================================================
+**	As a target, the ATU may encounter this error when operating in the Conventional or PCI-X modes.
+**	Data parity errors occurring during write operations received by the ATU may assert PERR# on
+**	the PCI Bus. When an error occurs, the ATU continues accepting data until the initiator of the write
+**	transaction completes or a queue fill condition is reached. Specifically, the following actions with
+**	the given constraints are taken by the ATU:
+**	E PERR# is asserted two clocks cycles (three clock cycles when operating in the PCI-X mode)
+**	following the data phase in which the data parity error is detected on the bus. This is only
+**	done when the Parity Error Response bit in the ATUCMD is set.
+**	E The Detected Parity Error bit in the ATUSR is set. When the ATU sets this bit, additional
+**	actions is taken:
+**	X When the ATU Detected Parity Error Interrupt Mask bit in the ATUIMR is clear, set the
+**	Detected Parity Error bit in the ATUISR. When set, no action.
+***************************************************************************
+***************************************************************************
+**                 Inbound Configuration Write Request
+**  =====================================================================
+**  As a target, the ATU may encounter this error when operating in the Conventional or PCI-X modes.
+**  ===============================================
+**              Conventional PCI Mode
+**  ===============================================
+**  To allow for correct data parity calculations for delayed write transactions, the ATU delays the
+**  assertion of STOP# (signalling a Retry) until PAR is driven by the master. A parity error during a
+**  delayed write transaction (inbound configuration write cycle) can occur in any of the following
+**  parts of the transactions:
+**  E During the initial Delayed Write Request cycle on the PCI bus when the ATU latches the
+**  address/command and data for delayed delivery to the internal configuration register.
+**  E During the Delayed Write Completion cycle on the PCI bus when the ATU delivers the status
+**  of the operation back to the original master.
+**  The 80331 ATU PCI interface has the following responses to a delayed write parity error for
+**  inbound transactions during Delayed Write Request cycles with the given constraints:
+**  E When the Parity Error Response bit in the ATUCMD is set, the ATU asserts TRDY#
+**  (disconnects with data) and two clock cycles later asserts PERR# notifying the initiator of the
+**  parity error. The delayed write cycle is not enqueued and forwarded to the internal bus.
+**  When the Parity Error Response bit in the ATUCMD is cleared, the ATU retries the
+**  transaction by asserting STOP# and enqueues the Delayed Write Request cycle to be
+**  forwarded to the internal bus. PERR# is not asserted.
+**  E The Detected Parity Error bit in the ATUSR is set. When the ATU sets this bit, additional
+**  actions is taken:
+**  X When the ATU Detected Parity Error Interrupt Mask bit in the ATUIMR is clear, set the
+**  Detected Parity Error bit in the ATUISR. When set, no action.
+**  For the original write transaction to be completed, the initiator retries the transaction on the PCI
+**  bus and the ATU returns the status from the internal bus, completing the transaction.
+**  For the Delayed Write Completion transaction on the PCI bus where a data parity error occurs and
+**  therefore does not agree with the status being returned from the internal bus (i.e. status being
+**  returned is normal completion) the ATU performs the following actions with the given constraints:
+**  E When the Parity Error Response Bit is set in the ATUCMD, the ATU asserts TRDY#
+**  (disconnects with data) and two clocks later asserts PERR#. The Delayed Completion cycle in
+**  the IDWQ remains since the data of retried command did not match the data within the queue.
+**  E The Detected Parity Error bit in the ATUSR is set. When the ATU sets this bit, additional
+**  actions is taken:
+**  X When the ATU Detected Parity Error Interrupt Mask bit in the ATUIMR is clear, set the
+**  Detected Parity Error bit in the ATUISR. When set, no action.
+**  ===================================================
+**                       PCI-X Mode
+**  ===================================================
+**  Data parity errors occurring during configuration write operations received by the ATU may cause
+**  PERR# assertion and delivery of a Split Completion Error Message on the PCI Bus. When an error
+**  occurs, the ATU accepts the write data and complete with a Split Response Termination.
+**  Specifically, the following actions with the given constraints are then taken by the ATU:
+**  E When the Parity Error Response bit in the ATUCMD is set, PERR# is asserted three clocks
+**  cycles following the Split Response Termination in which the data parity error is detected on
+**  the bus. When the ATU asserts PERR#, additional actions is taken:
+**  X A Split Write Data Parity Error message (with message class=2h - completer error and
+**  message index=01h - Split Write Data Parity Error) is initiated by the ATU on the PCI bus
+**  that addresses the requester of the configuration write.
+**  X When the Initiated Split Completion Error Message Interrupt Mask in the ATUIMR is
+**  clear, set the Initiated Split Completion Error Message bit in the ATUISR. When set, no
+**  action.
+**  X The Split Write Request is not enqueued and forwarded to the internal bus.
+**  E The Detected Parity Error bit in the ATUSR is set. When the ATU sets this bit, additional
+**  actions is taken:
+**  X When the ATU Detected Parity Error Interrupt Mask bit in the ATUIMR is clear, set the
+**  Detected Parity Error bit in the ATUISR. When set, no action.
+**
+***************************************************************************
+***************************************************************************
+**                       Split Completion Messages
+**  =======================================================================
+**  As a target, the ATU may encounter this error when operating in the PCI-X mode.
+**  Data parity errors occurring during Split Completion Messages claimed by the ATU may assert
+**  PERR# (when enabled) or SERR# (when enabled) on the PCI Bus. When an error occurs, the
+**  ATU accepts the data and complete normally. Specifically, the following actions with the given
+**  constraints are taken by the ATU:
+**  E PERR# is asserted three clocks cycles following the data phase in which the data parity error
+**  is detected on the bus. This is only done when the Parity Error Response bit in the ATUCMD
+**  is set. When the ATU asserts PERR#, additional actions is taken:
+**  X The Master Parity Error bit in the ATUSR is set.
+**  X When the ATU PCI Master Parity Error Interrupt Mask Bit in the ATUIMR is clear, set the
+**  PCI Master Parity Error bit in the ATUISR. When set, no action.
+**  X When the SERR# Enable bit in the ATUCMD is set, and the Data Parity Error Recover
+**  Enable bit in the PCIXCMD register is clear, assert SERR#; otherwise no action is taken.
+**  When the ATU asserts SERR#, additional actions is taken:
+**  Set the SERR# Asserted bit in the ATUSR.
+**  When the ATU SERR# Asserted Interrupt Mask Bit in the ATUIMR is clear, set the
+**  SERR# Asserted bit in the ATUISR. When set, no action.
+**  When the ATU SERR# Detected Interrupt Enable Bit in the ATUCR is set, set the
+**  SERR# Detected bit in the ATUISR. When clear, no action.
+**  E When the SCE bit (Split Completion Error -- bit 30 of the Completer Attributes) is set during
+**  the Attribute phase, the Received Split Completion Error Message bit in the PCIXSR is set.
+**  When the ATU sets this bit, additional actions is taken:
+**  X When the ATU Received Split Completion Error Message Interrupt Mask bit in the
+**  ATUIMR is clear, set the Received Split Completion Error Message bit in the ATUISR.
+**  When set, no action.
+**  E The Detected Parity Error bit in the ATUSR is set. When the ATU sets this bit, additional
+**  actions is taken:
+**  X When the ATU Detected Parity Error Interrupt Mask bit in the ATUIMR is clear, set the
+**  Detected Parity Error bit in the ATUISR. When set, no action.
+**  E The transaction associated with the Split Completion Message is discarded.
+**  E When the discarded transaction was a read, a completion error message (with message
+**  class=2h - completer error and message index=82h - PCI bus read parity error) is generated on
+**  the internal bus of the 80331.
+*****************************************************************************
+******************************************************************************************************
+**                 Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+**  ==================================================================================================
+**	The Messaging Unit (MU) transfers data between the PCI system and the 80331
+**  notifies the respective system when new data arrives.
+**	The PCI window for messaging transactions is always the first 4 Kbytes of the inbound translation.
+**	window defined by:
+**                    1.Inbound ATU Base Address Register 0 (IABAR0)
+**                    2.Inbound ATU Limit Register 0 (IALR0)
+**	All of the Messaging Unit errors are reported in the same manner as ATU errors.
+**  Error conditions and status can be found in :
+**                                               1.ATUSR
+**                                               2.ATUISR
+**====================================================================================================
+**     Mechanism        Quantity               Assert PCI Interrupt Signals      Generate I/O Processor Interrupt
+**----------------------------------------------------------------------------------------------------
+**  Message Registers      2 Inbound                   Optional                              Optional
+**                         2 Outbound
+**----------------------------------------------------------------------------------------------------
+**  Doorbell Registers     1 Inbound                   Optional                              Optional
+**                         1 Outbound
+**----------------------------------------------------------------------------------------------------
+**  Circular Queues        4 Circular Queues           Under certain conditions              Under certain conditions
+**----------------------------------------------------------------------------------------------------
+**  Index Registers     1004 32-bit Memory Locations   No                                    Optional
+**====================================================================================================
+**     PCI Memory Map: First 4 Kbytes of the ATU Inbound PCI Address Space
+**====================================================================================================
+**  0000H           Reserved
+**  0004H           Reserved
+**  0008H           Reserved
+**  000CH           Reserved
+**------------------------------------------------------------------------
+**  0010H 			Inbound Message Register 0              ]
+**  0014H 			Inbound Message Register 1              ]
+**  0018H 			Outbound Message Register 0             ]
+**  001CH 			Outbound Message Register 1             ]   4 Message Registers
+**------------------------------------------------------------------------
+**  0020H 			Inbound Doorbell Register               ]
+**  0024H 			Inbound Interrupt Status Register       ]
+**  0028H 			Inbound Interrupt Mask Register         ]
+**  002CH 			Outbound Doorbell Register              ]
+**  0030H 			Outbound Interrupt Status Register      ]
+**  0034H 			Outbound Interrupt Mask Register        ]   2 Doorbell Registers and 4 Interrupt Registers
+**------------------------------------------------------------------------
+**  0038H 			Reserved
+**  003CH 			Reserved
+**------------------------------------------------------------------------
+**  0040H 			Inbound Queue Port                      ]
+**  0044H 			Outbound Queue Port                     ]   2 Queue Ports
+**------------------------------------------------------------------------
+**  0048H 			Reserved
+**  004CH 			Reserved
+**------------------------------------------------------------------------
+**  0050H                                                   ]
+**    :                                                     ]
+**    :      Intel Xscale Microarchitecture Local Memory    ]
+**    :                                                     ]
+**  0FFCH                                                   ]   1004 Index Registers
+*******************************************************************************
+*****************************************************************************
+**                      Theory of MU Operation
+*****************************************************************************
+**--------------------
+**   inbound_msgaddr0:
+**   inbound_msgaddr1:
+**  outbound_msgaddr0:
+**  outbound_msgaddr1:
+**  .  The MU has four independent messaging mechanisms.
+**     There are four Message Registers that are similar to a combination of mailbox and doorbell registers.
+**     Each holds a 32-bit value and generates an interrupt when written.
+**--------------------
+**   inbound_doorbell:
+**  outbound_doorbell:
+**  .  The two Doorbell Registers support software interrupts.
+**     When a bit is set in a Doorbell Register, an interrupt is generated.
+**--------------------
+**  inbound_queueport:
+** outbound_queueport:
+**
+**
+**  .  The Circular Queues support a message passing scheme that uses 4 circular queues.
+**     The 4 circular queues are implemented in 80331 local memory.
+**     Two queues are used for inbound messages and two are used for outbound messages.
+**     Interrupts may be generated when the queue is written.
+**--------------------
+** local_buffer 0x0050 ....0x0FFF
+**  .  The Index Registers use a portion of the 80331 local memory to implement a large set of message registers.
+**     When one of the Index Registers is written, an interrupt is generated and the address of the register written is captured.
+**     Interrupt status for all interrupts is recorded in the Inbound Interrupt Status Register and the Outbound Interrupt Status Register.
+**     Each interrupt generated by the Messaging Unit can be masked.
+**--------------------
+**  .  Multi-DWORD PCI burst accesses are not supported by the Messaging Unit,
+**     with the exception of Multi-DWORD reads to the index registers.
+**     In Conventional mode: the MU terminates   Multi-DWORD PCI transactions
+**     (other than index register reads) with a disconnect at the next Qword boundary, with the exception of queue ports.
+**     In PCI-X mode       : the MU terminates a Multi-DWORD PCI read transaction with
+**     a Split Response and the data is returned through split completion transaction(s).
+**     however, when the burst request crosses into or through the range of
+**     offsets 40h to 4Ch (e.g., this includes the queue ports) the transaction is signaled target-abort immediately on the PCI bus.
+**  	In PCI-X mode, Multi-DWORD PCI writes is signaled a Single-Data-Phase Disconnect
+**     which means that no data beyond the first Qword (Dword when the MU does not assert P_ACK64#) is written.
+**--------------------
+**  .  All registers needed to configure and control the Messaging Unit are memory-mapped registers.
+**     The MU uses the first 4 Kbytes of the inbound translation window in the Address Translation Unit (ATU).
+**     This PCI address window is used for PCI transactions that access the 80331 local memory.
+**     The  PCI address of the inbound translation window is contained in the Inbound ATU Base Address Register.
+**--------------------
+**  .  From the PCI perspective, the Messaging Unit is part of the Address Translation Unit.
+**     The Messaging Unit uses the PCI configuration registers of the ATU for control and status information.
+**     The Messaging Unit must observe all PCI control bits in the ATU Command Register and ATU Configuration Register.
+**     The Messaging Unit reports all PCI errors in the ATU Status Register.
+**--------------------
+**  .  Parts of the Messaging Unit can be accessed as a 64-bit PCI device.
+**     The register interface, message registers, doorbell registers,
+**  	and index registers returns a P_ACK64# in response to a P_REQ64# on the PCI interface.
+**     Up to 1 Qword of data can be read or written per transaction (except Index Register reads).
+**     The Inbound and Outbound Queue Ports are always 32-bit addresses and the MU does not assert P_ACK64# to offsets 40H and 44H.
+**************************************************************************
+**************************************************************************
+**  Message Registers
+**  ==============================
+**  . Messages can be sent and received by the 80331 through the use of the Message Registers.
+**  . When written, the message registers may cause an interrupt to be generated to either the Intel XScale core or the host processor.
+**  . Inbound messages are sent by the host processor and received by the 80331.
+**    Outbound messages are sent by the 80331 and received by the host processor.
+**  . The interrupt status for outbound messages is recorded in the Outbound Interrupt Status Register.
+**    Interrupt status for inbound messages is recorded in the Inbound Interrupt Status Register.
+**
+**  Inbound Messages:
+**  -----------------
+**  . When an inbound message register is written by an external PCI agent, an interrupt may be generated to the Intel XScale core.
+**  . The interrupt may be masked by the mask bits in the Inbound Interrupt Mask Register.
+**  . The Intel XScale core interrupt is recorded in the Inbound Interrupt Status Register.
+**    The interrupt causes the Inbound Message Interrupt bit to be set in the Inbound Interrupt Status Register.
+**    This is a Read/Clear bit that is set by the MU hardware and cleared by software.
+**    The interrupt is cleared when the Intel XScale core writes
+**    a value of 1 to the Inbound Message Interrupt bit in the Inbound Interrupt Status Register.
+**  ------------------------------------------------------------------------
+**  Inbound Message Register - IMRx
+**
+**  . There are two Inbound Message Registers: IMR0 and IMR1.
+**  . When the IMR register is written, an interrupt to the Intel XScale core may be generated.
+**    The interrupt is recorded in the Inbound Interrupt Status Register
+**    and may be masked by the Inbound Message Interrupt Mask bit in the Inbound Interrupt Mask Register.
+**  -----------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:00    0000 0000H                     Inbound Message - This is a 32-bit message written by an external PCI agent.
+**                                                            When written, an interrupt to the Intel XScale core may be generated.
+**************************************************************************
+**************************************************************************
+**  Outbound Message Register - OMRx
+**  --------------------------------
+**  There are two Outbound Message Registers: OMR0 and OMR1. When the OMR register is
+**  written, a PCI interrupt may be generated. The interrupt is recorded in the Outbound Interrupt
+**  Status Register and may be masked by the Outbound Message Interrupt Mask bit in the Outbound
+**  Interrupt Mask Register.
+**
+**  Bit       Default                       Description
+**  31:00    00000000H                    Outbound Message - This is 32-bit message written by the Intel  XScale  core.
+**						When written, an interrupt may be generated
+**						on the PCI Interrupt pin determined by the ATU Interrupt Pin Register.
+**************************************************************************
+**************************************************************************
+**        Doorbell Registers
+**  ==============================
+**  There are two Doorbell Registers:
+**                                  Inbound Doorbell Register
+**                                  Outbound Doorbell Register
+**  The Inbound Doorbell Register allows external PCI agents to generate interrupts to the Intel R XScale core.
+**  The Outbound Doorbell Register allows the Intel R XScale core to generate a PCI interrupt.
+**  Both Doorbell Registers may generate interrupts whenever a bit in the register is set.
+**
+**  Inbound Doorbells:
+**  ------------------
+**  . When the Inbound Doorbell Register is written by an external PCI agent, an interrupt may be generated to the Intel R XScale  core.
+**    An interrupt is generated when any of the bits in the doorbell register is written to a value of 1.
+**    Writing a value of 0 to any bit does not change the value of that bit and does not cause an interrupt to be generated.
+**  . Once a bit is set in the Inbound Doorbell Register, it cannot be cleared by any external PCI agent.
+**    The interrupt is recorded in the Inbound Interrupt Status Register.
+**  . The interrupt may be masked by the Inbound Doorbell Interrupt mask bit in the Inbound Interrupt Mask Register.
+**    When the mask bit is set for a particular bit, no interrupt is generated for that bit.
+**    The Inbound Interrupt Mask Register affects only the generation of
+**    the normal messaging unit interrupt and not the values written to the Inbound Doorbell Register.
+**    One bit in the Inbound Doorbell Register is reserved for an Error Doorbell interrupt.
+**  . The interrupt is cleared when the Intel R XScale core writes a value of 1 to the bits in the Inbound Doorbell Register that are set.
+**    Writing a value of 0 to any bit does not change the value of that bit and does not clear the interrupt.
+**  ------------------------------------------------------------------------
+**  Inbound Doorbell Register - IDR
+**
+**  . The Inbound Doorbell Register (IDR) is used to generate interrupts to the Intel XScale core.
+**  . Bit 31 is reserved for generating an Error Doorbell interrupt.
+**    When bit 31 is set, an Error interrupt may be generated to the Intel XScale core.
+**    All other bits, when set, cause the Normal Messaging Unit interrupt line of the Intel XScale core to be asserted,
+**    when the interrupt is not masked by the Inbound Doorbell Interrupt Mask bit in the Inbound Interrupt Mask Register.
+**    The bits in the IDR register can only be set by an external PCI agent and can only be cleared by the Intel XScale  core.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31          0 2                         Error Interrupt - Generate an Error Interrupt to the Intel XScale core.
+**  30:00    00000000H                      Normal Interrupt - When any bit is set, generate a Normal interrupt to the Intel XScale core.
+**                                                             When all bits are clear, do not generate a Normal Interrupt.
+**************************************************************************
+**************************************************************************
+**  Inbound Interrupt Status Register - IISR
+**
+**  . The Inbound Interrupt Status Register (IISR) contains hardware interrupt status.
+**    It records the status of Intel XScale core interrupts generated by the Message Registers, Doorbell Registers, and the Circular Queues.
+**    All interrupts are routed to the Normal Messaging Unit interrupt input of the Intel XScale core,
+**    except for the Error Doorbell Interrupt and the Outbound Free Queue Full interrupt;
+**    these two are routed to the Messaging Unit Error interrupt input.
+**    The generation of interrupts recorded in the Inbound Interrupt Status Register
+**    may be masked by setting the corresponding bit in the Inbound Interrupt Mask Register.
+**    Some of the bits in this register are Read Only.
+**    For those bits, the interrupt must be cleared through another register.
+**
+**  Bit       Default                       Description
+**  31:07    0000000H 0 2                   Reserved
+**  06          0 2                       Index Register Interrupt - This bit is set by the MU hardware
+**						when an Index Register has been written after a PCI transaction.
+**  05          0 2                       Outbound Free Queue Full Interrupt - This bit is set
+**						when the Outbound Free Head Pointer becomes equal to the Tail Pointer and the queue is full.
+**                                        An Error interrupt is generated for this condition.
+**  04          0 2                       Inbound Post Queue Interrupt - This bit is set
+**						by the MU hardware when the Inbound Post Queue has been written.
+**						Once cleared, an interrupt does NOT be generated
+**						when the head and tail pointers remain unequal (i.e. queue status is Not Empty).
+**						Therefore, when software leaves any
+**						unprocessed messages in the post queue when the interrupt is cleared,
+**						software must retain the information that the Inbound Post queue status is not empty.
+**	NOTE: This interrupt is provided with dedicated support in the 80331 Interrupt Controller.
+**  03          0 2				Error Doorbell Interrupt - This bit is set
+**						when the Error Interrupt of the Inbound Doorbell Register is set.
+**						To clear this bit (and the interrupt),
+**						the Error Interrupt bit of the Inbound Doorbell Register must be clear.
+**  02          0 2				Inbound Doorbell Interrupt - This bit is set
+**						when at least one Normal Interrupt bit in the Inbound Doorbell Register is set.
+**						To clear this bit (and the interrupt),
+**						the Normal Interrupt bits in the Inbound Doorbell Register must all be clear.
+**  01          0 2				Inbound Message 1 Interrupt - This bit is set
+**						by the MU hardware when the Inbound Message 1 Register has been written.
+**  00          0 2				Inbound Message 0 Interrupt - This bit is set
+**						by the MU hardware when the Inbound Message 0 Register has been written.
+**************************************************************************
+**************************************************************************
+**  Inbound Interrupt Mask Register - IIMR
+**
+**  . The Inbound Interrupt Mask Register (IIMR) provides the ability to mask
+**    Intel XScale core interrupts generated by the Messaging Unit.
+**    Each bit in the Mask register corresponds to an interrupt bit in the Inbound Interrupt Status Register.
+**    Setting or clearing bits in this register does not affect the Inbound Interrupt Status Register.
+**    They only affect the generation of the Intel XScale core interrupt.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:07     000000H 0 2                   Reserved
+**  06        0 2                  Index Register Interrupt Mask - When set, this bit masks
+**					the interrupt generated by the MU hardware when an Index Register
+**					has been written after a PCI transaction.
+**  05        0 2                  Outbound Free Queue Full Interrupt Mask - When set, this bit masks
+**					the Error interrupt generated when the Outbound
+**					Free Head Pointer becomes equal to the Tail Pointer and the queue is full.
+**  04        0 2			Inbound Post Queue Interrupt Mask - When set,
+**					this bit masks the interrupt generated by the MU hardware
+**					when the Inbound Post Queue has been written.
+**  03        0 2			Error Doorbell Interrupt Mask - When set,
+**					this bit masks the Error Interrupt when the Error Interrupt bit
+**					of the Inbound Doorbell Register is set.
+**  02        0 2			Inbound Doorbell Interrupt Mask - When set,
+**					this bit masks the interrupt generated when at least
+**					one Normal Interrupt bit in the Inbound Doorbell Register is set.
+**  01        0 2			Inbound Message 1 Interrupt Mask - When set,
+**					this bit masks the Inbound Message 1 Interrupt
+**					generated by a write to the Inbound Message 1 Register.
+**  00        0 2			Inbound Message 0 Interrupt Mask - When set,
+**					this bit masks the Inbound Message 0 Interrupt generated
+**					by a write to the Inbound Message 0 Register.
+**************************************************************************
+**************************************************************************
+**  Outbound Doorbell Register - ODR
+**
+**  The Outbound Doorbell Register (ODR) allows software interrupt generation. It allows the Intel
+**  XScale  core to generate PCI interrupts to the host processor by writing to this register. The
+**  generation of PCI interrupts through the Outbound Doorbell Register may be masked by setting the
+**  Outbound Doorbell Interrupt Mask bit in the Outbound Interrupt Mask Register.
+**  The Software Interrupt bits in this register can only be set by the Intel  XScale  core and can only
+**  be cleared by an external PCI agent.
+**  ----------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31          0 2                          Reserved
+**  30          0 2                          Reserved.
+**  29          0 2                          Reserved
+**  28       0000 0000H            PCI Interrupt - When set,
+**					this bit causes the P_INTC# interrupt output (P_INTA# with BRG_EN and ARB_EN straps low)
+**					signal to be asserted or a Message-signaled Interrupt is generated (when enabled).
+**					When this bit is cleared, the P_INTC# interrupt output (P_INTA# with BRG_EN and ARB_EN straps low)
+**					signal is deasserted.
+**  27:00     000 0000H            Software Interrupts - When any bit is set the P_INTC#
+**					interrupt output (P_INTA# with BRG_EN and ARB_EN straps low)
+**					signal is asserted or a Message-signaled Interrupt is generated (when enabled).
+**					When all bits are cleared, the P_INTC# interrupt output (P_INTA# with BRG_EN and ARB_EN straps low)
+**					signal is deasserted.
+**************************************************************************
+**************************************************************************
+**  Outbound Interrupt Status Register - OISR
+**
+**  The Outbound Interrupt Status Register (OISR) contains hardware interrupt status. It records the
+**  status of PCI interrupts generated by the Message Registers, Doorbell Registers, and the Circular
+**  Queues. The generation of PCI interrupts recorded in the Outbound Interrupt Status Register may
+**  be masked by setting the corresponding bit in the Outbound Interrupt Mask Register. Some of the
+**  bits in this register are Read Only. For those bits, the interrupt must be cleared through another
+**  register.
+**  ----------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:05     000000H 000 2                 Reserved
+**  04        0 2                         PCI Interrupt - This bit is set when the
+**						PCI Interrupt bit (bit 28) is set in the Outbound Doorbell Register.
+**						To clear this bit (and the interrupt), the PCI Interrupt bit must be cleared.
+**  03        0 2                         Outbound Post Queue Interrupt - This bit is set when
+**						data in the prefetch buffer is valid. This bit is
+**						cleared when any prefetch data has been read from the Outbound Queue Port.
+**  02        0 2                         Outbound Doorbell Interrupt - This bit is set when at least
+**						one Software Interrupt bit in the Outbound
+**						Doorbell Register is set. To clear this bit (and the interrupt),
+**						the Software Interrupt bits in the Outbound
+**						Doorbell Register must all be clear.
+**  01        0 2				Outbound Message 1 Interrupt - This bit is set by
+**						the MU when the Outbound Message 1 Register is
+**						written. Clearing this bit clears the interrupt.
+**  00        0 2				Outbound Message 0 Interrupt - This bit is set by
+**						the MU when the Outbound Message 0 Register is
+**						written. Clearing this bit clears the interrupt.
+**************************************************************************
+**************************************************************************
+**  Outbound Interrupt Mask Register - OIMR
+**  The Outbound Interrupt Mask Register (OIMR) provides the ability to mask outbound PCI
+**  interrupts generated by the Messaging Unit. Each bit in the mask register corresponds to a
+**  hardware interrupt bit in the Outbound Interrupt Status Register. When the bit is set, the PCI
+**  interrupt is not generated. When the bit is clear, the interrupt is allowed to be generated.
+**  Setting or clearing bits in this register does not affect the Outbound Interrupt Status Register. They
+**  only affect the generation of the PCI interrupt.
+**  ----------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:05     000000H                       Reserved
+**  04          0 2                       PCI Interrupt Mask - When set, this bit masks
+**						the interrupt generation when the PCI Interrupt bit (bit 28)
+**						in the Outbound Doorbell Register is set.
+**  03          0 2				Outbound Post Queue Interrupt Mask - When set,
+**						this bit masks the interrupt generated when data in
+**						the prefetch buffer is valid.
+**  02          0 2				Outbound Doorbell Interrupt Mask - When set,
+**						this bit masks the interrupt generated by the Outbound
+**						Doorbell Register.
+**  01          0 2				Outbound Message 1 Interrupt Mask - When set,
+**						this bit masks the Outbound Message 1 Interrupt
+**						generated by a write to the Outbound Message 1 Register.
+**  00          0 2				Outbound Message 0 Interrupt Mask- When set,
+**						this bit masks the Outbound Message 0 Interrupt
+**						generated by a write to the Outbound Message 0 Register.
+**************************************************************************
+**************************************************************************
+**                          Circular Queues
+**  ======================================================================
+**  The MU implements four circular queues. There are 2 inbound queues and 2 outbound queues. In
+**  this case, inbound and outbound refer to the direction of the flow of posted messages.
+**  Inbound messages are either:
+**  						E posted messages by other processors for the Intel XScale core to process or
+**  						E free (or empty) messages that can be reused by other processors.
+**  Outbound messages are either:
+** 							E posted messages by the Intel XScale core for other processors to process or
+** 							E free (or empty) messages that can be reused by the Intel XScale core.
+**  Therefore, free inbound messages flow away from the 80331 and free outbound messages flow toward the 80331.
+**  The four Circular Queues are used to pass messages in the following manner.
+**  	. The two inbound queues are used to handle inbound messages
+**  	  and the two outbound queues are used to handle  outbound messages.
+**  	. One of the inbound queues is designated the Free queue and it contains inbound free messages.
+**  	  The other inbound queue is designated the Post queue and it contains inbound posted messages.
+**  	  Similarly, one of the outbound queues is designated the Free queue and the other outbound queue is designated the Post queue.
+**
+**  =============================================================================================================
+**  Circular Queue Summary
+**   _____________________________________________________________________________________________________________
+**  |    Queue Name        |                     Purpose                                |  Action on PCI Interface|
+**  |______________________|____________________________________________________________|_________________________|
+**  |Inbound Post  Queue   |    Queue for inbound messages from other processors        |          Written        |
+**  |                      |     waiting to be processed by the 80331                   |                         |
+**  |Inbound Free  Queue   |    Queue for empty inbound messages from the 80331         |          Read           |
+**  |                      |    available for use by other processors                   |                         |
+**  |Outbound Post Queue   |    Queue for outbound messages from the 80331              |          Read           |
+**  |                      |    that are being posted to the other processors           |                         |
+**  |Outbound Free Queue   |    Queue for empty outbound messages from other processors |          Written        |
+**  |                      |    available for use by the 80331                          |                         |
+**  |______________________|____________________________________________________________|_________________________|
+**
+**  . The two inbound queues allow the host processor to post inbound messages for the 80331 in one
+**    queue and to receive free messages returning from the 80331.
+**    The host processor posts inbound messages,
+**    the Intel XScale core receives the posted message and when it is finished with the message,
+**    places it back on the inbound free queue for reuse by the host processor.
+**
+**  The circular queues are accessed by external PCI agents through two port locations in the PCI
+**  address space:
+**              Inbound Queue Port
+**          and Outbound Queue Port.
+**  The Inbound Queue Port is used by external PCI agents to read the Inbound Free Queue and write the Inbound Post Queue.
+**  The Outbound Queue Port is used by external PCI agents to read the Outbound Post Queue and write the Outbound Free Queue.
+**  Note that a PCI transaction to the inbound or outbound queue ports with null byte enables (P_C/BE[3:0]#=1111 2 )
+**  does not cause the MU hardware to increment the queue pointers.
+**  This is treated as when the PCI transaction did not occur.
+**  The Inbound and Outbound Queue Ports never respond with P_ACK64# on the PCI interface.
+**  ======================================================================================
+**  Overview of Circular Queue Operation
+**  ======================================================================================
+**  . The data storage for the circular queues must be provided by the 80331 local memory.
+**  . The base address of the circular queues is contained in the Queue Base Address Register.
+**    Each entry in the queue is a 32-bit data value.
+**  . Each read from or write to the queue may access only one queue entry.
+**  . Multi-DWORD accesses to the circular queues are not allowed.
+**    Sub-DWORD accesses are promoted to DWORD accesses.
+**  . Each circular queue has a head pointer and a tail pointer.
+**    The pointers are offsets from the Queue Base Address.
+**  . Writes to a queue occur at the head of the queue and reads occur from the tail.
+**    The head and tail pointers are incremented by either the Intel XScale core or the Messaging Unit hardware.
+**    Which unit maintains the pointer is determined by the writer of the queue.
+**    More details about the pointers are given in the queue descriptions below.
+**    The pointers are incremented after the queue access.
+**    Both pointers wrap around to the first address of the circular queue when they reach the circular queue size.
+**
+**  Messaging Unit...
+**
+**  The Messaging Unit generates an interrupt to the Intel XScale core or generate a PCI interrupt under certain conditions.
+**  . In general, when a Post queue is written, an interrupt is generated to notify the receiver that a message was posted.
+**    The size of each circular queue can range from 4K entries (16 Kbytes) to 64K entries (256 Kbytes).
+**  . All four queues must be the same size and may be contiguous.
+**    Therefore, the total amount of local memory needed by the circular queues ranges from 64 Kbytes to 1 Mbytes.
+**    The Queue size is determined by the Queue Size field in the MU Configuration Register.
+**  . There is one base address for all four queues.
+**    It is stored in the Queue Base Address Register (QBAR).
+**    The starting addresses of each queue is based on the Queue Base Address and the Queue Size field.
+**    here shows an example of how the circular queues should be set up based on the
+**    Intelligent I/O (I 2 O) Architecture Specification.
+**    Other ordering of the circular queues is possible.
+**
+**  				Queue                           Starting Address
+**  				Inbound Free Queue              QBAR
+**  				Inbound Post Queue              QBAR + Queue Size
+**  				Outbound Post Queue             QBAR + 2 * Queue Size
+**  				Outbound Free Queue             QBAR + 3 * Queue Size
+**  ===================================================================================
+**  Inbound Post Queue
+**  ------------------
+**  The Inbound Post Queue holds posted messages placed there by other processors for the Intel XScale core to process.
+**  This queue is read from the queue tail by the Intel XScale core. It is written to the queue head by external PCI agents.
+**  The tail pointer is maintained by the Intel XScale core. The head pointer is maintained by the MU hardware.
+**  For a PCI write transaction that accesses the Inbound Queue Port,
+**  the MU writes the data to the local memory location address in the Inbound Post Head Pointer Register.
+**  When the data written to the Inbound Queue Port is written to local memory,
+**  the MU hardware increments the Inbound Post Head Pointer Register.
+**  An Intel XScale core interrupt may be generated when the Inbound Post Queue is written.
+**  The Inbound Post Queue Interrupt bit in the Inbound Interrupt Status Register indicates the interrupt status.
+**  The interrupt is cleared when the Inbound Post Queue Interrupt bit is cleared.
+**  The interrupt can be masked by the Inbound Interrupt Mask Register.
+**  Software must be aware of the state of the Inbound Post Queue Interrupt
+**  Mask bit to guarantee that the full condition is recognized by the core processor.
+**  In addition, to guarantee that the queue does not get overwritten,
+**  software must process messages from the tail of the queue before incrementing the tail pointer and clearing this interrupt.
+**  Once cleared, an interrupt is NOT generated when the head and tail pointers remain unequal (i.e. queue status is Not Empty).
+**  Only a new message posting the in the inbound queue generates a new interrupt.
+**  Therefore, when software leaves any unprocessed messages in the post
+**  queue when the interrupt is cleared, software must retain the information that the Inbound Post queue status.
+**  From the time that the PCI write transaction is received until
+**  the data is written in local memory and the Inbound Post Head
+**  Pointer Register is incremented, any PCI transaction that attempts
+**  to access the Inbound Post Queue Port is signalled a Retry.
+**  The Intel XScale core may read messages from the Inbound Post
+**  Queue by reading the data from the local memory location pointed to by the Inbound Post Tail Pointer Register.
+**  The Intel XScale core must then increment the Inbound Post Tail Pointer Register.
+**  When the Inbound Post Queue is full (head and tail pointers are
+**  equal and the head pointer was last updated by hardware), the hardware retries
+**  any PCI writes until a slot in the queue becomes available.
+**  A slot in the post queue becomes available by the Intel XScale core incrementing the tail pointer.
+**  ===================================================================================
+**  Inbound Free Queue
+**  ------------------
+**  The Inbound Free Queue holds free inbound messages placed there by the Intel XScale core for other processors to use.
+**  This queue is read from the queue tail by external PCI agents.
+**  It is written to the queue head by the Intel XScale core.
+**  The tail pointer is maintained by the MU hardware.
+**  The head pointer is maintained by the Intel XScale core.
+**  For a PCI read transaction that accesses the Inbound Queue Port,
+**  the MU attempts to read the data at the local memory address in the Inbound Free Tail Pointer.
+**  When the queue is not empty (head and tail pointers are not equal)
+**  or full (head and tail pointers are equal but the head pointer was last written by software), the data is returned.
+**  When the queue is empty (head and tail pointers are equal and the
+**  head pointer was last updated by hardware), the value of -1 (FFFF.FFFFH) is  returned.
+**  When the queue was not empty and the MU succeeded in returning the data at the tail,
+**  the MU hardware must increment the value in the Inbound Free Tail Pointer Register.
+**  To reduce latency for the PCI read access, the MU implements a
+**  prefetch mechanism to anticipate accesses to the Inbound Free Queue.
+**  The MU hardware prefetches the data at the tail of the Inbound Free Queue and load it into an internal prefetch register.
+**  When the PCI read access occurs, the data is read directly from the prefetch register.
+**  The prefetch mechanism loads a value of -1 (FFFF.FFFFH) into the prefetch register
+**  when the head and tail pointers are equal and the queue is empty.
+**  In order to update the prefetch register when messages are added to the queue and it becomes non-empty,
+**  the prefetch mechanism automatically starts a prefetch when the
+**  prefetch register contains FFFF.FFFFH and the Inbound Free Head Pointer Register is written.
+**  The Intel XScale core needs to update the Inbound Free Head Pointer Register when it adds messages to the queue.
+**  A prefetch must appear atomic from the perspective of the external PCI agent.
+**  When a prefetch is started, any PCI transaction that attempts to access
+**  the Inbound Free Queue is signalled a Retry until the prefetch is completed.
+**  The Intel XScale core may place messages in the Inbound Free Queue by writing the data to the
+**  local memory location pointed to by the Inbound Free Head Pointer Register.
+**  The processor must then increment the Inbound Free Head Pointer Register.
+**  ==================================================================================
+**  Outbound Post Queue
+**  -------------------
+**  The Outbound Post Queue holds outbound posted messages placed there by the Intel XScale
+**  core for other processors to process. This queue is read from the queue tail by external PCI agents.
+**  It is written to the queue head by the Intel XScale  core. The tail pointer is maintained by the
+**  MU hardware. The head pointer is maintained by the Intel XScale  core.
+**  For a PCI read transaction that accesses the Outbound Queue Port, the MU attempts to read the
+**  data at the local memory address in the Outbound Post Tail Pointer Register. When the queue is not
+**  empty (head and tail pointers are not equal) or full (head and tail pointers are equal but the head
+**  pointer was last written by software), the data is returned. When the queue is empty (head and tail
+**  pointers are equal and the head pointer was last updated by hardware), the value of -1
+**  (FFFF.FFFFH) is returned. When the queue was not empty and the MU succeeded in returning the
+**  data at the tail, the MU hardware must increment the value in the Outbound Post Tail Pointer
+**  Register.
+**  To reduce latency for the PCI read access, the MU implements a prefetch mechanism to anticipate
+**  accesses to the Outbound Post Queue. The MU hardware prefetches the data at the tail of the
+**  Outbound Post Queue and load it into an internal prefetch register. When the PCI read access
+**  occurs, the data is read directly from the prefetch register.
+**  The prefetch mechanism loads a value of -1 (FFFF.FFFFH) into the prefetch register when the head
+**  and tail pointers are equal and the queue is empty. In order to update the prefetch register when
+**  messages are added to the queue and it becomes non-empty, the prefetch mechanism automatically
+**  starts a prefetch when the prefetch register contains FFFF.FFFFH and the Outbound Post Head
+**  Pointer Register is written. The Intel XScale  core needs to update the Outbound Post Head
+**  Pointer Register when it adds messages to the queue.
+**  A prefetch must appear atomic from the perspective of the external PCI agent. When a prefetch is
+**  started, any PCI transaction that attempts to access the Outbound Post Queue is signalled a Retry
+**  until the prefetch is completed.
+**  A PCI interrupt may be generated when data in the prefetch buffer is valid. When the prefetch
+**  queue is clear, no interrupt is generated. The Outbound Post Queue Interrupt bit in the Outbound
+**  Interrupt Status Register shall indicate the status of the prefetch buffer data and therefore the
+**  interrupt status. The interrupt is cleared when any prefetched data has been read from the Outbound
+**  Queue Port. The interrupt can be masked by the Outbound Interrupt Mask Register.
+**  The Intel XScale  core may place messages in the Outbound Post Queue by writing the data to
+**  the local memory address in the Outbound Post Head Pointer Register. The processor must then
+**  increment the Outbound Post Head Pointer Register.
+**  ==================================================
+**  Outbound Free Queue
+**  -----------------------
+**  The Outbound Free Queue holds free messages placed there by other processors for the Intel
+**  XScale  core to use. This queue is read from the queue tail by the Intel XScale  core. It is
+**  written to the queue head by external PCI agents. The tail pointer is maintained by the Intel
+**  XScale  core. The head pointer is maintained by the MU hardware.
+**  For a PCI write transaction that accesses the Outbound Queue Port, the MU writes the data to the
+**  local memory address in the Outbound Free Head Pointer Register. When the data written to the
+**  Outbound Queue Port is written to local memory, the MU hardware increments the Outbound Free
+**  Head Pointer Register.
+**  When the head pointer and the tail pointer become equal and the queue is full, the MU may signal
+**  an interrupt to the Intel XScale  core to register the queue full condition. This interrupt is
+**  recorded in the Inbound Interrupt Status Register. The interrupt is cleared when the Outbound Free
+**  Queue Full Interrupt bit is cleared and not by writing to the head or tail pointers. The interrupt can
+**  be masked by the Inbound Interrupt Mask Register. Software must be aware of the state of the
+**  Outbound Free Queue Interrupt Mask bit to guarantee that the full condition is recognized by the
+**  core processor.
+**  From the time that a PCI write transaction is received until the data is written in local memory and
+**  the Outbound Free Head Pointer Register is incremented, any PCI transaction that attempts to
+**  access the Outbound Free Queue Port is signalled a retry.
+**  The Intel XScale  core may read messages from the Outbound Free Queue by reading the data
+**  from the local memory address in the Outbound Free Tail Pointer Register. The processor must
+**  then increment the Outbound Free Tail Pointer Register. When the Outbound Free Queue is full,
+**  the hardware must retry any PCI writes until a slot in the queue becomes available.
+**
+**  ==================================================================================
+**  Circular Queue Summary
+**  ----------------------
+**  ________________________________________________________________________________________________________________________________________________
+** | Queue Name  |  PCI Port     |Generate PCI Interrupt |Generate Intel Xscale Core Interrupt|Head Pointer maintained by|Tail Pointer maintained by|
+** |_____________|_______________|_______________________|____________________________________|__________________________|__________________________|
+** |Inbound Post | Inbound Queue |                       |                                    |                          |                          |
+** |    Queue    |     Port      |          NO           |      Yes, when queue is written    |         MU hardware      |     Intel XScale         |
+** |_____________|_______________|_______________________|____________________________________|__________________________|__________________________|
+** |Inbound Free | Inbound Queue |                       |                                    |                          |                          |
+** |    Queue    |     Port      |          NO           |      NO                            |        Intel XScale      |      MU hardware         |
+** |_____________|_______________|_______________________|____________________________________|__________________________|__________________________|
+** ==================================================================================
+**  Circular Queue Status Summary
+**  ----------------------
+**  ____________________________________________________________________________________________________
+** |     Queue Name      |  Queue Status  | Head & Tail Pointer |         Last Pointer Update           |
+** |_____________________|________________|_____________________|_______________________________________|
+** | Inbound Post Queue  |      Empty     |       Equal         | Tail pointer last updated by software |
+** |_____________________|________________|_____________________|_______________________________________|
+** | Inbound Free Queue  |      Empty     |       Equal         | Head pointer last updated by hardware |
+** |_____________________|________________|_____________________|_______________________________________|
+**************************************************************************
+**************************************************************************
+**       Index Registers
+**  ========================
+**  . The Index Registers are a set of 1004 registers that when written
+**    by an external PCI agent can generate an interrupt to the Intel XScale core.
+**    These registers are for inbound messages only.
+**    The interrupt is recorded in the Inbound Interrupt Status Register.
+**    The storage for the Index Registers is allocated from the 80331 local memory.
+**    PCI write accesses to the Index Registers write the data to local memory.
+**    PCI read accesses to the Index Registers read the data from local memory.
+**  . The local memory used for the Index Registers ranges from Inbound ATU Translate Value Register + 050H
+**                                                           to Inbound ATU Translate Value Register + FFFH.
+**  . The address of the first write access is stored in the Index Address Register.
+**    This register is written during the earliest write access and provides
+**    a means to determine which Index Register was written.
+**    Once updated by the MU, the Index Address Register is not updated until
+**    the Index Register Interrupt bit in the Inbound Interrupt Status Register is cleared.
+**  . When the interrupt is cleared, the Index Address Register
+**    is re-enabled and stores the address of the next Index Register write access.
+**    Writes by the Intel XScale core to the local memory used by the Index Registers
+**    does not cause an interrupt and does not update the Index Address Register.
+**  . The index registers can be accessed with Multi-DWORD reads and single QWORD aligned writes.
+**************************************************************************
+**************************************************************************
+**    Messaging Unit Internal Bus Memory Map
+**  =======================================
+**  Internal Bus Address___Register Description (Name)____________________|_PCI Configuration Space Register Number_
+**  FFFF E300H             reserved                                       |
+**    ..                     ..                                           |
+**  FFFF E30CH             reserved                                       |
+**  FFFF E310H             Inbound Message Register 0                     | Available through
+**  FFFF E314H             Inbound Message Register 1                     | ATU Inbound Translation Window
+**  FFFF E318H             Outbound Message Register 0                    |
+**  FFFF E31CH             Outbound Message Register 1                    | or
+**  FFFF E320H             Inbound Doorbell Register                      |
+**  FFFF E324H             Inbound Interrupt Status Register              | must translate PCI address to
+**  FFFF E328H             Inbound Interrupt Mask Register                | the Intel Xscale Core
+**  FFFF E32CH             Outbound Doorbell Register                     | Memory-Mapped Address
+**  FFFF E330H             Outbound Interrupt Status Register             |
+**  FFFF E334H             Outbound Interrupt Mask Register               |
+**  ______________________________________________________________________|________________________________________
+**  FFFF E338H             reserved                                       |
+**  FFFF E33CH             reserved                                       |
+**  FFFF E340H             reserved                                       |
+**  FFFF E344H             reserved                                       |
+**  FFFF E348H             reserved                                       |
+**  FFFF E34CH             reserved                                       |
+**  FFFF E350H             MU Configuration Register                      |
+**  FFFF E354H             Queue Base Address Register                    |
+**  FFFF E358H             reserved                                       |
+**  FFFF E35CH             reserved                                       | must translate PCI address to
+**  FFFF E360H             Inbound Free Head Pointer Register             | the Intel Xscale Core
+**  FFFF E364H             Inbound Free Tail Pointer Register             | Memory-Mapped Address
+**  FFFF E368H             Inbound Post Head pointer Register             |
+**  FFFF E36CH             Inbound Post Tail Pointer Register             |
+**  FFFF E370H             Outbound Free Head Pointer Register            |
+**  FFFF E374H             Outbound Free Tail Pointer Register            |
+**  FFFF E378H             Outbound Post Head pointer Register            |
+**  FFFF E37CH             Outbound Post Tail Pointer Register            |
+**  FFFF E380H             Index Address Register                         |
+**  FFFF E384H             reserved                                       |
+**   ..                       ..                                          |
+**  FFFF E3FCH             reserved                                       |
+**  ______________________________________________________________________|_______________________________________
+**************************************************************************
+**************************************************************************
+**  MU Configuration Register - MUCR  FFFF.E350H
+**
+**  . The MU Configuration Register (MUCR) contains the Circular Queue Enable bit and the size of one Circular Queue.
+**  . The Circular Queue Enable bit enables or disables the Circular Queues.
+**    The Circular Queues are disabled at reset to allow the software to initialize
+**    the head and tail pointer registers before any PCI accesses to the Queue Ports.
+**  . Each Circular Queue may range from 4 K entries (16 Kbytes) to 64 K entries (256 Kbytes) and there are four Circular Queues.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:06     000000H 00 2                  Reserved
+**  05:01     00001 2                       Circular Queue Size - This field determines the size of each Circular Queue.
+**                                                                All four queues are the same size.
+**  								E 00001 2 - 4K Entries (16 Kbytes)
+**  								E 00010 2 - 8K Entries (32 Kbytes)
+**  								E 00100 2 - 16K Entries (64 Kbytes)
+**  								E 01000 2 - 32K Entries (128 Kbytes)
+**  								E 10000 2 - 64K Entries (256 Kbytes)
+**  00        0 2                         Circular Queue Enable - This bit enables
+**  						or disables the Circular Queues. When clear the Circular
+**  						Queues are disabled, however the MU accepts
+**  						PCI accesses to the Circular Queue Ports but ignores
+**  						the data for Writes and return FFFF.FFFFH for Reads.
+**  						Interrupts are not generated to the core when
+**  						disabled. When set, the Circular Queues are fully enabled.
+**************************************************************************
+**************************************************************************
+**  Queue Base Address Register - QBAR
+**
+**  . The Queue Base Address Register (QBAR) contains the local memory address of the Circular Queues.
+**    The base address is required to be located on a 1 Mbyte address boundary.
+**  . All Circular Queue head and tail pointers are based on the QBAR.
+**    When the head and tail pointer registers are read, the Queue Base Address is returned in the upper 12 bits.
+**    Writing to the upper 12 bits of the head and tail pointer registers
+**    does not affect the Queue Base Address or Queue Base Address Register.
+**  Warning:
+**         The QBAR must designate a range allocated to the 80331 DDR SDRAM interface
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20     000H                          Queue Base Address - Local memory address of the circular queues.
+**  19:00     00000H                        Reserved
+**************************************************************************
+**************************************************************************
+**  Inbound Free Head Pointer Register - IFHPR
+**
+**  . The Inbound Free Head Pointer Register (IFHPR) contains the local memory offset
+**    from the Queue Base Address of the head pointer for the Inbound Free Queue.
+**    The Head Pointer must be aligned on a DWORD address boundary.
+**    When read, the Queue Base Address is provided in the upper 12 bits of the register.
+**    Writes to the upper 12 bits of the register are ignored.
+**    This register is maintained by software.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20     000H                        Queue Base Address - Local memory address of the circular queues.
+**  19:02     0000H 00 2                  Inbound Free Head Pointer - Local memory offset
+**						of the head pointer for the Inbound Free Queue.
+**  01:00     00 2                        Reserved
+**************************************************************************
+**************************************************************************
+**  Inbound Free Tail Pointer Register - IFTPR
+**
+**  . The Inbound Free Tail Pointer Register (IFTPR) contains the local memory offset from the Queue
+**    Base Address of the tail pointer for the Inbound Free Queue. The Tail Pointer must be aligned on a
+**    DWORD address boundary. When read, the Queue Base Address is provided in the upper 12 bits
+**    of the register. Writes to the upper 12 bits of the register are ignored.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20     000H                        Queue Base Address - Local memory address of the circular queues.
+**  19:02     0000H 00 2                  Inbound Free Tail Pointer - Local memory
+**						offset of the tail pointer for the Inbound Free Queue.
+**  01:00     00 2                        Reserved
+**************************************************************************
+**************************************************************************
+**  Inbound Post Head Pointer Register - IPHPR
+**
+**  . The Inbound Post Head Pointer Register (IPHPR) contains the local memory offset from the Queue
+**    Base Address of the head pointer for the Inbound Post Queue. The Head Pointer must be aligned on
+**    a DWORD address boundary. When read, the Queue Base Address is provided in the upper 12 bits
+**    of the register. Writes to the upper 12 bits of the register are ignored.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20     000H                        Queue Base Address - Local memory address of the circular queues.
+**  19:02     0000H 00 2                  Inbound Post Head Pointer - Local memory offset
+**						of the head pointer for the Inbound Post Queue.
+**  01:00     00 2                        Reserved
+**************************************************************************
+**************************************************************************
+**  Inbound Post Tail Pointer Register - IPTPR
+**
+**  . The Inbound Post Tail Pointer Register (IPTPR) contains the local memory offset from the Queue
+**    Base Address of the tail pointer for the Inbound Post Queue. The Tail Pointer must be aligned on a
+**    DWORD address boundary. When read, the Queue Base Address is provided in the upper 12 bits
+**    of the register. Writes to the upper 12 bits of the register are ignored.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:20     000H                        Queue Base Address - Local memory address of the circular queues.
+**  19:02     0000H 00 2                  Inbound Post Tail Pointer - Local memory offset of
+**						the tail pointer for the Inbound Post Queue.
+**  01:00     00 2                        Reserved
+**************************************************************************
+**************************************************************************
+**  Index Address Register - IAR
+**
+**  . The Index Address Register (IAR) contains the offset of the least recently accessed Index Register.
+**    It is written by the MU when the Index Registers are written by a PCI agent.
+**    The register is not updated until the Index Interrupt bit in the Inbound Interrupt Status Register is cleared.
+**  . The local memory address of the Index Register least recently
+**    accessed is computed by adding the Index Address Register to the Inbound ATU Translate Value Register.
+**  ------------------------------------------------------------------------
+**  Bit       Default                       Description
+**  31:12     000000H                       Reserved
+**  11:02     00H 00 2                      Index Address - is the local memory offset of the Index Register written (050H to FFCH)
+**  01:00     00 2                          Reserved
+**************************************************************************
+*******************************************************************************
+**                            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)
+*******************************************************************************
+***************************************************************************
+**                                RS-232 Interface for Areca Raid Controller
+**                    The low level command interface is exclusive with VT100 terminal
+**  --------------------------------------------------------------------
+**    1. Sequence of command execution
+**  --------------------------------------------------------------------
+**    	(A) Header : 3 bytes sequence (0x5E, 0x01, 0x61)
+**    	(B) Command block : variable length of data including length, command code, data and checksum byte
+**    	(C) Return data : variable length of data
+**  --------------------------------------------------------------------
+**    2. Command block
+**  --------------------------------------------------------------------
+**    	(A) 1st byte : command block length (low byte)
+**    	(B) 2nd byte : command block length (high byte)
+**                note ..command block length shouldn't > 2040 bytes, length excludes these two bytes
+**    	(C) 3rd byte : command code
+**    	(D) 4th and following bytes : variable length data bytes depends on command code
+**    	(E) last byte : checksum byte (sum of 1st byte until last data byte)
+**  --------------------------------------------------------------------
+**    3. Command code and associated data
+**  --------------------------------------------------------------------
+**    	The following are command code defined in raid controller Command
+**    	code 0x10--0x1? are used for system level management,
+**    	no password checking is needed and should be implemented in separate well controlled utility and not for end user access.
+**    	Command code 0x20--0x?? always check the password, password must be entered to enable these command.
+**    	enum
+**    	{
+**    		GUI_SET_SERIAL=0x10,
+**    		GUI_SET_VENDOR,
+**    		GUI_SET_MODEL,
+**    		GUI_IDENTIFY,
+**    		GUI_CHECK_PASSWORD,
+**    		GUI_LOGOUT,
+**    		GUI_HTTP,
+**    		GUI_SET_ETHERNET_ADDR,
+**    		GUI_SET_LOGO,
+**    		GUI_POLL_EVENT,
+**    		GUI_GET_EVENT,
+**    		GUI_GET_HW_MONITOR,
+**
+**    		//    GUI_QUICK_CREATE=0x20, (function removed)
+**    		GUI_GET_INFO_R=0x20,
+**    		GUI_GET_INFO_V,
+**    		GUI_GET_INFO_P,
+**    		GUI_GET_INFO_S,
+**    		GUI_CLEAR_EVENT,
+**
+**    		GUI_MUTE_BEEPER=0x30,
+**    		GUI_BEEPER_SETTING,
+**    		GUI_SET_PASSWORD,
+**    		GUI_HOST_INTERFACE_MODE,
+**    		GUI_REBUILD_PRIORITY,
+**    		GUI_MAX_ATA_MODE,
+**    		GUI_RESET_CONTROLLER,
+**    		GUI_COM_PORT_SETTING,
+**    		GUI_NO_OPERATION,
+**    		GUI_DHCP_IP,
+**
+**    		GUI_CREATE_PASS_THROUGH=0x40,
+**    		GUI_MODIFY_PASS_THROUGH,
+**    		GUI_DELETE_PASS_THROUGH,
+**    		GUI_IDENTIFY_DEVICE,
+**
+**    		GUI_CREATE_RAIDSET=0x50,
+**    		GUI_DELETE_RAIDSET,
+**    		GUI_EXPAND_RAIDSET,
+**    		GUI_ACTIVATE_RAIDSET,
+**    		GUI_CREATE_HOT_SPARE,
+**    		GUI_DELETE_HOT_SPARE,
+**
+**    		GUI_CREATE_VOLUME=0x60,
+**    		GUI_MODIFY_VOLUME,
+**    		GUI_DELETE_VOLUME,
+**    		GUI_START_CHECK_VOLUME,
+**    		GUI_STOP_CHECK_VOLUME
+**    	};
+**
+**    Command description :
+**
+**    	GUI_SET_SERIAL : Set the controller serial#
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x10
+**    		byte 3          : password length (should be 0x0f)
+**    		byte 4-0x13     : should be "ArEcATecHnoLogY"
+**    		byte 0x14--0x23 : Serial number string (must be 16 bytes)
+**      GUI_SET_VENDOR : Set vendor string for the controller
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x11
+**    		byte 3          : password length (should be 0x08)
+**    		byte 4-0x13     : should be "ArEcAvAr"
+**    		byte 0x14--0x3B : vendor string (must be 40 bytes)
+**      GUI_SET_MODEL : Set the model name of the controller
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x12
+**    		byte 3          : password length (should be 0x08)
+**    		byte 4-0x13     : should be "ArEcAvAr"
+**    		byte 0x14--0x1B : model string (must be 8 bytes)
+**      GUI_IDENTIFY : Identify device
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x13
+**    		                  return "Areca RAID Subsystem "
+**      GUI_CHECK_PASSWORD : Verify password
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x14
+**    		byte 3          : password length
+**    		byte 4-0x??     : user password to be checked
+**      GUI_LOGOUT : Logout GUI (force password checking on next command)
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x15
+**      GUI_HTTP : HTTP interface (reserved for Http proxy service)(0x16)
+**
+**      GUI_SET_ETHERNET_ADDR : Set the ethernet MAC address
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x17
+**    		byte 3          : password length (should be 0x08)
+**    		byte 4-0x13     : should be "ArEcAvAr"
+**    		byte 0x14--0x19 : Ethernet MAC address (must be 6 bytes)
+**      GUI_SET_LOGO : Set logo in HTTP
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x18
+**    		byte 3          : Page# (0/1/2/3) (0xff --> clear OEM logo)
+**    		byte 4/5/6/7    : 0x55/0xaa/0xa5/0x5a
+**    		byte 8          : TITLE.JPG data (each page must be 2000 bytes)
+**    		                  note .... page0 1st 2 byte must be actual length of the JPG file
+**      GUI_POLL_EVENT : Poll If Event Log Changed
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x19
+**      GUI_GET_EVENT : Read Event
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x1a
+**    		byte 3          : Event Page (0:1st page/1/2/3:last page)
+**      GUI_GET_HW_MONITOR : Get HW monitor data
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x1b
+**    		byte 3 			: # of FANs(example 2)
+**    		byte 4 			: # of Voltage sensor(example 3)
+**    		byte 5 			: # of temperature sensor(example 2)
+**    		byte 6 			: # of power
+**    		byte 7/8        : Fan#0 (RPM)
+**    		byte 9/10       : Fan#1
+**    		byte 11/12 		: Voltage#0 original value in *1000
+**    		byte 13/14 		: Voltage#0 value
+**    		byte 15/16 		: Voltage#1 org
+**    		byte 17/18 		: Voltage#1
+**    		byte 19/20 		: Voltage#2 org
+**    		byte 21/22 		: Voltage#2
+**    		byte 23 		: Temp#0
+**    		byte 24 		: Temp#1
+**    		byte 25 		: Power indicator (bit0 : power#0, bit1 : power#1)
+**    		byte 26 		: UPS indicator
+**      GUI_QUICK_CREATE : Quick create raid/volume set
+**    	    byte 0,1        : length
+**    	    byte 2          : command code 0x20
+**    	    byte 3/4/5/6    : raw capacity
+**    	    byte 7 			: raid level
+**    	    byte 8 			: stripe size
+**    	    byte 9 			: spare
+**    	    byte 10/11/12/13: device mask (the devices to create raid/volume)
+**    		                  This function is removed, application like to implement quick create function
+**    		                  need to use GUI_CREATE_RAIDSET and GUI_CREATE_VOLUMESET function.
+**      GUI_GET_INFO_R : Get Raid Set Information
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x20
+**    		byte 3          : raidset#
+**
+**    	typedef struct sGUI_RAIDSET
+**    	{
+**    		BYTE grsRaidSetName[16];
+**    		DWORD grsCapacity;
+**    		DWORD grsCapacityX;
+**    		DWORD grsFailMask;
+**    		BYTE grsDevArray[32];
+**    		BYTE grsMemberDevices;
+**    		BYTE grsNewMemberDevices;
+**    		BYTE grsRaidState;
+**    		BYTE grsVolumes;
+**    		BYTE grsVolumeList[16];
+**    		BYTE grsRes1;
+**    		BYTE grsRes2;
+**    		BYTE grsRes3;
+**    		BYTE grsFreeSegments;
+**    		DWORD grsRawStripes[8];
+**    		DWORD grsRes4;
+**    		DWORD grsRes5; //     Total to 128 bytes
+**    		DWORD grsRes6; //     Total to 128 bytes
+**    	} sGUI_RAIDSET, *pGUI_RAIDSET;
+**      GUI_GET_INFO_V : Get Volume Set Information
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x21
+**    		byte 3          : volumeset#
+**
+**    	typedef struct sGUI_VOLUMESET
+**    	{
+**    		BYTE gvsVolumeName[16]; //     16
+**    		DWORD gvsCapacity;
+**    		DWORD gvsCapacityX;
+**    		DWORD gvsFailMask;
+**    		DWORD gvsStripeSize;
+**    		DWORD gvsNewFailMask;
+**    		DWORD gvsNewStripeSize;
+**    		DWORD gvsVolumeStatus;
+**    		DWORD gvsProgress; //     32
+**    		sSCSI_ATTR gvsScsi;
+**    		BYTE gvsMemberDisks;
+**    		BYTE gvsRaidLevel; //     8
+**
+**    		BYTE gvsNewMemberDisks;
+**    		BYTE gvsNewRaidLevel;
+**    		BYTE gvsRaidSetNumber;
+**    		BYTE gvsRes0; //     4
+**    		BYTE gvsRes1[4]; //     64 bytes
+**    	} sGUI_VOLUMESET, *pGUI_VOLUMESET;
+**
+**      GUI_GET_INFO_P : Get Physical Drive Information
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x22
+**    		byte 3          : drive # (from 0 to max-channels - 1)
+**
+**    	typedef struct sGUI_PHY_DRV
+**    	{
+**    		BYTE gpdModelName[40];
+**    		BYTE gpdSerialNumber[20];
+**    		BYTE gpdFirmRev[8];
+**    		DWORD gpdCapacity;
+**    		DWORD gpdCapacityX; //     Reserved for expansion
+**    		BYTE gpdDeviceState;
+**    		BYTE gpdPioMode;
+**    		BYTE gpdCurrentUdmaMode;
+**    		BYTE gpdUdmaMode;
+**    		BYTE gpdDriveSelect;
+**    		BYTE gpdRaidNumber; //     0xff if not belongs to a raid set
+**    		sSCSI_ATTR gpdScsi;
+**    		BYTE gpdReserved[40]; //     Total to 128 bytes
+**    	} sGUI_PHY_DRV, *pGUI_PHY_DRV;
+**
+**    	GUI_GET_INFO_S : Get System Information
+**      	byte 0,1        : length
+**      	byte 2          : command code 0x23
+**
+**    	typedef struct sCOM_ATTR
+**    	{
+**    		BYTE comBaudRate;
+**    		BYTE comDataBits;
+**    		BYTE comStopBits;
+**    		BYTE comParity;
+**    		BYTE comFlowControl;
+**    	} sCOM_ATTR, *pCOM_ATTR;
+**
+**    	typedef struct sSYSTEM_INFO
+**    	{
+**    		BYTE gsiVendorName[40];
+**    		BYTE gsiSerialNumber[16];
+**    		BYTE gsiFirmVersion[16];
+**    		BYTE gsiBootVersion[16];
+**    		BYTE gsiMbVersion[16];
+**    		BYTE gsiModelName[8];
+**    		BYTE gsiLocalIp[4];
+**    		BYTE gsiCurrentIp[4];
+**    		DWORD gsiTimeTick;
+**    		DWORD gsiCpuSpeed;
+**    		DWORD gsiICache;
+**    		DWORD gsiDCache;
+**    		DWORD gsiScache;
+**    		DWORD gsiMemorySize;
+**    		DWORD gsiMemorySpeed;
+**    		DWORD gsiEvents;
+**    		BYTE gsiMacAddress[6];
+**    		BYTE gsiDhcp;
+**    		BYTE gsiBeeper;
+**    		BYTE gsiChannelUsage;
+**    		BYTE gsiMaxAtaMode;
+**    		BYTE gsiSdramEcc; //     1:if ECC enabled
+**    		BYTE gsiRebuildPriority;
+**    		sCOM_ATTR gsiComA; //     5 bytes
+**    		sCOM_ATTR gsiComB; //     5 bytes
+**    		BYTE gsiIdeChannels;
+**    		BYTE gsiScsiHostChannels;
+**    		BYTE gsiIdeHostChannels;
+**    		BYTE gsiMaxVolumeSet;
+**    		BYTE gsiMaxRaidSet;
+**    		BYTE gsiEtherPort; //     1:if ether net port supported
+**    		BYTE gsiRaid6Engine; //     1:Raid6 engine supported
+**    		BYTE gsiRes[75];
+**    	} sSYSTEM_INFO, *pSYSTEM_INFO;
+**
+**    	GUI_CLEAR_EVENT : Clear System Event
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x24
+**
+**      GUI_MUTE_BEEPER : Mute current beeper
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x30
+**
+**      GUI_BEEPER_SETTING : Disable beeper
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x31
+**    		byte 3          : 0->disable, 1->enable
+**
+**      GUI_SET_PASSWORD : Change password
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x32
+**    		byte 3 			: pass word length ( must <= 15 )
+**    		byte 4 			: password (must be alpha-numerical)
+**
+**    	GUI_HOST_INTERFACE_MODE : Set host interface mode
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x33
+**    		byte 3 			: 0->Independent, 1->cluster
+**
+**      GUI_REBUILD_PRIORITY : Set rebuild priority
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x34
+**    		byte 3 			: 0/1/2/3 (low->high)
+**
+**      GUI_MAX_ATA_MODE : Set maximum ATA mode to be used
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x35
+**    		byte 3 			: 0/1/2/3 (133/100/66/33)
+**
+**      GUI_RESET_CONTROLLER : Reset Controller
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x36
+**                            *Response with VT100 screen (discard it)
+**
+**      GUI_COM_PORT_SETTING : COM port setting
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x37
+**    		byte 3 			: 0->COMA (term port), 1->COMB (debug port)
+**    		byte 4 			: 0/1/2/3/4/5/6/7 (1200/2400/4800/9600/19200/38400/57600/115200)
+**    		byte 5 			: data bit (0:7 bit, 1:8 bit : must be 8 bit)
+**    		byte 6 			: stop bit (0:1, 1:2 stop bits)
+**    		byte 7 			: parity (0:none, 1:off, 2:even)
+**    		byte 8 			: flow control (0:none, 1:xon/xoff, 2:hardware => must use none)
+**
+**      GUI_NO_OPERATION : No operation
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x38
+**
+**      GUI_DHCP_IP : Set DHCP option and local IP address
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x39
+**    		byte 3          : 0:dhcp disabled, 1:dhcp enabled
+**    		byte 4/5/6/7    : IP address
+**
+**      GUI_CREATE_PASS_THROUGH : Create pass through disk
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x40
+**    		byte 3 			: device #
+**    		byte 4 			: scsi channel (0/1)
+**    		byte 5 			: scsi id (0-->15)
+**    		byte 6 			: scsi lun (0-->7)
+**    		byte 7 			: tagged queue (1 : enabled)
+**    		byte 8 			: cache mode (1 : enabled)
+**    		byte 9 			: max speed (0/1/2/3/4, async/20/40/80/160 for scsi)
+**    								    (0/1/2/3/4, 33/66/100/133/150 for ide  )
+**
+**      GUI_MODIFY_PASS_THROUGH : Modify pass through disk
+**    		byte 0,1        : length
+**    		byte 2 			: command code 0x41
+**    		byte 3 			: device #
+**    		byte 4 			: scsi channel (0/1)
+**    		byte 5 			: scsi id (0-->15)
+**    		byte 6 			: scsi lun (0-->7)
+**    		byte 7 			: tagged queue (1 : enabled)
+**    		byte 8 			: cache mode (1 : enabled)
+**    		byte 9 			: max speed (0/1/2/3/4, async/20/40/80/160 for scsi)
+**    							        (0/1/2/3/4, 33/66/100/133/150 for ide  )
+**
+**      GUI_DELETE_PASS_THROUGH : Delete pass through disk
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x42
+**    		byte 3          : device# to be deleted
+**
+**      GUI_IDENTIFY_DEVICE : Identify Device
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x43
+**    		byte 3          : Flash Method(0:flash selected, 1:flash not selected)
+**    		byte 4/5/6/7    : IDE device mask to be flashed
+**                           note .... no response data available
+**
+**    	GUI_CREATE_RAIDSET : Create Raid Set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x50
+**    		byte 3/4/5/6    : device mask
+**    		byte 7-22       : raidset name (if byte 7 == 0:use default)
+**
+**      GUI_DELETE_RAIDSET : Delete Raid Set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x51
+**    		byte 3          : raidset#
+**
+**    	GUI_EXPAND_RAIDSET : Expand Raid Set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x52
+**    		byte 3          : raidset#
+**    		byte 4/5/6/7    : device mask for expansion
+**    		byte 8/9/10     : (8:0 no change, 1 change, 0xff:terminate, 9:new raid level,10:new stripe size 0/1/2/3/4/5->4/8/16/32/64/128K )
+**    		byte 11/12/13   : repeat for each volume in the raidset ....
+**
+**      GUI_ACTIVATE_RAIDSET : Activate incomplete raid set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x53
+**    		byte 3          : raidset#
+**
+**      GUI_CREATE_HOT_SPARE : Create hot spare disk
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x54
+**    		byte 3/4/5/6    : device mask for hot spare creation
+**
+**    	GUI_DELETE_HOT_SPARE : Delete hot spare disk
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x55
+**    		byte 3/4/5/6    : device mask for hot spare deletion
+**
+**    	GUI_CREATE_VOLUME : Create volume set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x60
+**    		byte 3          : raidset#
+**    		byte 4-19       : volume set name (if byte4 == 0, use default)
+**    		byte 20-27      : volume capacity (blocks)
+**    		byte 28 		: raid level
+**    		byte 29 		: stripe size (0/1/2/3/4/5->4/8/16/32/64/128K)
+**    		byte 30 		: channel
+**    		byte 31 		: ID
+**    		byte 32 		: LUN
+**    		byte 33 		: 1 enable tag
+**    		byte 34 		: 1 enable cache
+**    		byte 35 		: speed (0/1/2/3/4->async/20/40/80/160 for scsi)
+**    								(0/1/2/3/4->33/66/100/133/150 for IDE  )
+**    		byte 36 		: 1 to select quick init
+**
+**    	GUI_MODIFY_VOLUME : Modify volume Set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x61
+**    		byte 3          : volumeset#
+**    		byte 4-19       : new volume set name (if byte4 == 0, not change)
+**    		byte 20-27      : new volume capacity (reserved)
+**    		byte 28 		: new raid level
+**    		byte 29 		: new stripe size (0/1/2/3/4/5->4/8/16/32/64/128K)
+**    		byte 30 		: new channel
+**    		byte 31 		: new ID
+**    		byte 32 		: new LUN
+**    		byte 33 		: 1 enable tag
+**    		byte 34 		: 1 enable cache
+**    		byte 35 		: speed (0/1/2/3/4->async/20/40/80/160 for scsi)
+**    								(0/1/2/3/4->33/66/100/133/150 for IDE  )
+**
+**    	GUI_DELETE_VOLUME : Delete volume set
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x62
+**    		byte 3          : volumeset#
+**
+**    	GUI_START_CHECK_VOLUME : Start volume consistency check
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x63
+**    		byte 3          : volumeset#
+**
+**    	GUI_STOP_CHECK_VOLUME : Stop volume consistency check
+**    		byte 0,1        : length
+**    		byte 2          : command code 0x64
+** ---------------------------------------------------------------------
+**    4. Returned data
+** ---------------------------------------------------------------------
+**    	(A) Header          : 3 bytes sequence (0x5E, 0x01, 0x61)
+**    	(B) Length          : 2 bytes (low byte 1st, excludes length and checksum byte)
+**    	(C) status or data  :
+**           <1> If length == 1 ==> 1 byte status code
+**    								#define GUI_OK                    0x41
+**    								#define GUI_RAIDSET_NOT_NORMAL    0x42
+**    								#define GUI_VOLUMESET_NOT_NORMAL  0x43
+**    								#define GUI_NO_RAIDSET            0x44
+**    								#define GUI_NO_VOLUMESET          0x45
+**    								#define GUI_NO_PHYSICAL_DRIVE     0x46
+**    								#define GUI_PARAMETER_ERROR       0x47
+**    								#define GUI_UNSUPPORTED_COMMAND   0x48
+**    								#define GUI_DISK_CONFIG_CHANGED   0x49
+**    								#define GUI_INVALID_PASSWORD      0x4a
+**    								#define GUI_NO_DISK_SPACE         0x4b
+**    								#define GUI_CHECKSUM_ERROR        0x4c
+**    								#define GUI_PASSWORD_REQUIRED     0x4d
+**           <2> If length > 1 ==> data block returned from controller and the contents depends on the command code
+**        (E) Checksum : checksum of length and status or data byte
+**************************************************************************
+
diff -urN oldtree/MAINTAINERS newtree/MAINTAINERS
--- oldtree/MAINTAINERS	2006-04-01 04:48:27.000000000 -0500
+++ newtree/MAINTAINERS	2006-04-01 05:36:13.517214500 -0500
@@ -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
@@ -1400,6 +1407,12 @@
 L:	linux-mips@linux-mips.org
 S:	Maintained
 
+IOCTL REGISTRY (Documentation/ioctl-mess.txt)
+P:	Alexey Dobriyan
+M:	adobriyan@gmail.com
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 IP MASQUERADING:
 P:	Juanjo Ciarlante
 M:	jjciarla@raiz.uncu.edu.ar
diff -urN oldtree/arch/alpha/kernel/setup.c newtree/arch/alpha/kernel/setup.c
--- oldtree/arch/alpha/kernel/setup.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/alpha/kernel/setup.c	2006-04-01 05:35:38.115002000 -0500
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/platform_device.h>
 #include <linux/bootmem.h>
 #include <linux/pci.h>
 #include <linux/seq_file.h>
@@ -1484,3 +1485,20 @@
 #endif
         return NOTIFY_DONE;
 }
+
+static __init int add_pcspkr(void)
+{
+	struct platform_device *pd;
+	int ret;
+
+	pd = platform_device_alloc("pcspkr", -1);
+	if (!pd)
+		return -ENOMEM;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		platform_device_put(pd);
+
+	return ret;
+}
+device_initcall(add_pcspkr);
diff -urN oldtree/arch/arm/Kconfig newtree/arch/arm/Kconfig
--- oldtree/arch/arm/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/arm/Kconfig	2006-04-01 05:35:57.300201000 -0500
@@ -809,6 +809,8 @@
 
 source "drivers/mfd/Kconfig"
 
+source "drivers/leds/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
diff -urN oldtree/arch/arm/common/sharpsl_pm.c newtree/arch/arm/common/sharpsl_pm.c
--- oldtree/arch/arm/common/sharpsl_pm.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/arm/common/sharpsl_pm.c	2006-04-01 05:35:57.356204500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/arm/mach-pxa/corgi.c	2006-04-01 05:35:57.372205500 -0500
@@ -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/spitz.c newtree/arch/arm/mach-pxa/spitz.c
--- oldtree/arch/arm/mach-pxa/spitz.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/arm/mach-pxa/spitz.c	2006-04-01 05:35:57.372205500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/arm/mach-pxa/tosa.c	2006-04-01 05:35:57.420208500 -0500
@@ -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/frv/kernel/entry.S newtree/arch/frv/kernel/entry.S
--- oldtree/arch/frv/kernel/entry.S	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/entry.S	2006-04-01 05:36:15.325327500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/irq-routing.c	2006-04-01 05:36:15.325327500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/irq.c	2006-04-01 05:36:15.325327500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/pm.c	2006-04-01 05:36:15.325327500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/process.c	2006-04-01 05:36:15.325327500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/signal.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/sys_frv.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/sysctl.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/kernel/uaccess.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/mb93090-mb00/pci-irq.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/frv/mm/kmap.c	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/i386/Kconfig.debug	2006-04-01 05:36:13.697225750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/i386/kernel/acpi/processor.c	2006-04-01 05:35:30.682537500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c	2006-04-01 05:35:30.886550250 -0500
@@ -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,95 @@
 			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_HOTPLUG_CPU
+	/* cpufreq holds the hotplug lock, so we are safe from here on */
+	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#else
+	online_policy_cpus = 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 +331,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 +399,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 +451,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 +461,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 +480,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 +500,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 +521,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 +567,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 +579,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/speedstep-centrino.c newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
--- oldtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c	2006-04-01 05:35:30.890550500 -0500
@@ -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,128 @@
 			    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;
-	}
-
-	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;
+	if (unlikely(cpufreq_frequency_table_target(policy,
+			centrino_model[cpu]->op_points,
+			target_freq,
+			relation,
+			&newstate))) {
+		return -EINVAL;
 	}
 
-	freqs.cpu = cpu;
-	freqs.old = extract_clock(oldmsr, cpu, 0);
-	freqs.new = extract_clock(msr, cpu, 0);
+#ifdef CONFIG_HOTPLUG_CPU
+	/* cpufreq holds the hotplug lock, so we are safe from here on */
+	cpus_and(online_policy_cpus, cpu_online_map, policy->cpus);
+#else
+	online_policy_cpus = 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 +797,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/setup.c newtree/arch/i386/kernel/setup.c
--- oldtree/arch/i386/kernel/setup.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/i386/kernel/setup.c	2006-04-01 05:35:38.115002000 -0500
@@ -34,6 +34,7 @@
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
+#include <linux/platform_device.h>
 #include <linux/console.h>
 #include <linux/mca.h>
 #include <linux/root_dev.h>
@@ -1634,6 +1635,23 @@
 #endif
 }
 
+static __init int add_pcspkr(void)
+{
+	struct platform_device *pd;
+	int ret;
+
+	pd = platform_device_alloc("pcspkr", -1);
+	if (!pd)
+		return -ENOMEM;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		platform_device_put(pd);
+
+	return ret;
+}
+device_initcall(add_pcspkr);
+
 #include "setup_arch_post.h"
 /*
  * Local Variables:
diff -urN oldtree/arch/ia64/Kconfig newtree/arch/ia64/Kconfig
--- oldtree/arch/ia64/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/ia64/Kconfig	2006-04-01 05:35:33.190694250 -0500
@@ -69,6 +69,7 @@
 config IA64_GENERIC
 	bool "generic"
 	select ACPI
+	select PCI
 	select NUMA
 	select ACPI_NUMA
 	help
diff -urN oldtree/arch/m32r/kernel/entry.S newtree/arch/m32r/kernel/entry.S
--- oldtree/arch/m32r/kernel/entry.S	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/entry.S	2006-04-01 05:36:15.277324500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/setup.c	2006-04-01 05:36:15.277324500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/setup_mappi.c	2006-04-01 05:36:15.277324500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/signal.c	2006-04-01 05:36:15.277324500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/smp.c	2006-04-01 05:36:15.281324750 -0500
@@ -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/sys_m32r.c newtree/arch/m32r/kernel/sys_m32r.c
--- oldtree/arch/m32r/kernel/sys_m32r.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/sys_m32r.c	2006-04-01 05:36:15.281324750 -0500
@@ -30,7 +30,7 @@
 /*
  * sys_tas() - test-and-set
  */
-asmlinkage int sys_tas(int *addr)
+asmlinkage int sys_tas(int __user *addr)
 {
 	int oldval;
 
@@ -89,7 +89,7 @@
 
 	error = do_pipe(fd);
 	if (!error) {
-		if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int)))
+		if (copy_to_user((void __user *)r0, fd, 2*sizeof(int)))
 			error = -EFAULT;
 	}
 	return error;
@@ -200,7 +200,7 @@
 	}
 }
 
-asmlinkage int sys_uname(struct old_utsname * name)
+asmlinkage int sys_uname(struct old_utsname __user * name)
 {
 	int err;
 	if (!name)
diff -urN oldtree/arch/m32r/kernel/traps.c newtree/arch/m32r/kernel/traps.c
--- oldtree/arch/m32r/kernel/traps.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/kernel/traps.c	2006-04-01 05:36:15.281324750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m32r/mm/mmu.S	2006-04-01 05:36:15.281324750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/kernel/process.c	2006-04-01 05:36:15.301326000 -0500
@@ -222,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,
@@ -362,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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/kernel/traps.c	2006-04-01 05:36:15.301326000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_cond.S	2006-04-01 05:36:15.301326000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_decode.h	2006-04-01 05:36:15.301326000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_move.S	2006-04-01 05:36:15.305326250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_movem.S	2006-04-01 05:36:15.301326000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_scan.S	2006-04-01 05:36:15.305326250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/m68k/math-emu/fp_util.S	2006-04-01 05:36:15.305326250 -0500
@@ -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/mips/Kconfig newtree/arch/mips/Kconfig
--- oldtree/arch/mips/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/mips/Kconfig	2006-04-01 05:35:38.119002250 -0500
@@ -233,6 +233,7 @@
 	select ARC32
 	select ARCH_MAY_HAVE_PC_FDC
 	select GENERIC_ISA_DMA
+	select I8253
 	select I8259
 	select ISA
 	select SYS_HAS_CPU_R4X00
@@ -530,6 +531,7 @@
 	select DMA_COHERENT
 	select GENERIC_ISA_DMA
 	select HAVE_STD_PC_SERIAL_PORT
+	select I8253
 	select I8259
 	select ISA
 	select SWAP_IO_SPACE
@@ -714,6 +716,7 @@
 	select HAVE_STD_PC_SERIAL_PORT
 	select HW_HAS_EISA
 	select HW_HAS_PCI
+	select I8253
 	select I8259
 	select ISA
 	select SYS_HAS_CPU_R4X00
@@ -1711,6 +1714,9 @@
 	bool
 	default y
 
+config I8253
+	bool
+
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -urN oldtree/arch/mips/kernel/Makefile newtree/arch/mips/kernel/Makefile
--- oldtree/arch/mips/kernel/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/mips/kernel/Makefile	2006-04-01 05:35:38.119002250 -0500
@@ -59,6 +59,8 @@
 
 obj-$(CONFIG_64BIT)		+= cpu-bugs64.o
 
+obj-$(CONFIG_I8253)		+= i8253.o
+
 CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -urN oldtree/arch/mips/kernel/i8253.c newtree/arch/mips/kernel/i8253.c
--- oldtree/arch/mips/kernel/i8253.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/arch/mips/kernel/i8253.c	2006-04-01 05:35:38.119002250 -0500
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Implements device information for i8253 timer chip
+ *
+ * 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/platform_device.h>
+
+static __init int add_pcspkr(void)
+{
+	struct platform_device *pd;
+	int ret;
+
+	pd = platform_device_alloc("pcspkr", -1);
+	if (!pd)
+		return -ENOMEM;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		platform_device_put(pd);
+
+	return ret;
+}
+device_initcall(add_pcspkr);
diff -urN oldtree/arch/powerpc/kernel/setup-common.c newtree/arch/powerpc/kernel/setup-common.c
--- oldtree/arch/powerpc/kernel/setup-common.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/powerpc/kernel/setup-common.c	2006-04-01 05:35:38.119002250 -0500
@@ -18,6 +18,7 @@
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
+#include <linux/platform_device.h>
 #include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
@@ -469,3 +470,26 @@
 }
 early_param("xmon", early_xmon);
 #endif
+
+static __init int add_pcspkr(void)
+{
+	struct device_node *np;
+	struct platform_device *pd;
+	int ret;
+
+	np = of_find_compatible_node(NULL, NULL, "pnpPNP,100");
+	of_node_put(np);
+	if (!np)
+		return -ENODEV;
+
+	pd = platform_device_alloc("pcspkr", -1);
+	if (!pd)
+		return -ENOMEM;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		platform_device_put(pd);
+
+	return ret;
+}
+device_initcall(add_pcspkr);
diff -urN oldtree/arch/x86_64/Kconfig newtree/arch/x86_64/Kconfig
--- oldtree/arch/x86_64/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/x86_64/Kconfig	2006-04-01 05:35:33.194694500 -0500
@@ -276,6 +276,7 @@
        bool "ACPI NUMA detection"
        depends on NUMA
        select ACPI 
+	select PCI
        select ACPI_NUMA
        default y
        help
diff -urN oldtree/arch/x86_64/kernel/acpi/Makefile newtree/arch/x86_64/kernel/acpi/Makefile
--- oldtree/arch/x86_64/kernel/acpi/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/arch/x86_64/kernel/acpi/Makefile	2006-04-01 05:35:30.686537750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/arch/x86_64/kernel/acpi/processor.c	1969-12-31 19:00:00.000000000 -0500
@@ -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/block/ll_rw_blk.c newtree/block/ll_rw_blk.c
--- oldtree/block/ll_rw_blk.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/block/ll_rw_blk.c	2006-04-01 05:35:45.867486500 -0500
@@ -2292,7 +2292,7 @@
 	 */
 	uaddr = (unsigned long) ubuf;
 	if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))
-		bio = bio_map_user(q, NULL, uaddr, len, reading);
+		bio = bio_map_user(q, NULL, uaddr, len, reading, 0);
 	else
 		bio = bio_copy_user(q, uaddr, len, reading);
 
@@ -2344,7 +2344,8 @@
 	/* we don't allow misaligned data like bio_map_user() does.  If the
 	 * user is using sg, they're expected to know the alignment constraints
 	 * and respect them accordingly */
-	bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ);
+	bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ,
+				0);
 	if (IS_ERR(bio))
 		return PTR_ERR(bio);
 
diff -urN oldtree/drivers/Kconfig newtree/drivers/Kconfig
--- oldtree/drivers/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/Kconfig	2006-04-01 05:36:00.848422750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/Makefile	2006-04-01 05:36:00.848422750 -0500
@@ -25,9 +25,6 @@
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
-# we also need input/serio early so serio bus is initialized by the time
-# serial drivers start registering their serio ports
-obj-$(CONFIG_SERIO)		+= input/serio/
 obj-y				+= serial/
 obj-$(CONFIG_PARPORT)		+= parport/
 obj-y				+= base/ block/ misc/ mfd/ net/ media/
@@ -53,12 +50,14 @@
 obj-$(CONFIG_USB)		+= usb/
 obj-$(CONFIG_PCI)		+= usb/
 obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
+obj-$(CONFIG_SERIO)		+= input/serio/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 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 +67,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/Kconfig	2006-04-01 05:35:35.730853000 -0500
@@ -10,9 +10,8 @@
 config ACPI
 	bool "ACPI Support"
 	depends on IA64 || X86
+	depends on PCI
 	select PM
-	select PCI
-
 	default y
 	---help---
 	  Advanced Configuration and Power Interface (ACPI) support for 
@@ -231,6 +230,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/Makefile	2006-04-01 05:35:35.730853000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/ac.c	2006-04-01 05:35:30.702538750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/acpi_memhotplug.c	2006-04-01 05:35:34.350766750 -0500
@@ -57,6 +57,7 @@
 
 static int acpi_memory_device_add(struct acpi_device *device);
 static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_start(struct acpi_device *device);
 
 static struct acpi_driver acpi_memory_device_driver = {
 	.name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
@@ -65,48 +66,80 @@
 	.ops = {
 		.add = acpi_memory_device_add,
 		.remove = acpi_memory_device_remove,
+		.start = acpi_memory_device_start,
 		},
 };
 
+struct acpi_memory_info {
+	struct list_head list;
+	u64 start_addr;		/* Memory Range start physical addr */
+	u64 length;		/* Memory Range length */
+	unsigned short caching;	/* memory cache attribute */
+	unsigned short write_protect;	/* memory read/write attribute */
+	unsigned int enabled:1;
+};
+
 struct acpi_memory_device {
 	acpi_handle handle;
 	unsigned int state;	/* State of the memory device */
-	unsigned short caching;	/* memory cache attribute */
-	unsigned short write_protect;	/* memory read/write attribute */
-	u64 start_addr;		/* Memory Range start physical addr */
-	u64 end_addr;		/* Memory Range end physical addr */
+	struct list_head res_list;
 };
 
+static acpi_status
+acpi_memory_get_resource(struct acpi_resource *resource, void *context)
+{
+	struct acpi_memory_device *mem_device = context;
+	struct acpi_resource_address64 address64;
+	struct acpi_memory_info *info, *new;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(resource, &address64);
+	if (ACPI_FAILURE(status) ||
+	    (address64.resource_type != ACPI_MEMORY_RANGE))
+		return AE_OK;
+
+	list_for_each_entry(info, &mem_device->res_list, list) {
+		/* Can we combine the resource range information? */
+		if ((info->caching == address64.info.mem.caching) &&
+		    (info->write_protect == address64.info.mem.write_protect) &&
+		    (info->start_addr + info->length == address64.minimum)) {
+			info->length += address64.address_length;
+			return AE_OK;
+		}
+	}
+
+	new = acpi_os_allocate(sizeof(struct acpi_memory_info));
+	if (!new)
+		return AE_ERROR;
+
+	memset(new, 0, sizeof(*new));
+	INIT_LIST_HEAD(&new->list);
+	new->caching = address64.info.mem.caching;
+	new->write_protect = address64.info.mem.write_protect;
+	new->start_addr = address64.minimum;
+	new->length = address64.address_length;
+	list_add_tail(&new->list, &mem_device->res_list);
+
+	return AE_OK;
+}
+
 static int
 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 {
 	acpi_status status;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	struct acpi_resource *resource = NULL;
-	struct acpi_resource_address64 address64;
+	struct acpi_memory_info *info, *n;
 
 	ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
 
 	/* Get the range from the _CRS */
-	status = acpi_get_current_resources(mem_device->handle, &buffer);
-	if (ACPI_FAILURE(status))
+	status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS,
+				     acpi_memory_get_resource, mem_device);
+	if (ACPI_FAILURE(status)) {
+		list_for_each_entry_safe(info, n, &mem_device->res_list, list)
+			acpi_os_free(info);
 		return_VALUE(-EINVAL);
-
-	resource = (struct acpi_resource *)buffer.pointer;
-	status = acpi_resource_to_address64(resource, &address64);
-	if (ACPI_SUCCESS(status)) {
-		if (address64.resource_type == ACPI_MEMORY_RANGE) {
-			/* Populate the structure */
-			mem_device->caching =
-			    address64.info.mem.caching;
-			mem_device->write_protect =
-			    address64.info.mem.write_protect;
-			mem_device->start_addr = address64.minimum;
-			mem_device->end_addr = address64.maximum;
-		}
 	}
 
-	acpi_os_free(buffer.pointer);
 	return_VALUE(0);
 }
 
@@ -126,15 +159,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 +176,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);
 	}
 
@@ -182,15 +214,15 @@
 
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 {
-	int result;
+	int result, num_enabled = 0;
+	struct acpi_memory_info *info;
 
 	ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
 
 	/* 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;
 	}
@@ -198,13 +230,32 @@
 	/*
 	 * Tell the VM there is more memory here...
 	 * Note: Assume that this function returns zero on success
+    	 * We don't have memory-hot-add rollback function,now.
+         * (i.e. memory-hot-remove function)
 	 */
-	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"));
+	list_for_each_entry(info, &mem_device->res_list, list) {
+		u64 start_pfn, end_pfn;
+
+		start_pfn = info->start_addr >> PAGE_SHIFT;
+		end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT;
+
+		if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) {
+			/* already enabled. try next area */
+			num_enabled++;
+			continue;
+		}
+
+		result = add_memory(info->start_addr, info->length);
+		if (result)
+			continue;
+		info->enabled = 1;
+		num_enabled++;
+	}
+
+	if (!num_enabled) {
+		ACPI_ERROR((AE_INFO, "add_memory failed"));
 		mem_device->state = MEMORY_INVALID_STATE;
-		return result;
+		return -EINVAL;
 	}
 
 	return result;
@@ -228,7 +279,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);
 	}
 
@@ -248,8 +299,7 @@
 static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
 {
 	int result;
-	u64 start = mem_device->start_addr;
-	u64 len = mem_device->end_addr - start + 1;
+	struct acpi_memory_info *info, *n;
 
 	ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
 
@@ -257,17 +307,18 @@
 	 * Ask the VM to offline this memory range.
 	 * 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"));
-		return_VALUE(result);
+	list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
+		if (info->enabled) {
+			result = remove_memory(info->start_addr, info->length);
+			if (result)
+				return_VALUE(result);
+		}
+		acpi_os_free(info);
 	}
 
 	/* 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 +345,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 +360,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 +376,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
 		 */
@@ -358,6 +406,7 @@
 		return_VALUE(-ENOMEM);
 	memset(mem_device, 0, sizeof(struct acpi_memory_device));
 
+	INIT_LIST_HEAD(&mem_device->res_list);
 	mem_device->handle = device->handle;
 	sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
 	sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
@@ -393,6 +442,25 @@
 	return_VALUE(0);
 }
 
+static int acpi_memory_device_start (struct acpi_device *device)
+{
+	struct acpi_memory_device *mem_device;
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_memory_device_start");
+
+	mem_device = acpi_driver_data(device);
+
+	if (!acpi_memory_check_device(mem_device)) {
+		/* call add_memory func */
+		result = acpi_memory_enable_device(mem_device);
+		if (result)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error in acpi_memory_enable_device\n"));
+	}
+	return_VALUE(result);
+}
+
 /*
  * Helper function to check for memory device
  */
@@ -407,7 +475,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 +501,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 +521,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 +551,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 +575,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/asus_acpi.c	2006-04-01 05:35:35.706851500 -0500
@@ -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
@@ -817,7 +817,7 @@
 			      unsigned long count, void *data);
 
 static int
-__init asus_proc_add(char *name, proc_writefunc * writefunc,
+asus_proc_add(char *name, proc_writefunc * writefunc,
 		     proc_readfunc * readfunc, mode_t mode,
 		     struct acpi_device *device)
 {
@@ -836,7 +836,7 @@
 	return 0;
 }
 
-static int __init asus_hotk_add_fs(struct acpi_device *device)
+static int asus_hotk_add_fs(struct acpi_device *device)
 {
 	struct proc_dir_entry *proc;
 	mode_t mode;
@@ -954,7 +954,7 @@
  * This function is used to initialize the hotk with right values. In this
  * method, we can make all the detection we want, and modify the hotk struct
  */
-static int __init asus_hotk_get_info(void)
+static int asus_hotk_get_info(void)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -1101,7 +1101,7 @@
 	return AE_OK;
 }
 
-static int __init asus_hotk_check(void)
+static int asus_hotk_check(void)
 {
 	int result = 0;
 
@@ -1119,7 +1119,9 @@
 	return result;
 }
 
-static int __init asus_hotk_add(struct acpi_device *device)
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
 {
 	acpi_status status = AE_OK;
 	int result;
@@ -1180,6 +1182,8 @@
 		}
 	}
 
+	asus_hotk_found = 1;
+
       end:
 	if (result) {
 		kfree(hotk);
@@ -1226,7 +1230,19 @@
 	asus_proc_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&asus_hotk_driver);
-	if (result < 1) {
+	if (result < 0) {
+		remove_proc_entry(PROC_ASUS, acpi_root_dir);
+		return -ENODEV;
+	}
+
+	/*
+	 * This is a bit of a kludge.  We only want this module loaded
+	 * for ASUS systems, but there's currently no way to probe the
+	 * ACPI namespace for ASUS HIDs.  So we just return failure if
+	 * we didn't find one, which will cause the module to be
+	 * unloaded.
+	 */
+	if (!asus_hotk_found) {
 		acpi_bus_unregister_driver(&asus_hotk_driver);
 		remove_proc_entry(PROC_ASUS, acpi_root_dir);
 		return -ENODEV;
diff -urN oldtree/drivers/acpi/battery.c newtree/drivers/acpi/battery.c
--- oldtree/drivers/acpi/battery.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/battery.c	2006-04-01 05:35:30.702538750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/bus.c	2006-04-01 05:36:15.129315250 -0500
@@ -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,8 @@
 	/* 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 '%s' is not power manageable",
+					device->kobj.name));
 		return_VALUE(-ENODEV);
 	}
 	/*
@@ -213,13 +212,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 +261,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 +578,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/button.c	2006-04-01 05:35:30.702538750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/container.c	2006-04-01 05:35:30.702538750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/debug.c	2006-04-01 05:35:30.702538750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsfield.c	2006-04-01 05:35:30.706539000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsmethod.c	2006-04-01 05:35:30.706539000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsmthdat.c	2006-04-01 05:35:30.706539000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsobject.c	2006-04-01 05:35:30.706539000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsopcode.c	2006-04-01 05:35:30.706539000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dsutils.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dswexec.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dswload.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dswscope.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/dispatcher/dswstate.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/ec.c	2006-04-01 05:35:34.238759750 -0500
@@ -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);
@@ -991,7 +989,6 @@
 	int result = 0;
 	acpi_status status = AE_OK;
 	union acpi_ec *ec = NULL;
-	unsigned long uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
 
@@ -1014,10 +1011,9 @@
 	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
 			      &ec->common.global_lock);
 
-	/* If our UID matches the UID for the ECDT-enumerated EC,
-	   we now have the *real* EC info, so kill the makeshift one. */
-	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
-	if (ec_ecdt && ec_ecdt->common.uid == uid) {
+	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+	if (ec_ecdt) {
 		acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
@@ -1034,8 +1030,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;
 	}
@@ -1062,7 +1057,6 @@
 	int result = 0;
 	acpi_status status = AE_OK;
 	union acpi_ec *ec = NULL;
-	unsigned long uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
 
@@ -1088,10 +1082,9 @@
 	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
 			      &ec->common.global_lock);
 
-	/* If our UID matches the UID for the ECDT-enumerated EC,
-	   we now have the *real* EC info, so kill the makeshift one. */
-	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
-	if (ec_ecdt && ec_ecdt->common.uid == uid) {
+	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+	if (ec_ecdt) {
 		acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
@@ -1108,8 +1101,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 +1195,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/event.c	2006-04-01 05:35:30.710539250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evevent.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evgpe.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evgpeblk.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evmisc.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evregion.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evrgnini.c	2006-04-01 05:35:30.714539500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evxface.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evxfevnt.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/events/evxfregn.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exconfig.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exconvrt.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exdump.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exfield.c	2006-04-01 05:35:30.718539750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exfldio.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exmisc.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exmutex.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exnames.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exoparg1.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exoparg2.c	2006-04-01 05:35:30.722540000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exoparg3.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exoparg6.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exregion.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exresnte.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exresolv.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exresop.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exstore.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exstoren.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exstorob.c	2006-04-01 05:35:30.726540250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exsystem.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/executer/exutils.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/fan.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/hardware/hwgpe.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/hardware/hwregs.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/hardware/hwsleep.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/hardware/hwtimer.c	2006-04-01 05:35:30.730540500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/hotkey.c	2006-04-01 05:35:30.730540500 -0500
@@ -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;
@@ -723,6 +720,8 @@
 		goto do_fail;
 	count = tmp1 - tmp;
 	*action_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
+	if (!*action_handle)
+		goto do_fail;
 	strncpy(*action_handle, tmp, count);
 	*(*action_handle + count) = 0;
 
@@ -769,7 +768,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 +789,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 +802,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 +824,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 +858,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 +903,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 +950,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 +983,7 @@
 
 		}
 	} else {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
+		ACPI_WARNING((AE_INFO, "Not supported"));
 		return_VALUE(-EINVAL);
 	}
 	return_VALUE(count);
@@ -1011,9 +1009,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 +1016,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 +1028,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 +1039,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 +1049,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/motherboard.c newtree/drivers/acpi/motherboard.c
--- oldtree/drivers/acpi/motherboard.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/motherboard.c	2006-04-01 05:35:31.978618500 -0500
@@ -37,7 +37,7 @@
 #define ACPI_MB_HID2			"PNP0C02"
 /**
  * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve 
+ * Doesn't care about the failure of 'request_region', since other may reserve
  * the io ports as well
  */
 #define IS_RESERVED_ADDR(base, len) \
@@ -46,7 +46,7 @@
 /*
  * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
  * the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it. 
+ * still preventing hotplug PCI devices from using it.
  */
 static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
 {
@@ -123,49 +123,54 @@
 		},
 };
 
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+	unsigned int length, char *desc)
+{
+	if (!addr->address || !length)
+		return;
+
+	if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+		request_region(addr->address, length, desc);
+	else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		request_mem_region(addr->address, length, desc);
+}
+
 static void __init acpi_reserve_resources(void)
 {
-	if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
-		request_region(acpi_gbl_FADT->xpm1a_evt_blk.address,
-			       acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK");
-
-	if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
-		request_region(acpi_gbl_FADT->xpm1b_evt_blk.address,
-			       acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK");
-
-	if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
-		request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address,
-			       acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK");
-
-	if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
-		request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address,
-			       acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK");
-
-	if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4)
-		request_region(acpi_gbl_FADT->xpm_tmr_blk.address, 4, "PM_TMR");
-
-	if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len)
-		request_region(acpi_gbl_FADT->xpm2_cnt_blk.address,
-			       acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK");
+	acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
+			       acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
+			       acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
+			       acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
+
+	acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
+			       acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
+
+	if (acpi_gbl_FADT->pm_tm_len == 4)
+		acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
+
+	acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
+			       acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
 
 	/* Length of GPE blocks must be a non-negative multiple of 2 */
 
-	if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len &&
-	    !(acpi_gbl_FADT->gpe0_blk_len & 0x1))
-		request_region(acpi_gbl_FADT->xgpe0_blk.address,
-			       acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK");
-
-	if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len &&
-	    !(acpi_gbl_FADT->gpe1_blk_len & 0x1))
-		request_region(acpi_gbl_FADT->xgpe1_blk.address,
-			       acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK");
+	if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
+		acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
+			       acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
+
+	if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
+		acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
+			       acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
 }
 
 static int __init acpi_motherboard_init(void)
 {
 	acpi_bus_register_driver(&acpi_motherboard_driver1);
 	acpi_bus_register_driver(&acpi_motherboard_driver2);
-	/* 
+	/*
 	 * Guarantee motherboard IO reservation first
 	 * This module must run after scan.c
 	 */
diff -urN oldtree/drivers/acpi/namespace/nsaccess.c newtree/drivers/acpi/namespace/nsaccess.c
--- oldtree/drivers/acpi/namespace/nsaccess.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsaccess.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsalloc.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsdump.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nseval.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsinit.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsload.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsobject.c	2006-04-01 05:35:30.734540750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nssearch.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsutils.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nswalk.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsxfeval.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsxfname.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/namespace/nsxfobj.c	2006-04-01 05:35:30.738541000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/osl.c	2006-04-01 05:35:34.274762000 -0500
@@ -136,6 +136,7 @@
 #endif
 }
 
+
 extern int acpi_in_resume;
 void *acpi_os_allocate(acpi_size size)
 {
@@ -144,6 +145,7 @@
 	else
 		return kmalloc(size, GFP_KERNEL);
 }
+EXPORT_SYMBOL(acpi_os_allocate);
 
 void acpi_os_free(void *ptr)
 {
@@ -623,7 +625,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 +677,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 +851,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));
 	}
 
@@ -1175,7 +1176,12 @@
 
 void *acpi_os_acquire_object(acpi_cache_t * cache)
 {
-	void *object = kmem_cache_alloc(cache, GFP_KERNEL);
+	void *object;
+
+	if (acpi_in_resume)
+		object = kmem_cache_alloc(cache, GFP_ATOMIC);
+	else
+		object = kmem_cache_alloc(cache, GFP_KERNEL);
 	WARN_ON(!object);
 	return object;
 }
diff -urN oldtree/drivers/acpi/parser/psargs.c newtree/drivers/acpi/parser/psargs.c
--- oldtree/drivers/acpi/parser/psargs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psargs.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psloop.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psopcode.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psparse.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psscope.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/pstree.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psutils.c	2006-04-01 05:35:33.130690500 -0500
@@ -135,15 +135,20 @@
 	/* 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);
-		memset(op, 0, sizeof(struct acpi_parse_obj_common));
+
+		if (op)
+			memset(op, 0, sizeof(struct acpi_parse_obj_common));
 	} else {
 		/* Extended parseop */
 
 		op = acpi_os_acquire_object(acpi_gbl_ps_node_ext_cache);
-		memset(op, 0, sizeof(struct acpi_parse_obj_named));
+
+		if (op)
+			memset(op, 0, sizeof(struct acpi_parse_obj_named));
 	}
 
 	/* Initialize the Op */
diff -urN oldtree/drivers/acpi/parser/pswalk.c newtree/drivers/acpi/parser/pswalk.c
--- oldtree/drivers/acpi/parser/pswalk.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/pswalk.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/parser/psxface.c	2006-04-01 05:35:30.742541250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/pci_bind.c	2006-04-01 05:35:30.746541500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/pci_irq.c	2006-04-01 05:35:30.746541500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/pci_link.c	2006-04-01 05:35:30.918552250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/pci_root.c	2006-04-01 05:35:30.746541500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/power.c	2006-04-01 05:35:30.746541500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/processor_core.c	2006-04-01 05:35:33.178693500 -0500
@@ -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);
@@ -388,7 +382,7 @@
 
 /* Use the acpiid in MADT to map cpus in case of SMP */
 #ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (0xff)
+#define convert_acpiid_to_cpu(acpi_id) (-1)
 #else
 
 #ifdef CONFIG_IA64
@@ -401,7 +395,7 @@
 #define ARCH_BAD_APICID		(0xff)
 #endif
 
-static u8 convert_acpiid_to_cpu(u8 acpi_id)
+static int convert_acpiid_to_cpu(u8 acpi_id)
 {
 	u16 apic_id;
 	int i;
@@ -427,7 +421,7 @@
 	acpi_status status = 0;
 	union acpi_object object = { 0 };
 	struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
-	u8 cpu_index;
+	int cpu_index;
 	static int cpu0_initialized;
 
 	ACPI_FUNCTION_TRACE("acpi_processor_get_info");
@@ -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);
 	}
 
@@ -473,7 +466,7 @@
 	cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
 
 	/* Handle UP system running SMP kernel, with no LAPIC in MADT */
-	if (!cpu0_initialized && (cpu_index == 0xff) &&
+	if (!cpu0_initialized && (cpu_index == -1) &&
 	    (num_online_cpus() == 1)) {
 		cpu_index = 0;
 	}
@@ -487,12 +480,12 @@
 	 *  less than the max # of CPUs. They should be ignored _iff
 	 *  they are physically not present.
 	 */
-	if (cpu_index >= NR_CPUS) {
+	if (cpu_index == -1) {
 		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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/processor_idle.c	2006-04-01 05:35:30.750541750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/processor_perflib.c	2006-04-01 05:35:30.902551250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/processor_thermal.c	2006-04-01 05:35:30.750541750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/processor_throttling.c	2006-04-01 05:35:30.750541750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/resources/rscalc.c	2006-04-01 05:35:30.750541750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/resources/rslist.c	2006-04-01 05:35:30.750541750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/resources/rsmisc.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/resources/rsutils.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/resources/rsxface.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/scan.c	2006-04-01 05:35:32.038622250 -0500
@@ -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() */
@@ -235,12 +236,9 @@
 
 int acpi_match_ids(struct acpi_device *device, char *ids)
 {
-	int error = 0;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
 	if (device->flags.hardware_id)
 		if (strstr(ids, device->pnp.hardware_id))
-			goto Done;
+			return 0;
 
 	if (device->flags.compatible_ids) {
 		struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
@@ -249,15 +247,10 @@
 		/* compare multiple _CID entries against driver ids */
 		for (i = 0; i < cid_list->count; i++) {
 			if (strstr(ids, cid_list->id[i].value))
-				goto Done;
+				return 0;
 		}
 	}
-	error = -ENOENT;
-
-      Done:
-	if (buffer.pointer)
-		acpi_os_free(buffer.pointer);
-	return error;
+	return -ENOENT;
 }
 
 static acpi_status
@@ -321,15 +314,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 +464,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
@@ -549,10 +541,9 @@
 	return_VALUE(result);
 }
 
-static int acpi_driver_attach(struct acpi_driver *drv)
+static void acpi_driver_attach(struct acpi_driver *drv)
 {
 	struct list_head *node, *next;
-	int count = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_driver_attach");
 
@@ -569,7 +560,6 @@
 			if (!acpi_bus_driver_init(dev, drv)) {
 				acpi_start_single_object(dev);
 				atomic_inc(&drv->references);
-				count++;
 				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 						  "Found driver [%s] for device [%s]\n",
 						  drv->name, dev->pnp.bus_id));
@@ -578,7 +568,6 @@
 		spin_lock(&acpi_device_lock);
 	}
 	spin_unlock(&acpi_device_lock);
-	return_VALUE(count);
 }
 
 static int acpi_driver_detach(struct acpi_driver *drv)
@@ -611,14 +600,11 @@
  * @driver: driver being registered
  *
  * Registers a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and binds.  Returns the
- * number of devices that were claimed by the driver, or a negative
- * error status for failure.
+ * devices that match the driver's criteria and binds.  Returns zero for
+ * success or a negative error status for failure.
  */
 int acpi_bus_register_driver(struct acpi_driver *driver)
 {
-	int count;
-
 	ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
 
 	if (acpi_disabled)
@@ -630,9 +616,9 @@
 	spin_lock(&acpi_device_lock);
 	list_add_tail(&driver->node, &acpi_bus_drivers);
 	spin_unlock(&acpi_device_lock);
-	count = acpi_driver_attach(driver);
+	acpi_driver_attach(driver);
 
-	return_VALUE(count);
+	return_VALUE(0);
 }
 
 EXPORT_SYMBOL(acpi_bus_register_driver);
@@ -646,21 +632,19 @@
  */
 int acpi_bus_unregister_driver(struct acpi_driver *driver)
 {
-	int error = 0;
-
 	ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");
 
-	if (driver) {
-		acpi_driver_detach(driver);
+	if (!driver)
+		return_VALUE(-EINVAL);
 
-		if (!atomic_read(&driver->references)) {
-			spin_lock(&acpi_device_lock);
-			list_del_init(&driver->node);
-			spin_unlock(&acpi_device_lock);
-		}
-	} else
-		error = -EINVAL;
-	return_VALUE(error);
+	acpi_driver_detach(driver);
+
+	if (!atomic_read(&driver->references)) {
+		spin_lock(&acpi_device_lock);
+		list_del_init(&driver->node);
+		spin_unlock(&acpi_device_lock);
+	}
+	return_VALUE(0);
 }
 
 EXPORT_SYMBOL(acpi_bus_unregister_driver);
@@ -1001,7 +985,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/sleep/Makefile newtree/drivers/acpi/sleep/Makefile
--- oldtree/drivers/acpi/sleep/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/sleep/Makefile	2006-04-01 05:35:33.146691500 -0500
@@ -1,5 +1,4 @@
-obj-y					:= poweroff.o wakeup.o
+obj-y					:= poweroff.o wakeup.o proc.o
 obj-$(CONFIG_ACPI_SLEEP)		+= main.o
-obj-$(CONFIG_ACPI_SLEEP_PROC_FS)	+= proc.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff -urN oldtree/drivers/acpi/sleep/poweroff.c newtree/drivers/acpi/sleep/poweroff.c
--- oldtree/drivers/acpi/sleep/poweroff.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/sleep/poweroff.c	2006-04-01 05:35:33.146691500 -0500
@@ -45,6 +45,7 @@
 	/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
 	printk("%s called\n", __FUNCTION__);
 	local_irq_disable();
+	acpi_enable_wakeup_device(ACPI_STATE_S5);
 	/* Some SMP machines only can poweroff in boot CPU */
 	acpi_enter_sleep_state(ACPI_STATE_S5);
 }
diff -urN oldtree/drivers/acpi/sleep/proc.c newtree/drivers/acpi/sleep/proc.c
--- oldtree/drivers/acpi/sleep/proc.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/sleep/proc.c	2006-04-01 05:35:33.146691500 -0500
@@ -70,6 +70,7 @@
 }
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#ifdef	CONFIG_ACPI_SLEEP
 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
 {
 	u32 sec, min, hr;
@@ -339,6 +340,7 @@
       end:
 	return_VALUE(result ? result : count);
 }
+#endif				/* CONFIG_ACPI_SLEEP */
 
 extern struct list_head acpi_wakeup_device_list;
 extern spinlock_t acpi_device_lock;
@@ -357,6 +359,10 @@
 
 		if (!dev->wakeup.flags.valid)
 			continue;
+#ifndef CONFIG_ACPI_SLEEP
+		if (dev->wakeup.sleep_state != ACPI_STATE_S5)
+			continue;
+#endif
 		spin_unlock(&acpi_device_lock);
 		seq_printf(seq, "%4s	%4d		%s%8s\n",
 			   dev->pnp.bus_id,
@@ -394,6 +400,10 @@
 		    container_of(node, struct acpi_device, wakeup_list);
 		if (!dev->wakeup.flags.valid)
 			continue;
+#ifndef CONFIG_ACPI_SLEEP
+		if (dev->wakeup.sleep_state != ACPI_STATE_S5)
+			continue;
+#endif
 
 		if (!strncmp(dev->pnp.bus_id, str, 4)) {
 			dev->wakeup.state.enabled =
@@ -452,6 +462,7 @@
 };
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#ifdef	CONFIG_ACPI_SLEEP
 static struct file_operations acpi_system_alarm_fops = {
 	.open = acpi_system_alarm_open_fs,
 	.read = seq_read,
@@ -467,6 +478,7 @@
 
 	return ACPI_INTERRUPT_HANDLED;
 }
+#endif				/* CONFIG_ACPI_SLEEP */
 
 static int acpi_sleep_proc_init(void)
 {
@@ -484,12 +496,14 @@
 		entry->proc_fops = &acpi_system_sleep_fops;
 #endif
 
+#ifdef	CONFIG_ACPI_SLEEP
 	/* 'alarm' [R/W] */
 	entry =
 	    create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
 			      acpi_root_dir);
 	if (entry)
 		entry->proc_fops = &acpi_system_alarm_fops;
+#endif
 
 	/* 'wakeup device' [R/W] */
 	entry =
@@ -498,7 +512,9 @@
 	if (entry)
 		entry->proc_fops = &acpi_system_wakeup_device_fops;
 
+#ifdef	CONFIG_ACPI_SLEEP
 	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+#endif
 	return 0;
 }
 
diff -urN oldtree/drivers/acpi/sleep/wakeup.c newtree/drivers/acpi/sleep/wakeup.c
--- oldtree/drivers/acpi/sleep/wakeup.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/sleep/wakeup.c	2006-04-01 05:35:33.146691500 -0500
@@ -48,6 +48,7 @@
 	}
 	spin_unlock(&acpi_device_lock);
 }
+#endif
 
 /**
  * acpi_enable_wakeup_device - enable wakeup devices
@@ -100,6 +101,7 @@
 	spin_unlock(&acpi_device_lock);
 }
 
+#ifdef CONFIG_ACPI_SLEEP
 /**
  * acpi_disable_wakeup_device - disable devices' wakeup capability
  *	@sleep_state:	ACPI state
@@ -155,7 +157,7 @@
 
 	if (acpi_disabled)
 		return 0;
-	printk("ACPI wakeup devices: \n");
+	printk(KERN_INFO PREFIX "wakeup devices: ");
 
 	spin_lock(&acpi_device_lock);
 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
diff -urN oldtree/drivers/acpi/sony_acpi.c newtree/drivers/acpi/sony_acpi.c
--- oldtree/drivers/acpi/sony_acpi.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/acpi/sony_acpi.c	2006-04-01 05:35:35.746854000 -0500
@@ -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 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 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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/system.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbconvrt.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbget.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbgetall.c	2006-04-01 05:35:30.754542000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbinstal.c	2006-04-01 05:35:30.758542250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbrsdt.c	2006-04-01 05:35:30.758542250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbutils.c	2006-04-01 05:35:30.758542250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbxface.c	2006-04-01 05:35:30.758542250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/tables/tbxfroot.c	2006-04-01 05:35:30.758542250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/thermal.c	2006-04-01 05:35:30.758542250 -0500
@@ -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;
 	}
 
@@ -942,17 +940,17 @@
 	memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
 
 	active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
-	if (!active)
+	if (!active) {
+		kfree(limit_string);
 		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 +963,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 +1122,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 +1133,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 +1145,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 +1157,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 +1169,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 +1339,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 +1380,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utalloc.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utcache.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utcopy.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utdebug.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utdelete.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/uteval.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utglobal.c	2006-04-01 05:35:30.762542500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utmisc.c	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utobject.c	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utresrc.c	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utilities/utstate.c	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/utils.c	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/acpi/video.c	2006-04-01 05:35:30.766542750 -0500
@@ -323,8 +323,8 @@
 	if (!ACPI_SUCCESS(status))
 		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"));
+	if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+		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/bluetooth/bluecard_cs.c newtree/drivers/bluetooth/bluecard_cs.c
--- oldtree/drivers/bluetooth/bluecard_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/bluetooth/bluecard_cs.c	2006-04-01 05:35:44.239384750 -0500
@@ -65,7 +65,7 @@
 
 
 typedef struct bluecard_info_t {
-	dev_link_t link;
+	struct pcmcia_device *p_dev;
 	dev_node_t node;
 
 	struct hci_dev *hdev;
@@ -85,8 +85,8 @@
 } bluecard_info_t;
 
 
-static void bluecard_config(dev_link_t *link);
-static void bluecard_release(dev_link_t *link);
+static int bluecard_config(struct pcmcia_device *link);
+static void bluecard_release(struct pcmcia_device *link);
 
 static void bluecard_detach(struct pcmcia_device *p_dev);
 
@@ -162,7 +162,7 @@
 static void bluecard_activity_led_timeout(u_long arg)
 {
 	bluecard_info_t *info = (bluecard_info_t *)arg;
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 
 	if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
 		return;
@@ -179,7 +179,7 @@
 
 static void bluecard_enable_activity_led(bluecard_info_t *info)
 {
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 
 	if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
 		return;
@@ -235,7 +235,7 @@
 	}
 
 	do {
-		register unsigned int iobase = info->link.io.BasePort1;
+		register unsigned int iobase = info->p_dev->io.BasePort1;
 		register unsigned int offset;
 		register unsigned char command;
 		register unsigned long ready_bit;
@@ -244,7 +244,7 @@
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
-		if (!(info->link.state & DEV_PRESENT))
+		if (!pcmcia_dev_present(info->p_dev))
 			return;
 
 		if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
@@ -382,7 +382,7 @@
 		return;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
 		bluecard_enable_activity_led(info);
@@ -512,7 +512,7 @@
 	if (!test_bit(CARD_READY, &(info->hw_state)))
 		return IRQ_HANDLED;
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	spin_lock(&(info->lock));
 
@@ -626,7 +626,7 @@
 static int bluecard_hci_open(struct hci_dev *hdev)
 {
 	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 
 	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
 		bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
@@ -646,7 +646,7 @@
 static int bluecard_hci_close(struct hci_dev *hdev)
 {
 	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 
 	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
 		return 0;
@@ -713,7 +713,7 @@
 
 static int bluecard_open(bluecard_info_t *info)
 {
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev;
 	unsigned char id;
 
@@ -831,7 +831,7 @@
 
 static int bluecard_close(bluecard_info_t *info)
 {
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev = info->hdev;
 
 	if (!hdev)
@@ -856,17 +856,16 @@
 	return 0;
 }
 
-static int bluecard_attach(struct pcmcia_device *p_dev)
+static int bluecard_probe(struct pcmcia_device *link)
 {
 	bluecard_info_t *info;
-	dev_link_t *link;
 
 	/* Create new info device */
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -878,32 +877,22 @@
 	link->irq.Instance = info;
 
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	bluecard_config(link);
-
-	return 0;
+	return bluecard_config(link);
 }
 
 
-static void bluecard_detach(struct pcmcia_device *p_dev)
+static void bluecard_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	bluecard_info_t *info = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		bluecard_release(link);
-
+	bluecard_release(link);
 	kfree(info);
 }
 
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int i;
 
@@ -918,14 +907,12 @@
 	return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static void bluecard_config(dev_link_t *link)
+static int bluecard_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	bluecard_info_t *info = link->priv;
 	tuple_t tuple;
 	u_short buf[256];
 	cisparse_t parse;
-	config_info_t config;
 	int i, n, last_ret, last_fn;
 
 	tuple.TupleData = (cisdata_t *)buf;
@@ -935,7 +922,7 @@
 
 	/* Get configuration register information */
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	last_ret = first_tuple(handle, &tuple, &parse);
+	last_ret = first_tuple(link, &tuple, &parse);
 	if (last_ret != CS_SUCCESS) {
 		last_fn = ParseTuple;
 		goto cs_failed;
@@ -943,36 +930,31 @@
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	i = pcmcia_get_configuration_info(handle, &config);
-	link->conf.Vcc = config.Vcc;
-
 	link->conf.ConfigIndex = 0x20;
 	link->io.NumPorts1 = 64;
 	link->io.IOAddrLines = 6;
 
 	for (n = 0; n < 0x400; n += 0x40) {
 		link->io.BasePort1 = n ^ 0x300;
-		i = pcmcia_request_io(link->handle, &link->io);
+		i = pcmcia_request_io(link, &link->io);
 		if (i == CS_SUCCESS)
 			break;
 	}
 
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
 
@@ -980,57 +962,28 @@
 		goto failed;
 
 	strcpy(info->node.dev_name, info->hdev->name);
-	link->dev = &info->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &info->node;
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
 failed:
 	bluecard_release(link);
+	return -ENODEV;
 }
 
 
-static void bluecard_release(dev_link_t *link)
+static void bluecard_release(struct pcmcia_device *link)
 {
 	bluecard_info_t *info = link->priv;
 
-	if (link->state & DEV_PRESENT)
-		bluecard_close(info);
+	bluecard_close(info);
 
 	del_timer(&(info->timer));
 
-	link->dev = NULL;
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
-}
-
-static int bluecard_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int bluecard_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
+	pcmcia_disable_device(link);
 }
 
 static struct pcmcia_device_id bluecard_ids[] = {
@@ -1046,11 +999,9 @@
 	.drv		= {
 		.name	= "bluecard_cs",
 	},
-	.probe		= bluecard_attach,
+	.probe		= bluecard_probe,
 	.remove		= bluecard_detach,
 	.id_table	= bluecard_ids,
-	.suspend	= bluecard_suspend,
-	.resume		= bluecard_resume,
 };
 
 static int __init init_bluecard_cs(void)
diff -urN oldtree/drivers/bluetooth/bt3c_cs.c newtree/drivers/bluetooth/bt3c_cs.c
--- oldtree/drivers/bluetooth/bt3c_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/bluetooth/bt3c_cs.c	2006-04-01 05:35:44.239384750 -0500
@@ -72,7 +72,7 @@
 
 
 typedef struct bt3c_info_t {
-	dev_link_t link;
+	struct pcmcia_device *p_dev;
 	dev_node_t node;
 
 	struct hci_dev *hdev;
@@ -88,8 +88,8 @@
 } bt3c_info_t;
 
 
-static void bt3c_config(dev_link_t *link);
-static void bt3c_release(dev_link_t *link);
+static int bt3c_config(struct pcmcia_device *link);
+static void bt3c_release(struct pcmcia_device *link);
 
 static void bt3c_detach(struct pcmcia_device *p_dev);
 
@@ -191,11 +191,11 @@
 		return;
 
 	do {
-		register unsigned int iobase = info->link.io.BasePort1;
+		register unsigned int iobase = info->p_dev->io.BasePort1;
 		register struct sk_buff *skb;
 		register int len;
 
-		if (!(info->link.state & DEV_PRESENT))
+		if (!pcmcia_dev_present(info->p_dev))
 			break;
 
 
@@ -229,7 +229,7 @@
 		return;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	avail = bt3c_read(iobase, 0x7006);
 	//printk("bt3c_cs: receiving %d bytes\n", avail);
@@ -350,7 +350,7 @@
 		return IRQ_NONE;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	spin_lock(&(info->lock));
 
@@ -481,7 +481,7 @@
 	unsigned int iobase, size, addr, fcs, tmp;
 	int i, err = 0;
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	/* Reset */
 	bt3c_io_write(iobase, 0x8040, 0x0404);
@@ -562,7 +562,6 @@
 {
 	const struct firmware *firmware;
 	struct hci_dev *hdev;
-	client_handle_t handle;
 	int err;
 
 	spin_lock_init(&(info->lock));
@@ -594,10 +593,8 @@
 
 	hdev->owner = THIS_MODULE;
 
-	handle = info->link.handle;
-
 	/* Load firmware */
-	err = request_firmware(&firmware, "BT3CPCC.bin", &handle_to_dev(handle));
+	err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
 	if (err < 0) {
 		BT_ERR("Firmware request failed");
 		goto error;
@@ -648,17 +645,16 @@
 	return 0;
 }
 
-static int bt3c_attach(struct pcmcia_device *p_dev)
+static int bt3c_probe(struct pcmcia_device *link)
 {
 	bt3c_info_t *info;
-	dev_link_t *link;
 
 	/* Create new info device */
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -670,31 +666,21 @@
 	link->irq.Instance = info;
 
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	bt3c_config(link);
-
-	return 0;
+	return bt3c_config(link);
 }
 
 
-static void bt3c_detach(struct pcmcia_device *p_dev)
+static void bt3c_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	bt3c_info_t *info = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		bt3c_release(link);
-
+	bt3c_release(link);
 	kfree(info);
 }
 
-static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int i;
 
@@ -705,30 +691,28 @@
 	return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static void bt3c_config(dev_link_t *link)
+static int bt3c_config(struct pcmcia_device *link)
 {
 	static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-	client_handle_t handle = link->handle;
 	bt3c_info_t *info = link->priv;
 	tuple_t tuple;
 	u_short buf[256];
 	cisparse_t parse;
 	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-	config_info_t config;
 	int i, j, try, last_ret, last_fn;
 
 	tuple.TupleData = (cisdata_t *)buf;
@@ -738,7 +722,7 @@
 
 	/* Get configuration register information */
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	last_ret = first_tuple(handle, &tuple, &parse);
+	last_ret = first_tuple(link, &tuple, &parse);
 	if (last_ret != CS_SUCCESS) {
 		last_fn = ParseTuple;
 		goto cs_failed;
@@ -746,11 +730,6 @@
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	i = pcmcia_get_configuration_info(handle, &config);
-	link->conf.Vcc = config.Vcc;
-
 	/* First pass: look for a config entry that looks normal. */
 	tuple.TupleData = (cisdata_t *)buf;
 	tuple.TupleOffset = 0;
@@ -759,59 +738,59 @@
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	/* Two tries: without IO aliases, then with aliases */
 	for (try = 0; try < 2; try++) {
-		i = first_tuple(handle, &tuple, &parse);
+		i = first_tuple(link, &tuple, &parse);
 		while (i != CS_NO_MORE_ITEMS) {
 			if (i != CS_SUCCESS)
 				goto next_entry;
 			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+				link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
 				link->conf.ConfigIndex = cf->index;
 				link->io.BasePort1 = cf->io.win[0].base;
 				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				if (i == CS_SUCCESS)
 					goto found_port;
 			}
 next_entry:
-			i = next_tuple(handle, &tuple, &parse);
+			i = next_tuple(link, &tuple, &parse);
 		}
 	}
 
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(link, &tuple, &parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
 			link->conf.ConfigIndex = cf->index;
 			for (j = 0; j < 5; j++) {
 				link->io.BasePort1 = base[j];
 				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				if (i == CS_SUCCESS)
 					goto found_port;
 			}
 		}
-		i = next_tuple(handle, &tuple, &parse);
+		i = next_tuple(link, &tuple, &parse);
 	}
 
 found_port:
 	if (i != CS_SUCCESS) {
 		BT_ERR("No usable port range found");
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
 
@@ -819,55 +798,26 @@
 		goto failed;
 
 	strcpy(info->node.dev_name, info->hdev->name);
-	link->dev = &info->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &info->node;
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
 failed:
 	bt3c_release(link);
+	return -ENODEV;
 }
 
 
-static void bt3c_release(dev_link_t *link)
+static void bt3c_release(struct pcmcia_device *link)
 {
 	bt3c_info_t *info = link->priv;
 
-	if (link->state & DEV_PRESENT)
-		bt3c_close(info);
-
-	link->dev = NULL;
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
-}
-
-static int bt3c_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
+	bt3c_close(info);
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int bt3c_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
+	pcmcia_disable_device(link);
 }
 
 
@@ -882,11 +832,9 @@
 	.drv		= {
 		.name	= "bt3c_cs",
 	},
-	.probe		= bt3c_attach,
+	.probe		= bt3c_probe,
 	.remove		= bt3c_detach,
 	.id_table	= bt3c_ids,
-	.suspend	= bt3c_suspend,
-	.resume		= bt3c_resume,
 };
 
 static int __init init_bt3c_cs(void)
diff -urN oldtree/drivers/bluetooth/btuart_cs.c newtree/drivers/bluetooth/btuart_cs.c
--- oldtree/drivers/bluetooth/btuart_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/bluetooth/btuart_cs.c	2006-04-01 05:35:44.239384750 -0500
@@ -68,7 +68,7 @@
 
 
 typedef struct btuart_info_t {
-	dev_link_t link;
+	struct pcmcia_device *p_dev;
 	dev_node_t node;
 
 	struct hci_dev *hdev;
@@ -84,8 +84,8 @@
 } btuart_info_t;
 
 
-static void btuart_config(dev_link_t *link);
-static void btuart_release(dev_link_t *link);
+static int btuart_config(struct pcmcia_device *link);
+static void btuart_release(struct pcmcia_device *link);
 
 static void btuart_detach(struct pcmcia_device *p_dev);
 
@@ -146,13 +146,13 @@
 	}
 
 	do {
-		register unsigned int iobase = info->link.io.BasePort1;
+		register unsigned int iobase = info->p_dev->io.BasePort1;
 		register struct sk_buff *skb;
 		register int len;
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
-		if (!(info->link.state & DEV_PRESENT))
+		if (!pcmcia_dev_present(info->p_dev))
 			return;
 
 		if (!(skb = skb_dequeue(&(info->txq))))
@@ -187,7 +187,7 @@
 		return;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	do {
 		info->hdev->stat.byte_rx++;
@@ -301,7 +301,7 @@
 		return IRQ_NONE;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	spin_lock(&(info->lock));
 
@@ -357,7 +357,7 @@
 		return;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	spin_lock_irqsave(&(info->lock), flags);
 
@@ -481,7 +481,7 @@
 static int btuart_open(btuart_info_t *info)
 {
 	unsigned long flags;
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev;
 
 	spin_lock_init(&(info->lock));
@@ -550,7 +550,7 @@
 static int btuart_close(btuart_info_t *info)
 {
 	unsigned long flags;
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev = info->hdev;
 
 	if (!hdev)
@@ -576,17 +576,16 @@
 	return 0;
 }
 
-static int btuart_attach(struct pcmcia_device *p_dev)
+static int btuart_probe(struct pcmcia_device *link)
 {
 	btuart_info_t *info;
-	dev_link_t *link;
 
 	/* Create new info device */
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -598,31 +597,21 @@
 	link->irq.Instance = info;
 
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	btuart_config(link);
-
-	return 0;
+	return btuart_config(link);
 }
 
 
-static void btuart_detach(struct pcmcia_device *p_dev)
+static void btuart_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	btuart_info_t *info = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		btuart_release(link);
-
+	btuart_release(link);
 	kfree(info);
 }
 
-static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int i;
 
@@ -633,30 +622,28 @@
 	return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static void btuart_config(dev_link_t *link)
+static int btuart_config(struct pcmcia_device *link)
 {
 	static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-	client_handle_t handle = link->handle;
 	btuart_info_t *info = link->priv;
 	tuple_t tuple;
 	u_short buf[256];
 	cisparse_t parse;
 	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-	config_info_t config;
 	int i, j, try, last_ret, last_fn;
 
 	tuple.TupleData = (cisdata_t *)buf;
@@ -666,7 +653,7 @@
 
 	/* Get configuration register information */
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	last_ret = first_tuple(handle, &tuple, &parse);
+	last_ret = first_tuple(link, &tuple, &parse);
 	if (last_ret != CS_SUCCESS) {
 		last_fn = ParseTuple;
 		goto cs_failed;
@@ -674,11 +661,6 @@
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	i = pcmcia_get_configuration_info(handle, &config);
-	link->conf.Vcc = config.Vcc;
-
 	/* First pass: look for a config entry that looks normal. */
 	tuple.TupleData = (cisdata_t *) buf;
 	tuple.TupleOffset = 0;
@@ -687,29 +669,29 @@
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	/* Two tries: without IO aliases, then with aliases */
 	for (try = 0; try < 2; try++) {
-		i = first_tuple(handle, &tuple, &parse);
+		i = first_tuple(link, &tuple, &parse);
 		while (i != CS_NO_MORE_ITEMS) {
 			if (i != CS_SUCCESS)
 				goto next_entry;
 			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+				link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
 				link->conf.ConfigIndex = cf->index;
 				link->io.BasePort1 = cf->io.win[0].base;
 				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				if (i == CS_SUCCESS)
 					goto found_port;
 			}
 next_entry:
-			i = next_tuple(handle, &tuple, &parse);
+			i = next_tuple(link, &tuple, &parse);
 		}
 	}
 
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(link, &tuple, &parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
 		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
@@ -717,30 +699,30 @@
 			for (j = 0; j < 5; j++) {
 				link->io.BasePort1 = base[j];
 				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				if (i == CS_SUCCESS)
 					goto found_port;
 			}
 		}
-		i = next_tuple(handle, &tuple, &parse);
+		i = next_tuple(link, &tuple, &parse);
 	}
 
 found_port:
 	if (i != CS_SUCCESS) {
 		BT_ERR("No usable port range found");
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
 
@@ -748,58 +730,28 @@
 		goto failed;
 
 	strcpy(info->node.dev_name, info->hdev->name);
-	link->dev = &info->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &info->node;
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
 failed:
 	btuart_release(link);
+	return -ENODEV;
 }
 
 
-static void btuart_release(dev_link_t *link)
+static void btuart_release(struct pcmcia_device *link)
 {
 	btuart_info_t *info = link->priv;
 
-	if (link->state & DEV_PRESENT)
-		btuart_close(info);
-
-	link->dev = NULL;
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
-}
-
-static int btuart_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
+	btuart_close(info);
 
-	return 0;
+	pcmcia_disable_device(link);
 }
 
-static int btuart_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
-}
-
-
 static struct pcmcia_device_id btuart_ids[] = {
 	/* don't use this driver. Use serial_cs + hci_uart instead */
 	PCMCIA_DEVICE_NULL
@@ -811,11 +763,9 @@
 	.drv		= {
 		.name	= "btuart_cs",
 	},
-	.probe		= btuart_attach,
+	.probe		= btuart_probe,
 	.remove		= btuart_detach,
 	.id_table	= btuart_ids,
-	.suspend	= btuart_suspend,
-	.resume		= btuart_resume,
 };
 
 static int __init init_btuart_cs(void)
diff -urN oldtree/drivers/bluetooth/dtl1_cs.c newtree/drivers/bluetooth/dtl1_cs.c
--- oldtree/drivers/bluetooth/dtl1_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/bluetooth/dtl1_cs.c	2006-04-01 05:35:44.239384750 -0500
@@ -68,7 +68,7 @@
 
 
 typedef struct dtl1_info_t {
-	dev_link_t link;
+	struct pcmcia_device *p_dev;
 	dev_node_t node;
 
 	struct hci_dev *hdev;
@@ -87,8 +87,8 @@
 } dtl1_info_t;
 
 
-static void dtl1_config(dev_link_t *link);
-static void dtl1_release(dev_link_t *link);
+static int dtl1_config(struct pcmcia_device *link);
+static void dtl1_release(struct pcmcia_device *link);
 
 static void dtl1_detach(struct pcmcia_device *p_dev);
 
@@ -153,13 +153,13 @@
 	}
 
 	do {
-		register unsigned int iobase = info->link.io.BasePort1;
+		register unsigned int iobase = info->p_dev->io.BasePort1;
 		register struct sk_buff *skb;
 		register int len;
 
 		clear_bit(XMIT_WAKEUP, &(info->tx_state));
 
-		if (!(info->link.state & DEV_PRESENT))
+		if (!pcmcia_dev_present(info->p_dev))
 			return;
 
 		if (!(skb = skb_dequeue(&(info->txq))))
@@ -218,7 +218,7 @@
 		return;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	do {
 		info->hdev->stat.byte_rx++;
@@ -305,7 +305,7 @@
 		return IRQ_NONE;
 	}
 
-	iobase = info->link.io.BasePort1;
+	iobase = info->p_dev->io.BasePort1;
 
 	spin_lock(&(info->lock));
 
@@ -458,7 +458,7 @@
 static int dtl1_open(dtl1_info_t *info)
 {
 	unsigned long flags;
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev;
 
 	spin_lock_init(&(info->lock));
@@ -504,7 +504,7 @@
 	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
 	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
 
-	info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
+	info->ri_latch = inb(info->p_dev->io.BasePort1 + UART_MSR) & UART_MSR_RI;
 
 	/* Turn on interrupts */
 	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
@@ -529,7 +529,7 @@
 static int dtl1_close(dtl1_info_t *info)
 {
 	unsigned long flags;
-	unsigned int iobase = info->link.io.BasePort1;
+	unsigned int iobase = info->p_dev->io.BasePort1;
 	struct hci_dev *hdev = info->hdev;
 
 	if (!hdev)
@@ -555,17 +555,16 @@
 	return 0;
 }
 
-static int dtl1_attach(struct pcmcia_device *p_dev)
+static int dtl1_probe(struct pcmcia_device *link)
 {
 	dtl1_info_t *info;
-	dev_link_t *link;
 
 	/* Create new info device */
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -577,31 +576,22 @@
 	link->irq.Instance = info;
 
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	dtl1_config(link);
-
-	return 0;
+	return dtl1_config(link);
 }
 
 
-static void dtl1_detach(struct pcmcia_device *p_dev)
+static void dtl1_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	dtl1_info_t *info = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		dtl1_release(link);
+	dtl1_release(link);
 
 	kfree(info);
 }
 
-static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int i;
 
@@ -612,29 +602,27 @@
 	return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
 		return CS_NO_MORE_ITEMS;
 	return get_tuple(handle, tuple, parse);
 }
 
-static void dtl1_config(dev_link_t *link)
+static int dtl1_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	dtl1_info_t *info = link->priv;
 	tuple_t tuple;
 	u_short buf[256];
 	cisparse_t parse;
 	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-	config_info_t config;
 	int i, last_ret, last_fn;
 
 	tuple.TupleData = (cisdata_t *)buf;
@@ -644,7 +632,7 @@
 
 	/* Get configuration register information */
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	last_ret = first_tuple(handle, &tuple, &parse);
+	last_ret = first_tuple(link, &tuple, &parse);
 	if (last_ret != CS_SUCCESS) {
 		last_fn = ParseTuple;
 		goto cs_failed;
@@ -652,11 +640,6 @@
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	i = pcmcia_get_configuration_info(handle, &config);
-	link->conf.Vcc = config.Vcc;
-
 	tuple.TupleData = (cisdata_t *)buf;
 	tuple.TupleOffset = 0;
 	tuple.TupleDataMax = 255;
@@ -665,34 +648,34 @@
 
 	/* Look for a generic full-sized window */
 	link->io.NumPorts1 = 8;
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(link, &tuple, &parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
 			link->conf.ConfigIndex = cf->index;
 			link->io.BasePort1 = cf->io.win[0].base;
 			link->io.NumPorts1 = cf->io.win[0].len;	/*yo */
 			link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-			i = pcmcia_request_io(link->handle, &link->io);
+			i = pcmcia_request_io(link, &link->io);
 			if (i == CS_SUCCESS)
 				break;
 		}
-		i = next_tuple(handle, &tuple, &parse);
+		i = next_tuple(link, &tuple, &parse);
 	}
 
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		goto failed;
 	}
 
@@ -700,55 +683,26 @@
 		goto failed;
 
 	strcpy(info->node.dev_name, info->hdev->name);
-	link->dev = &info->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &info->node;
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
 failed:
 	dtl1_release(link);
+	return -ENODEV;
 }
 
 
-static void dtl1_release(dev_link_t *link)
+static void dtl1_release(struct pcmcia_device *link)
 {
 	dtl1_info_t *info = link->priv;
 
-	if (link->state & DEV_PRESENT)
-		dtl1_close(info);
-
-	link->dev = NULL;
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
-}
-
-static int dtl1_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int dtl1_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
+	dtl1_close(info);
 
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
+	pcmcia_disable_device(link);
 }
 
 
@@ -765,11 +719,9 @@
 	.drv		= {
 		.name	= "dtl1_cs",
 	},
-	.probe		= dtl1_attach,
+	.probe		= dtl1_probe,
 	.remove		= dtl1_detach,
 	.id_table	= dtl1_ids,
-	.suspend	= dtl1_suspend,
-	.resume		= dtl1_resume,
 };
 
 static int __init init_dtl1_cs(void)
diff -urN oldtree/drivers/char/Kconfig newtree/drivers/char/Kconfig
--- oldtree/drivers/char/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/Kconfig	2006-04-01 05:36:15.373330500 -0500
@@ -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
diff -urN oldtree/drivers/char/agp/amd64-agp.c newtree/drivers/char/agp/amd64-agp.c
--- oldtree/drivers/char/agp/amd64-agp.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/agp/amd64-agp.c	2006-04-01 05:35:35.766855250 -0500
@@ -617,6 +617,9 @@
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
+	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA)
+		nforce3_agp_init(pdev);
+
 	return amd_8151_configure();
 }
 
diff -urN oldtree/drivers/char/drm/drmP.h newtree/drivers/char/drm/drmP.h
--- oldtree/drivers/char/drm/drmP.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/drmP.h	2006-04-01 05:35:38.002995000 -0500
@@ -357,6 +357,12 @@
 	spinlock_t lock;
 } drm_freelist_t;
 
+typedef struct drm_dma_handle {
+	dma_addr_t busaddr;
+	void *vaddr;
+	size_t size;
+} drm_dma_handle_t;
+
 /**
  * Buffer entry.  There is one of this for each buffer size order.
  */
@@ -366,7 +372,7 @@
 	drm_buf_t *buflist;		/**< buffer list */
 	int seg_count;
 	int page_order;
-	unsigned long *seglist;
+	drm_dma_handle_t **seglist;
 
 	drm_freelist_t freelist;
 } drm_buf_entry_t;
@@ -483,12 +489,6 @@
 	drm_hw_lock_t *lock;
 } drm_sigdata_t;
 
-typedef struct drm_dma_handle {
-	dma_addr_t busaddr;
-	void *vaddr;
-	size_t size;
-} drm_dma_handle_t;
-
 /**
  * Mappings list
  */
diff -urN oldtree/drivers/char/drm/drm_bufs.c newtree/drivers/char/drm/drm_bufs.c
--- oldtree/drivers/char/drm/drm_bufs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/drm_bufs.c	2006-04-01 05:35:38.002995000 -0500
@@ -474,8 +474,7 @@
 	if (entry->seg_count) {
 		for (i = 0; i < entry->seg_count; i++) {
 			if (entry->seglist[i]) {
-				drm_free_pages(entry->seglist[i],
-					       entry->page_order, DRM_MEM_DMA);
+				drm_pci_free(dev, entry->seglist[i]);
 			}
 		}
 		drm_free(entry->seglist,
@@ -678,7 +677,7 @@
 	int total;
 	int page_order;
 	drm_buf_entry_t *entry;
-	unsigned long page;
+	drm_dma_handle_t *dmah;
 	drm_buf_t *buf;
 	int alignment;
 	unsigned long offset;
@@ -781,8 +780,10 @@
 	page_count = 0;
 
 	while (entry->buf_count < count) {
-		page = drm_alloc_pages(page_order, DRM_MEM_DMA);
-		if (!page) {
+		
+		dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful);
+		
+		if (!dmah) {
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
 			entry->seg_count = count;
@@ -794,13 +795,13 @@
 			atomic_dec(&dev->buf_alloc);
 			return -ENOMEM;
 		}
-		entry->seglist[entry->seg_count++] = page;
+		entry->seglist[entry->seg_count++] = dmah;
 		for (i = 0; i < (1 << page_order); i++) {
 			DRM_DEBUG("page %d @ 0x%08lx\n",
 				  dma->page_count + page_count,
-				  page + PAGE_SIZE * i);
+				  (unsigned long)dmah->vaddr + PAGE_SIZE * i);
 			temp_pagelist[dma->page_count + page_count++]
-			    = page + PAGE_SIZE * i;
+				= (unsigned long)dmah->vaddr + PAGE_SIZE * i;
 		}
 		for (offset = 0;
 		     offset + size <= total && entry->buf_count < count;
@@ -811,7 +812,8 @@
 			buf->order = order;
 			buf->used = 0;
 			buf->offset = (dma->byte_count + byte_count + offset);
-			buf->address = (void *)(page + offset);
+			buf->address = (void *)(dmah->vaddr + offset);
+			buf->bus_address = dmah->busaddr + offset;
 			buf->next = NULL;
 			buf->waiting = 0;
 			buf->pending = 0;
diff -urN oldtree/drivers/char/drm/drm_dma.c newtree/drivers/char/drm/drm_dma.c
--- oldtree/drivers/char/drm/drm_dma.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/drm_dma.c	2006-04-01 05:35:38.002995000 -0500
@@ -85,9 +85,7 @@
 				  dma->bufs[i].seg_count);
 			for (j = 0; j < dma->bufs[i].seg_count; j++) {
 				if (dma->bufs[i].seglist[j]) {
-					drm_free_pages(dma->bufs[i].seglist[j],
-						       dma->bufs[i].page_order,
-						       DRM_MEM_DMA);
+					drm_pci_free(dev, dma->bufs[i].seglist[j]);
 				}
 			}
 			drm_free(dma->bufs[i].seglist,
diff -urN oldtree/drivers/char/drm/drm_pci.c newtree/drivers/char/drm/drm_pci.c
--- oldtree/drivers/char/drm/drm_pci.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/drm_pci.c	2006-04-01 05:35:38.002995000 -0500
@@ -50,6 +50,10 @@
 				dma_addr_t maxaddr)
 {
 	drm_dma_handle_t *dmah;
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 
@@ -79,7 +83,7 @@
 		return NULL;
 
 	dmah->size = size;
-	dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr);
+	dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
 
 #ifdef DRM_DEBUG_MEMORY
 	if (dmah->vaddr == NULL) {
@@ -104,18 +108,29 @@
 
 	memset(dmah->vaddr, 0, size);
 
+	/* XXX - Is virt_to_page() legal for consistent mem? */
+	/* Reserve */
+	for (addr = (unsigned long)dmah->vaddr, sz = size;
+	     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+		SetPageReserved(virt_to_page(addr));
+	}
+
 	return dmah;
 }
 
 EXPORT_SYMBOL(drm_pci_alloc);
 
 /**
- * \brief Free a PCI consistent memory block with freeing its descriptor.
+ * \brief Free a PCI consistent memory block without freeing its descriptor.
  *
  * This function is for internal use in the Linux-specific DRM core code.
  */
 void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
 {
+#if 1
+	unsigned long addr;
+	size_t sz;
+#endif
 #ifdef DRM_DEBUG_MEMORY
 	int area = DRM_MEM_DMA;
 	int alloc_count;
@@ -127,8 +142,14 @@
 		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
 #endif
 	} else {
-		pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr,
-				    dmah->busaddr);
+		/* XXX - Is virt_to_page() legal for consistent mem? */
+		/* Unreserve */
+		for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
+		     sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+			ClearPageReserved(virt_to_page(addr));
+		}
+		dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
+				  dmah->busaddr);
 	}
 
 #ifdef DRM_DEBUG_MEMORY
diff -urN oldtree/drivers/char/drm/drm_pciids.h newtree/drivers/char/drm/drm_pciids.h
--- oldtree/drivers/char/drm/drm_pciids.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/drm_pciids.h	2006-04-01 05:35:38.002995000 -0500
@@ -3,49 +3,69 @@
    Please contact dri-devel@lists.sf.net to add new cards to this list
 */
 #define radeon_PCI_IDS \
-	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\
+	{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
 	{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
+	{0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
 	{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP}, \
+	{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
 	{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \
-	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
-	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
+	{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
-	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
 	{0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
+	{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
 	{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
 	{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
@@ -53,44 +73,66 @@
 	{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
 	{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x514F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
 	{0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
 	{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
 	{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
-	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
+	{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
+	{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
-	{0x1002, 0x5837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
 	{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
-	{0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
+	{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
 	{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
 	{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
-	{0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
-	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
-	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \
+	{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
+	{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
 	{0, 0, 0}
 
 #define r128_PCI_IDS \
diff -urN oldtree/drivers/char/drm/i915_dma.c newtree/drivers/char/drm/i915_dma.c
--- oldtree/drivers/char/drm/i915_dma.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/i915_dma.c	2006-04-01 05:35:38.006995250 -0500
@@ -495,8 +495,6 @@
 		}
 	}
 
-	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
-
 	i915_emit_breadcrumb(dev);
 
 	return 0;
diff -urN oldtree/drivers/char/drm/i915_irq.c newtree/drivers/char/drm/i915_irq.c
--- oldtree/drivers/char/drm/i915_irq.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/i915_irq.c	2006-04-01 05:35:38.006995250 -0500
@@ -53,6 +53,8 @@
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
 
+	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+
 	if (temp & USER_INT_FLAG)
 		DRM_WAKEUP(&dev_priv->irq_queue);
 
diff -urN oldtree/drivers/char/drm/r300_cmdbuf.c newtree/drivers/char/drm/r300_cmdbuf.c
--- oldtree/drivers/char/drm/r300_cmdbuf.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/r300_cmdbuf.c	2006-04-01 05:35:38.006995250 -0500
@@ -214,13 +214,13 @@
 	ADD_RANGE(0x4F54, 1);
 
 	ADD_RANGE(R300_TX_FILTER_0, 16);
-	ADD_RANGE(R300_TX_UNK1_0, 16);
+	ADD_RANGE(R300_TX_FILTER1_0, 16);
 	ADD_RANGE(R300_TX_SIZE_0, 16);
 	ADD_RANGE(R300_TX_FORMAT_0, 16);
 	ADD_RANGE(R300_TX_PITCH_0, 16);
 	/* Texture offset is dangerous and needs more checking */
 	ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
-	ADD_RANGE(R300_TX_UNK4_0, 16);
+	ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
 	ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
 
 	/* Sporadic registers used as primitives are emitted */
@@ -242,8 +242,10 @@
 	return 0;
 }
 
-  /* we expect offsets passed to the framebuffer to be either within video memory or
-     within AGP space */
+/*
+ * we expect offsets passed to the framebuffer to be either within video 
+ * memory or within AGP space 
+ */
 static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
 					u32 offset)
 {
@@ -251,11 +253,11 @@
 	   but this value is not being kept.
 	   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))
+	if (offset >= dev_priv->fb_location &&
+	    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))
+	if (offset >= dev_priv->gart_vm_start &&
+	    offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
 		return 0;
 	return 1;
 }
@@ -490,6 +492,7 @@
 
 	return 0;
 }
+
 static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
 					     drm_radeon_kcmd_buffer_t *cmdbuf)
 {
@@ -701,6 +704,64 @@
 	buf->used = 0;
 }
 
+static int r300_scratch(drm_radeon_private_t *dev_priv,
+			drm_radeon_kcmd_buffer_t *cmdbuf,
+			drm_r300_cmd_header_t header)
+{
+	u32 *ref_age_base;
+	u32 i, buf_idx, h_pending;
+	RING_LOCALS;
+	
+	if (cmdbuf->bufsz < 
+	    (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	if (header.scratch.reg >= 5) {
+		return DRM_ERR(EINVAL);
+	}
+	
+	dev_priv->scratch_ages[header.scratch.reg]++;
+	
+	ref_age_base = *(u32 **)cmdbuf->buf;
+	
+	cmdbuf->buf += sizeof(u64);
+	cmdbuf->bufsz -= sizeof(u64);
+	
+	for (i=0; i < header.scratch.n_bufs; i++) {
+		buf_idx = *(u32 *)cmdbuf->buf;
+		buf_idx *= 2; /* 8 bytes per buf */
+		
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		if (h_pending == 0) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		h_pending--;
+						
+		if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
+			return DRM_ERR(EINVAL);
+		}
+					
+		cmdbuf->buf += sizeof(buf_idx);
+		cmdbuf->bufsz -= sizeof(buf_idx);
+	}
+	
+	BEGIN_RING(2);
+	OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0));
+	OUT_RING(dev_priv->scratch_ages[header.scratch.reg]);
+	ADVANCE_RING();
+	
+	return 0;
+}
+
 /**
  * Parses and validates a user-supplied command buffer and emits appropriate
  * commands on the DMA ring buffer.
@@ -838,6 +899,15 @@
 			}
 			break;
 
+		case R300_CMD_SCRATCH:
+			DRM_DEBUG("R300_CMD_SCRATCH\n");
+			ret = r300_scratch(dev_priv, cmdbuf, header);
+			if (ret) {
+				DRM_ERROR("r300_scratch failed\n");
+				goto cleanup;
+			}
+			break;
+			
 		default:
 			DRM_ERROR("bad cmd_type %i at %p\n",
 				  header.header.cmd_type,
diff -urN oldtree/drivers/char/drm/r300_reg.h newtree/drivers/char/drm/r300_reg.h
--- oldtree/drivers/char/drm/r300_reg.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/r300_reg.h	2006-04-01 05:35:38.010995500 -0500
@@ -711,8 +711,22 @@
 #	define R300_TX_MAX_ANISO_16_TO_1 (8 << 21)
 #	define R300_TX_MAX_ANISO_MASK    (14 << 21)
 
-#define R300_TX_UNK1_0                      0x4440
+#define R300_TX_FILTER1_0                      0x4440
+#	define R300_CHROMA_KEY_MODE_DISABLE    0
+#	define R300_CHROMA_KEY_FORCE	       1
+#	define R300_CHROMA_KEY_BLEND           2
+#	define R300_MC_ROUND_NORMAL            (0<<2)
+#	define R300_MC_ROUND_MPEG4             (1<<2)
 #	define R300_LOD_BIAS_MASK	    0x1fff
+#	define R300_EDGE_ANISO_EDGE_DIAG       (0<<13)
+#	define R300_EDGE_ANISO_EDGE_ONLY       (1<<13)
+#	define R300_MC_COORD_TRUNCATE_DISABLE  (0<<14)
+#	define R300_MC_COORD_TRUNCATE_MPEG     (1<<14)
+#	define R300_TX_TRI_PERF_0_8            (0<<15)
+#	define R300_TX_TRI_PERF_1_8            (1<<15)
+#	define R300_TX_TRI_PERF_1_4            (2<<15)
+#	define R300_TX_TRI_PERF_3_8            (3<<15)
+#	define R300_ANISO_THRESHOLD_MASK       (7<<17)
 
 #define R300_TX_SIZE_0                      0x4480
 #       define R300_TX_WIDTHMASK_SHIFT           0
@@ -722,6 +736,8 @@
 #       define R300_TX_UNK23                     (1 << 23)
 #       define R300_TX_SIZE_SHIFT                26	/* largest of width, height */
 #       define R300_TX_SIZE_MASK                 (15 << 26)
+#       define R300_TX_SIZE_PROJECTED                     (1<<30)
+#       define R300_TX_SIZE_TXPITCH_EN                     (1<<31)
 #define R300_TX_FORMAT_0                    0x44C0
 	/* The interpretation of the format word by Wladimir van der Laan */
 	/* The X, Y, Z and W refer to the layout of the components.
@@ -750,7 +766,8 @@
 #	define R300_TX_FORMAT_B8G8_B8G8	    	    0x14	/* no swizzle */
 #	define R300_TX_FORMAT_G8R8_G8B8	    	    0x15	/* no swizzle */
 						  /* 0x16 - some 16 bit green format.. ?? */
-#	define R300_TX_FORMAT_UNK25		   (1 << 25)	/* no swizzle */
+#	define R300_TX_FORMAT_UNK25		   (1 << 25) /* no swizzle */
+#	define R300_TX_FORMAT_CUBIC_MAP		   (1 << 26)
 
 	/* gap */
 	/* Floating point formats */
@@ -800,18 +817,20 @@
 
 #	define R300_TX_FORMAT_YUV_MODE		0x00800000
 
-#define R300_TX_PITCH_0			    0x4500
+#define R300_TX_PITCH_0			    0x4500 /* obvious missing in gap */
 #define R300_TX_OFFSET_0                    0x4540
 /* BEGIN: Guess from R200 */
 #       define R300_TXO_ENDIAN_NO_SWAP           (0 << 0)
 #       define R300_TXO_ENDIAN_BYTE_SWAP         (1 << 0)
 #       define R300_TXO_ENDIAN_WORD_SWAP         (2 << 0)
 #       define R300_TXO_ENDIAN_HALFDW_SWAP       (3 << 0)
+#       define R300_TXO_MACRO_TILE               (1 << 2)
+#       define R300_TXO_MICRO_TILE               (1 << 3)
 #       define R300_TXO_OFFSET_MASK              0xffffffe0
 #       define R300_TXO_OFFSET_SHIFT             5
 /* END */
-#define R300_TX_UNK4_0                      0x4580
-#define R300_TX_BORDER_COLOR_0              0x45C0	//ff00ff00 == { 0, 1.0, 0, 1.0 }
+#define R300_TX_CHROMA_KEY_0                      0x4580 /* 32 bit chroma key */
+#define R300_TX_BORDER_COLOR_0              0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
 
 /* END */
 
@@ -868,7 +887,9 @@
 #       define R300_PFS_NODE_TEX_OFFSET_MASK     (31 << 12)
 #       define R300_PFS_NODE_TEX_END_SHIFT       17
 #       define R300_PFS_NODE_TEX_END_MASK        (31 << 17)
-#       define R300_PFS_NODE_LAST_NODE           (1 << 22)
+/*#       define R300_PFS_NODE_LAST_NODE           (1 << 22) */
+#		define R300_PFS_NODE_OUTPUT_COLOR        (1 << 22)
+#		define R300_PFS_NODE_OUTPUT_DEPTH        (1 << 23)
 
 /* TEX
 // As far as I can tell, texture instructions cannot write into output
@@ -887,6 +908,7 @@
  */
 #		define R300_FPITX_OPCODE_SHIFT			15
 #			define R300_FPITX_OP_TEX			1
+#			define R300_FPITX_OP_KIL			2
 #			define R300_FPITX_OP_TXP			3
 #			define R300_FPITX_OP_TXB			4
 
@@ -962,9 +984,11 @@
 #       define R300_FPI1_SRC2C_CONST             (1 << 17)
 #       define R300_FPI1_DSTC_SHIFT              18
 #       define R300_FPI1_DSTC_MASK               (31 << 18)
+#		define R300_FPI1_DSTC_REG_MASK_SHIFT     23
 #       define R300_FPI1_DSTC_REG_X              (1 << 23)
 #       define R300_FPI1_DSTC_REG_Y              (1 << 24)
 #       define R300_FPI1_DSTC_REG_Z              (1 << 25)
+#		define R300_FPI1_DSTC_OUTPUT_MASK_SHIFT  26
 #       define R300_FPI1_DSTC_OUTPUT_X           (1 << 26)
 #       define R300_FPI1_DSTC_OUTPUT_Y           (1 << 27)
 #       define R300_FPI1_DSTC_OUTPUT_Z           (1 << 28)
@@ -983,6 +1007,7 @@
 #       define R300_FPI3_DSTA_MASK               (31 << 18)
 #       define R300_FPI3_DSTA_REG                (1 << 23)
 #       define R300_FPI3_DSTA_OUTPUT             (1 << 24)
+#		define R300_FPI3_DSTA_DEPTH              (1 << 27)
 
 #define R300_PFS_INSTR0_0                   0x48C0
 #       define R300_FPI0_ARGC_SRC0C_XYZ          0
@@ -1036,7 +1061,7 @@
 #       define R300_FPI0_OUTC_FRC                (9 << 23)
 #       define R300_FPI0_OUTC_REPL_ALPHA         (10 << 23)
 #       define R300_FPI0_OUTC_SAT                (1 << 30)
-#       define R300_FPI0_UNKNOWN_31              (1 << 31)
+#       define R300_FPI0_INSERT_NOP              (1 << 31)
 
 #define R300_PFS_INSTR2_0                   0x49C0
 #       define R300_FPI2_ARGA_SRC0C_X            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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/radeon_cp.c	2006-04-01 05:35:38.010995500 -0500
@@ -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 */
@@ -1317,6 +1332,14 @@
 
 	DRM_DEBUG("\n");
 
+	/* if we require new memory map but we don't have it fail */
+	if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
+	{
+		DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
+		radeon_do_cleanup_cp(dev);
+		return DRM_ERR(EINVAL);
+	}
+
 	if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
 	{
 		DRM_DEBUG("Forcing AGP card to PCI mode\n");
@@ -1496,6 +1519,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 +1536,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 +1660,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/radeon_drm.h	2006-04-01 05:35:38.010995500 -0500
@@ -222,6 +222,7 @@
 #	define R300_WAIT_3D  		0x2
 #	define R300_WAIT_2D_CLEAN  	0x3
 #	define R300_WAIT_3D_CLEAN  	0x4
+#define R300_CMD_SCRATCH		8
 
 typedef union {
 	unsigned int u;
@@ -247,6 +248,9 @@
 	struct {
 		unsigned char cmd_type, flags, pad0, pad1;
 	} wait;
+	struct {
+		unsigned char cmd_type, reg, n_bufs, flags;
+	} scratch;
 } drm_r300_cmd_header_t;
 
 #define RADEON_FRONT			0x1
@@ -697,6 +701,7 @@
 #define RADEON_SETPARAM_FB_LOCATION    1	/* determined framebuffer location */
 #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
  */
diff -urN oldtree/drivers/char/drm/radeon_drv.h newtree/drivers/char/drm/radeon_drv.h
--- oldtree/drivers/char/drm/radeon_drv.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/radeon_drv.h	2006-04-01 05:35:38.010995500 -0500
@@ -38,7 +38,7 @@
 
 #define DRIVER_NAME		"radeon"
 #define DRIVER_DESC		"ATI Radeon"
-#define DRIVER_DATE		"20051229"
+#define DRIVER_DATE		"20060225"
 
 /* Interface history:
  *
@@ -91,9 +91,11 @@
  * 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
+ * 1.24- Add general-purpose packet for manipulating scratch registers (r300)
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		22
+#define DRIVER_MINOR		24
 #define DRIVER_PATCHLEVEL	0
 
 /*
@@ -101,20 +103,21 @@
  */
 enum radeon_family {
 	CHIP_R100,
-	CHIP_RS100,
 	CHIP_RV100,
+	CHIP_RS100,
 	CHIP_RV200,
-	CHIP_R200,
 	CHIP_RS200,
-	CHIP_R250,
-	CHIP_RS250,
+	CHIP_R200,
 	CHIP_RV250,
+	CHIP_RS300,
 	CHIP_RV280,
 	CHIP_R300,
-	CHIP_RS300,
 	CHIP_R350,
 	CHIP_RV350,
+	CHIP_RV380,
 	CHIP_R420,
+	CHIP_RV410,
+	CHIP_RS400,
 	CHIP_LAST,
 };
 
@@ -136,9 +139,11 @@
 	CHIP_IS_AGP = 0x00080000UL,
 	CHIP_HAS_HIERZ = 0x00100000UL,
 	CHIP_IS_PCIE = 0x00200000UL,
+	CHIP_NEW_MEMMAP = 0x00400000UL,
 };
 
-#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 {
@@ -199,6 +204,8 @@
 	drm_radeon_sarea_t *sarea_priv;
 
 	u32 fb_location;
+	u32 fb_size;
+	int new_memmap;
 
 	int gart_size;
 	u32 gart_vm_start;
@@ -272,6 +279,8 @@
 	unsigned long pcigart_offset;
 	drm_ati_pcigart_info gart_info;
 
+	u32 scratch_ages[5];
+
 	/* starting from here on, data is preserved accross an open */
 	uint32_t flags;		/* see radeon_chip_flags */
 } drm_radeon_private_t;
diff -urN oldtree/drivers/char/drm/radeon_state.c newtree/drivers/char/drm/radeon_state.c
--- oldtree/drivers/char/drm/radeon_state.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/drm/radeon_state.c	2006-04-01 05:35:38.014995750 -0500
@@ -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 *
@@ -1939,11 +1970,6 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_alloc_t alloc;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(alloc,
 				 (drm_radeon_surface_alloc_t __user *) data,
 				 sizeof(alloc));
@@ -1960,12 +1986,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_surface_free_t memfree;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
-	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
+	DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
 				 sizeof(memfree));
 
 	if (free_surface(filp, dev_priv, memfree.address))
@@ -2100,11 +2121,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
@@ -2189,11 +2205,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
@@ -2340,11 +2351,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(indirect,
 				 (drm_radeon_indirect_t __user *) data,
 				 sizeof(indirect));
@@ -2417,11 +2423,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
@@ -2738,11 +2739,6 @@
 
 	LOCK_TEST_WITH_RETURN(dev, filp);
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(cmdbuf,
@@ -2897,11 +2893,6 @@
 	drm_radeon_getparam_t param;
 	int value;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
 				 sizeof(param));
 
@@ -2981,11 +2972,6 @@
 	drm_radeon_setparam_t sp;
 	struct drm_radeon_driver_file_fields *radeon_priv;
 
-	if (!dev_priv) {
-		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
-		return DRM_ERR(EINVAL);
-	}
-
 	DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
 
 	DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
@@ -3012,6 +2998,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/pcmcia/cm4000_cs.c newtree/drivers/char/pcmcia/cm4000_cs.c
--- oldtree/drivers/char/pcmcia/cm4000_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/pcmcia/cm4000_cs.c	2006-04-01 05:35:44.243385000 -0500
@@ -46,7 +46,7 @@
 /* #define ATR_CSUM */
 
 #ifdef PCMCIA_DEBUG
-#define reader_to_dev(x)	(&handle_to_dev(x->link.handle))
+#define reader_to_dev(x)	(&handle_to_dev(x->p_dev->handle))
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0600);
 #define DEBUGP(n, rdr, x, args...) do { 				\
@@ -67,7 +67,7 @@
 #define	T_100MSEC	msecs_to_jiffies(100)
 #define	T_500MSEC	msecs_to_jiffies(500)
 
-static void cm4000_release(dev_link_t *link);
+static void cm4000_release(struct pcmcia_device *link);
 
 static int major;		/* major number we get from the kernel */
 
@@ -106,7 +106,7 @@
 #define REG_STOPBITS(x)		(x + 7)
 
 struct cm4000_dev {
-	dev_link_t link;		/* pcmcia link */
+	struct pcmcia_device *p_dev;
 	dev_node_t node;		/* OS node (major,minor) */
 
 	unsigned char atr[MAX_ATR];
@@ -149,14 +149,14 @@
 #define	ZERO_DEV(dev)  						\
 	memset(&dev->atr_csum,0,				\
 		sizeof(struct cm4000_dev) - 			\
-		/*link*/ sizeof(dev_link_t) - 			\
+		/*link*/ sizeof(struct pcmcia_device) - 	\
 		/*node*/ sizeof(dev_node_t) - 			\
 		/*atr*/ MAX_ATR*sizeof(char) - 			\
 		/*rbuf*/ 512*sizeof(char) - 			\
 		/*sbuf*/ 512*sizeof(char) - 			\
 		/*queue*/ 4*sizeof(wait_queue_head_t))
 
-static dev_link_t *dev_table[CM4000_MAX_DEV];
+static struct pcmcia_device *dev_table[CM4000_MAX_DEV];
 static struct class *cmm_class;
 
 /* This table doesn't use spaces after the comma between fields and thus
@@ -454,7 +454,7 @@
 static void set_cardparameter(struct cm4000_dev *dev)
 {
 	int i;
-	ioaddr_t iobase = dev->link.io.BasePort1;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
 	u_int8_t stopbits = 0x02; /* ISO default */
 
 	DEBUGP(3, dev, "-> set_cardparameter\n");
@@ -487,7 +487,7 @@
 	unsigned short num_bytes_read;
 	unsigned char pts_reply[4];
 	ssize_t rc;
-	ioaddr_t iobase = dev->link.io.BasePort1;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
 
 	rc = 0;
 
@@ -699,7 +699,7 @@
 static void monitor_card(unsigned long p)
 {
 	struct cm4000_dev *dev = (struct cm4000_dev *) p;
-	ioaddr_t iobase = dev->link.io.BasePort1;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
 	unsigned short s;
 	struct ptsreq ptsreq;
 	int i, atrc;
@@ -962,7 +962,7 @@
 			loff_t *ppos)
 {
 	struct cm4000_dev *dev = filp->private_data;
-	ioaddr_t iobase = dev->link.io.BasePort1;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
 	ssize_t rc;
 	int i, j, k;
 
@@ -971,7 +971,7 @@
 	if (count == 0)		/* according to manpage */
 		return 0;
 
-	if ((dev->link.state & DEV_PRESENT) == 0 ||	/* socket removed */
+	if (!pcmcia_dev_present(dev->p_dev) || /* device removed */
 	    test_bit(IS_CMM_ABSENT, &dev->flags))
 		return -ENODEV;
 
@@ -1083,7 +1083,7 @@
 			 size_t count, loff_t *ppos)
 {
 	struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
-	ioaddr_t iobase = dev->link.io.BasePort1;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
 	unsigned short s;
 	unsigned char tmp;
 	unsigned char infolen;
@@ -1108,7 +1108,7 @@
 
 	sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0;
 
-	if ((dev->link.state & DEV_PRESENT) == 0 ||	/* socket removed */
+	if (!pcmcia_dev_present(dev->p_dev) || /* device removed */
 	    test_bit(IS_CMM_ABSENT, &dev->flags))
 		return -ENODEV;
 
@@ -1440,8 +1440,8 @@
 		     unsigned long arg)
 {
 	struct cm4000_dev *dev = filp->private_data;
-	ioaddr_t iobase = dev->link.io.BasePort1;
-	dev_link_t *link;
+	ioaddr_t iobase = dev->p_dev->io.BasePort1;
+	struct pcmcia_device *link;
 	int size;
 	int rc;
 	void __user *argp = (void __user *)arg;
@@ -1458,7 +1458,7 @@
 	       iminor(inode), ioctl_names[_IOC_NR(cmd)]);
 
 	link = dev_table[iminor(inode)];
-	if (!(DEV_OK(link))) {
+	if (!pcmcia_dev_present(link)) {
 		DEBUGP(4, dev, "DEV_OK false\n");
 		return -ENODEV;
 	}
@@ -1660,14 +1660,14 @@
 static int cmm_open(struct inode *inode, struct file *filp)
 {
 	struct cm4000_dev *dev;
-	dev_link_t *link;
+	struct pcmcia_device *link;
 	int rc, minor = iminor(inode);
 
 	if (minor >= CM4000_MAX_DEV)
 		return -ENODEV;
 
 	link = dev_table[minor];
-	if (link == NULL || !(DEV_OK(link)))
+	if (link == NULL || !pcmcia_dev_present(link))
 		return -ENODEV;
 
 	if (link->open)
@@ -1709,7 +1709,7 @@
 static int cmm_close(struct inode *inode, struct file *filp)
 {
 	struct cm4000_dev *dev;
-	dev_link_t *link;
+	struct pcmcia_device *link;
 	int minor = iminor(inode);
 
 	if (minor >= CM4000_MAX_DEV)
@@ -1735,7 +1735,7 @@
 	return 0;
 }
 
-static void cmm_cm4000_release(dev_link_t * link)
+static void cmm_cm4000_release(struct pcmcia_device * link)
 {
 	struct cm4000_dev *dev = link->priv;
 
@@ -1759,13 +1759,11 @@
 
 /*==== Interface to PCMCIA Layer =======================================*/
 
-static void cm4000_config(dev_link_t * link, int devno)
+static int cm4000_config(struct pcmcia_device * link, int devno)
 {
-	client_handle_t handle = link->handle;
 	struct cm4000_dev *dev;
 	tuple_t tuple;
 	cisparse_t parse;
-	config_info_t conf;
 	u_char buf[64];
 	int fail_fn, fail_rc;
 	int rc;
@@ -1777,41 +1775,34 @@
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
 
-	if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+	if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) {
 		fail_fn = GetFirstTuple;
 		goto cs_failed;
 	}
-	if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+	if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) {
 		fail_fn = GetTupleData;
 		goto cs_failed;
 	}
 	if ((fail_rc =
-	     pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) {
+	     pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) {
 		fail_fn = ParseTuple;
 		goto cs_failed;
 	}
-	if ((fail_rc =
-	     pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) {
-		fail_fn = GetConfigurationInfo;
-		goto cs_failed;
-	}
 
-	link->state |= DEV_CONFIG;
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
-	link->conf.Vcc = conf.Vcc;
 
 	link->io.BasePort2 = 0;
 	link->io.NumPorts2 = 0;
 	link->io.Attributes2 = 0;
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (rc = pcmcia_get_first_tuple(handle, &tuple);
-	     rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) {
+	for (rc = pcmcia_get_first_tuple(link, &tuple);
+	     rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) {
 
-		rc = pcmcia_get_tuple_data(handle, &tuple);
+		rc = pcmcia_get_tuple_data(link, &tuple);
 		if (rc != CS_SUCCESS)
 			continue;
-		rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+		rc = pcmcia_parse_tuple(link, &tuple, &parse);
 		if (rc != CS_SUCCESS)
 			continue;
 
@@ -1831,7 +1822,7 @@
 		link->io.IOAddrLines = parse.cftable_entry.io.flags
 		    & CISTPL_IO_LINES_MASK;
 
-		rc = pcmcia_request_io(handle, &link->io);
+		rc = pcmcia_request_io(link, &link->io);
 		if (rc == CS_SUCCESS)
 			break;	/* we are done */
 	}
@@ -1841,7 +1832,7 @@
 	link->conf.IntType = 00000002;
 
 	if ((fail_rc =
-	     pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) {
+	     pcmcia_request_configuration(link, &link->conf)) != CS_SUCCESS) {
 		fail_fn = RequestConfiguration;
 		goto cs_release;
 	}
@@ -1851,63 +1842,48 @@
 	dev->node.major = major;
 	dev->node.minor = devno;
 	dev->node.next = NULL;
-	link->dev = &dev->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &dev->node;
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(handle, fail_fn, fail_rc);
+	cs_error(link, fail_fn, fail_rc);
 cs_release:
 	cm4000_release(link);
-
-	link->state &= ~DEV_CONFIG_PENDING;
+	return -ENODEV;
 }
 
-static int cm4000_suspend(struct pcmcia_device *p_dev)
+static int cm4000_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct cm4000_dev *dev;
 
 	dev = link->priv;
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 	stop_monitor(dev);
 
 	return 0;
 }
 
-static int cm4000_resume(struct pcmcia_device *p_dev)
+static int cm4000_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct cm4000_dev *dev;
 
 	dev = link->priv;
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
 	if (link->open)
 		start_monitor(dev);
 
 	return 0;
 }
 
-static void cm4000_release(dev_link_t *link)
+static void cm4000_release(struct pcmcia_device *link)
 {
 	cmm_cm4000_release(link->priv);	/* delay release until device closed */
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_disable_device(link);
 }
 
-static int cm4000_attach(struct pcmcia_device *p_dev)
+static int cm4000_probe(struct pcmcia_device *link)
 {
 	struct cm4000_dev *dev;
-	dev_link_t *link;
-	int i;
+	int i, ret;
 
 	for (i = 0; i < CM4000_MAX_DEV; i++)
 		if (dev_table[i] == NULL)
@@ -1923,7 +1899,7 @@
 	if (dev == NULL)
 		return -ENOMEM;
 
-	link = &dev->link;
+	dev->p_dev = link;
 	link->priv = dev;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	dev_table[i] = link;
@@ -1933,11 +1909,9 @@
 	init_waitqueue_head(&dev->atrq);
 	init_waitqueue_head(&dev->readq);
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	cm4000_config(link, i);
+	ret = cm4000_config(link, i);
+	if (ret)
+		return ret;
 
 	class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
 			    "cmm%d", i);
@@ -1945,9 +1919,8 @@
 	return 0;
 }
 
-static void cm4000_detach(struct pcmcia_device *p_dev)
+static void cm4000_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct cm4000_dev *dev = link->priv;
 	int devno;
 
@@ -1958,11 +1931,9 @@
 	if (devno == CM4000_MAX_DEV)
 		return;
 
-	link->state &= ~DEV_PRESENT;
 	stop_monitor(dev);
 
-	if (link->state & DEV_CONFIG)
- 		cm4000_release(link);
+	cm4000_release(link);
 
 	dev_table[devno] = NULL;
  	kfree(dev);
@@ -1993,7 +1964,7 @@
 	.drv	  = {
 		.name = "cm4000_cs",
 		},
-	.probe    = cm4000_attach,
+	.probe    = cm4000_probe,
 	.remove   = cm4000_detach,
 	.suspend  = cm4000_suspend,
 	.resume   = cm4000_resume,
diff -urN oldtree/drivers/char/pcmcia/cm4040_cs.c newtree/drivers/char/pcmcia/cm4040_cs.c
--- oldtree/drivers/char/pcmcia/cm4040_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/pcmcia/cm4040_cs.c	2006-04-01 05:35:44.243385000 -0500
@@ -41,7 +41,7 @@
 
 
 #ifdef PCMCIA_DEBUG
-#define reader_to_dev(x)	(&handle_to_dev(x->link.handle))
+#define reader_to_dev(x)	(&handle_to_dev(x->p_dev->handle))
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0600);
 #define DEBUGP(n, rdr, x, args...) do { 				\
@@ -65,7 +65,7 @@
 /* how often to poll for fifo status change */
 #define POLL_PERIOD 				msecs_to_jiffies(10)
 
-static void reader_release(dev_link_t *link);
+static void reader_release(struct pcmcia_device *link);
 
 static int major;
 static struct class *cmx_class;
@@ -74,7 +74,7 @@
 #define		BS_WRITABLE	0x02
 
 struct reader_dev {
-	dev_link_t		link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t		node;
 	wait_queue_head_t	devq;
 	wait_queue_head_t	poll_wait;
@@ -87,7 +87,7 @@
 	struct timer_list 	poll_timer;
 };
 
-static dev_link_t *dev_table[CM_MAX_DEV];
+static struct pcmcia_device *dev_table[CM_MAX_DEV];
 
 #ifndef PCMCIA_DEBUG
 #define	xoutb	outb
@@ -116,7 +116,7 @@
 static void cm4040_do_poll(unsigned long dummy)
 {
 	struct reader_dev *dev = (struct reader_dev *) dummy;
-	unsigned int obs = xinb(dev->link.io.BasePort1
+	unsigned int obs = xinb(dev->p_dev->io.BasePort1
 				+ REG_OFFSET_BUFFER_STATUS);
 
 	if ((obs & BSR_BULK_IN_FULL)) {
@@ -147,7 +147,7 @@
 static int wait_for_bulk_out_ready(struct reader_dev *dev)
 {
 	int i, rc;
-	int iobase = dev->link.io.BasePort1;
+	int iobase = dev->p_dev->io.BasePort1;
 
 	for (i = 0; i < POLL_LOOP_COUNT; i++) {
 		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
@@ -177,7 +177,7 @@
 /* Write to Sync Control Register */
 static int write_sync_reg(unsigned char val, struct reader_dev *dev)
 {
-	int iobase = dev->link.io.BasePort1;
+	int iobase = dev->p_dev->io.BasePort1;
 	int rc;
 
 	rc = wait_for_bulk_out_ready(dev);
@@ -195,7 +195,7 @@
 static int wait_for_bulk_in_ready(struct reader_dev *dev)
 {
 	int i, rc;
-	int iobase = dev->link.io.BasePort1;
+	int iobase = dev->p_dev->io.BasePort1;
 
 	for (i = 0; i < POLL_LOOP_COUNT; i++) {
 		if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
@@ -225,7 +225,7 @@
 			size_t count, loff_t *ppos)
 {
 	struct reader_dev *dev = filp->private_data;
-	int iobase = dev->link.io.BasePort1;
+	int iobase = dev->p_dev->io.BasePort1;
 	size_t bytes_to_read;
 	unsigned long i;
 	size_t min_bytes_to_read;
@@ -246,7 +246,7 @@
 		return -EAGAIN;
 	}
 
-	if ((dev->link.state & DEV_PRESENT)==0)
+	if (!pcmcia_dev_present(dev->p_dev))
 		return -ENODEV;
 
 	for (i = 0; i < 5; i++) {
@@ -328,7 +328,7 @@
 			 size_t count, loff_t *ppos)
 {
 	struct reader_dev *dev = filp->private_data;
-	int iobase = dev->link.io.BasePort1;
+	int iobase = dev->p_dev->io.BasePort1;
 	ssize_t rc;
 	int i;
 	unsigned int bytes_to_write;
@@ -351,7 +351,7 @@
 		return -EAGAIN;
 	}
 
-	if ((dev->link.state & DEV_PRESENT) == 0)
+	if (!pcmcia_dev_present(dev->p_dev))
 		return -ENODEV;
 
 	bytes_to_write = count;
@@ -445,14 +445,14 @@
 static int cm4040_open(struct inode *inode, struct file *filp)
 {
 	struct reader_dev *dev;
-	dev_link_t *link;
+	struct pcmcia_device *link;
 	int minor = iminor(inode);
 
 	if (minor >= CM_MAX_DEV)
 		return -ENODEV;
 
 	link = dev_table[minor];
-	if (link == NULL || !(DEV_OK(link)))
+	if (link == NULL || !pcmcia_dev_present(link))
 		return -ENODEV;
 
 	if (link->open)
@@ -478,7 +478,7 @@
 static int cm4040_close(struct inode *inode, struct file *filp)
 {
 	struct reader_dev *dev = filp->private_data;
-	dev_link_t *link;
+	struct pcmcia_device *link;
 	int minor = iminor(inode);
 
 	DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode),
@@ -500,7 +500,7 @@
 	return 0;
 }
 
-static void cm4040_reader_release(dev_link_t *link)
+static void cm4040_reader_release(struct pcmcia_device *link)
 {
 	struct reader_dev *dev = link->priv;
 
@@ -514,60 +514,49 @@
 	return;
 }
 
-static void reader_config(dev_link_t *link, int devno)
+static int reader_config(struct pcmcia_device *link, int devno)
 {
-	client_handle_t handle;
 	struct reader_dev *dev;
 	tuple_t tuple;
 	cisparse_t parse;
-	config_info_t conf;
 	u_char buf[64];
 	int fail_fn, fail_rc;
 	int rc;
 
-	handle = link->handle;
-
 	tuple.DesiredTuple = CISTPL_CONFIG;
 	tuple.Attributes = 0;
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
  	tuple.TupleOffset = 0;
 
-	if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+	if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) {
 		fail_fn = GetFirstTuple;
 		goto cs_failed;
 	}
-	if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+	if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) {
 		fail_fn = GetTupleData;
 		goto cs_failed;
 	}
-	if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse))
+	if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse))
 							!= CS_SUCCESS) {
 		fail_fn = ParseTuple;
 		goto cs_failed;
 	}
-	if ((fail_rc = pcmcia_get_configuration_info(handle, &conf))
-							!= CS_SUCCESS) {
-		fail_fn = GetConfigurationInfo;
-		goto cs_failed;
-	}
 
-	link->state |= DEV_CONFIG;
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
-	link->conf.Vcc = conf.Vcc;
 
 	link->io.BasePort2 = 0;
 	link->io.NumPorts2 = 0;
 	link->io.Attributes2 = 0;
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (rc = pcmcia_get_first_tuple(handle, &tuple);
+	for (rc = pcmcia_get_first_tuple(link, &tuple);
 	     rc == CS_SUCCESS;
-	     rc = pcmcia_get_next_tuple(handle, &tuple)) {
-		rc = pcmcia_get_tuple_data(handle, &tuple);
+	     rc = pcmcia_get_next_tuple(link, &tuple)) {
+		rc = pcmcia_get_tuple_data(link, &tuple);
 		if (rc != CS_SUCCESS)
 			continue;
-		rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+		rc = pcmcia_parse_tuple(link, &tuple, &parse);
 		if (rc != CS_SUCCESS)
 			continue;
 
@@ -585,13 +574,13 @@
 			link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
 		link->io.IOAddrLines = parse.cftable_entry.io.flags
 						& CISTPL_IO_LINES_MASK;
-		rc = pcmcia_request_io(handle, &link->io);
+		rc = pcmcia_request_io(link, &link->io);
 
-		dev_printk(KERN_INFO, &handle_to_dev(handle), "foo");
+		dev_printk(KERN_INFO, &handle_to_dev(link), "foo");
 		if (rc == CS_SUCCESS)
 			break;
 		else
-			dev_printk(KERN_INFO, &handle_to_dev(handle),
+			dev_printk(KERN_INFO, &handle_to_dev(link),
 				   "pcmcia_request_io failed 0x%x\n", rc);
 	}
 	if (rc != CS_SUCCESS)
@@ -599,10 +588,10 @@
 
 	link->conf.IntType = 00000002;
 
-	if ((fail_rc = pcmcia_request_configuration(handle,&link->conf))
+	if ((fail_rc = pcmcia_request_configuration(link,&link->conf))
 								!=CS_SUCCESS) {
 		fail_fn = RequestConfiguration;
-		dev_printk(KERN_INFO, &handle_to_dev(handle),
+		dev_printk(KERN_INFO, &handle_to_dev(link),
 			   "pcmcia_request_configuration failed 0x%x\n",
 			   fail_rc);
 		goto cs_release;
@@ -612,57 +601,31 @@
 	sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
 	dev->node.major = major;
 	dev->node.minor = devno;
-	dev->node.next = NULL;
-	link->dev = &dev->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	dev->node.next = &dev->node;
 
 	DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
 	      link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
 	DEBUGP(2, dev, "<- reader_config (succ)\n");
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(handle, fail_fn, fail_rc);
+	cs_error(link, fail_fn, fail_rc);
 cs_release:
 	reader_release(link);
-	link->state &= ~DEV_CONFIG_PENDING;
-}
-
-static int reader_suspend(struct pcmcia_device *p_dev)
-{
-	dev_link_t *link = dev_to_instance(p_dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
+	return -ENODEV;
 }
 
-static int reader_resume(struct pcmcia_device *p_dev)
-{
-	dev_link_t *link = dev_to_instance(p_dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
-}
-
-static void reader_release(dev_link_t *link)
+static void reader_release(struct pcmcia_device *link)
 {
 	cm4040_reader_release(link->priv);
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_disable_device(link);
 }
 
-static int reader_attach(struct pcmcia_device *p_dev)
+static int reader_probe(struct pcmcia_device *link)
 {
 	struct reader_dev *dev;
-	dev_link_t *link;
-	int i;
+	int i, ret;
 
 	for (i = 0; i < CM_MAX_DEV; i++) {
 		if (dev_table[i] == NULL)
@@ -679,8 +642,8 @@
 	dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
 	dev->buffer_status = 0;
 
-	link = &dev->link;
 	link->priv = dev;
+	dev->p_dev = link;
 
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	dev_table[i] = link;
@@ -692,11 +655,9 @@
 	init_timer(&dev->poll_timer);
 	dev->poll_timer.function = &cm4040_do_poll;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	reader_config(link, i);
+	ret = reader_config(link, i);
+	if (ret)
+		return ret;
 
 	class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
 			    "cmx%d", i);
@@ -704,9 +665,8 @@
 	return 0;
 }
 
-static void reader_detach(struct pcmcia_device *p_dev)
+static void reader_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct reader_dev *dev = link->priv;
 	int devno;
 
@@ -718,10 +678,7 @@
 	if (devno == CM_MAX_DEV)
 		return;
 
-	link->state &= ~DEV_PRESENT;
-
-	if (link->state & DEV_CONFIG)
-		reader_release(link);
+	reader_release(link);
 
 	dev_table[devno] = NULL;
 	kfree(dev);
@@ -753,10 +710,8 @@
   	.drv		= {
 		.name	= "cm4040_cs",
 	},
-	.probe		= reader_attach,
+	.probe		= reader_probe,
 	.remove		= reader_detach,
-	.suspend	= reader_suspend,
-	.resume		= reader_resume,
 	.id_table	= cm4040_ids,
 };
 
diff -urN oldtree/drivers/char/pcmcia/synclink_cs.c newtree/drivers/char/pcmcia/synclink_cs.c
--- oldtree/drivers/char/pcmcia/synclink_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/pcmcia/synclink_cs.c	2006-04-01 05:35:44.243385000 -0500
@@ -228,7 +228,7 @@
 	struct	_input_signal_events	input_signal_events;
 
 	/* PCMCIA support */
-	dev_link_t	      link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t	      node;
 	int		      stop;
 
@@ -484,7 +484,7 @@
 
 /* PCMCIA prototypes */
 
-static void mgslpc_config(dev_link_t *link);
+static int mgslpc_config(struct pcmcia_device *link);
 static void mgslpc_release(u_long arg);
 static void mgslpc_detach(struct pcmcia_device *p_dev);
 
@@ -533,14 +533,14 @@
 	}
 }
 
-static int mgslpc_attach(struct pcmcia_device *p_dev)
+static int mgslpc_probe(struct pcmcia_device *link)
 {
     MGSLPC_INFO *info;
-    dev_link_t *link;
-    
+    int ret;
+
     if (debug_level >= DEBUG_LEVEL_INFO)
 	    printk("mgslpc_attach\n");
-	
+
     info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
     if (!info) {
 	    printk("Error can't allocate device instance data\n");
@@ -565,25 +565,22 @@
     info->imrb_value = 0xffff;
     info->pim_value = 0xff;
 
-    link = &info->link;
+    info->p_dev = link;
     link->priv = info;
-    
-    /* Initialize the dev_link_t structure */
+
+    /* Initialize the struct pcmcia_device structure */
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1   = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
-    
+
     link->conf.Attributes = 0;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    mgslpc_config(link);
+    ret = mgslpc_config(link);
+    if (ret)
+	    return ret;
 
     mgslpc_add_device(info);
 
@@ -596,15 +593,13 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void mgslpc_config(dev_link_t *link)
+static int mgslpc_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     MGSLPC_INFO *info = link->priv;
     tuple_t tuple;
     cisparse_t parse;
     int last_fn, last_ret;
     u_char buf[64];
-    config_info_t conf;
     cistpl_cftable_entry_t dflt = { 0 };
     cistpl_cftable_entry_t *cfg;
     
@@ -617,27 +612,20 @@
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
 
     /* get CIS configuration entry */
 
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 
     cfg = &(parse.cftable_entry);
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 
     if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
     if (cfg->index == 0)
@@ -658,11 +646,10 @@
 	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
 	    link->io.BasePort1 = io->win[0].base;
 	    link->io.NumPorts1 = io->win[0].len;
-	    CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
+	    CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
 
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 8;
     link->conf.Present = PRESENT_OPTION;
@@ -670,9 +657,9 @@
     link->irq.Attributes |= IRQ_HANDLE_PRESENT;
     link->irq.Handler     = mgslpc_isr;
     link->irq.Instance    = info;
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     info->io_base = link->io.BasePort1;
     info->irq_level = link->irq.AssignedIRQ;
@@ -680,7 +667,7 @@
     /* add to linked list of devices */
     sprintf(info->node.dev_name, "mgslpc0");
     info->node.major = info->node.minor = 0;
-    link->dev = &info->node;
+    link->dev_node = &info->node;
 
     printk(KERN_INFO "%s: index 0x%02x:",
 	   info->node.dev_name, link->conf.ConfigIndex);
@@ -690,13 +677,12 @@
 	    printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 		   link->io.BasePort1+link->io.NumPorts1-1);
     printk("\n");
-    
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
     mgslpc_release((u_long)link);
+    return -ENODEV;
 }
 
 /* Card has been removed.
@@ -705,58 +691,38 @@
  */
 static void mgslpc_release(u_long arg)
 {
-    dev_link_t *link = (dev_link_t *)arg;
+	struct pcmcia_device *link = (struct pcmcia_device *)arg;
 
-    if (debug_level >= DEBUG_LEVEL_INFO)
-	    printk("mgslpc_release(0x%p)\n", link);
-
-    /* Unlink the device chain */
-    link->dev = NULL;
-    link->state &= ~DEV_CONFIG;
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_release(0x%p)\n", link);
 
-    pcmcia_release_configuration(link->handle);
-    if (link->io.NumPorts1)
-	    pcmcia_release_io(link->handle, &link->io);
-    if (link->irq.AssignedIRQ)
-	    pcmcia_release_irq(link->handle, &link->irq);
+	pcmcia_disable_device(link);
 }
 
-static void mgslpc_detach(struct pcmcia_device *p_dev)
+static void mgslpc_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
-    if (debug_level >= DEBUG_LEVEL_INFO)
-	    printk("mgslpc_detach(0x%p)\n", link);
+	if (debug_level >= DEBUG_LEVEL_INFO)
+		printk("mgslpc_detach(0x%p)\n", link);
 
-    if (link->state & DEV_CONFIG) {
-	    ((MGSLPC_INFO *)link->priv)->stop = 1;
-	    mgslpc_release((u_long)link);
-    }
+	((MGSLPC_INFO *)link->priv)->stop = 1;
+	mgslpc_release((u_long)link);
 
-    mgslpc_remove_device((MGSLPC_INFO *)link->priv);
+	mgslpc_remove_device((MGSLPC_INFO *)link->priv);
 }
 
-static int mgslpc_suspend(struct pcmcia_device *dev)
+static int mgslpc_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	MGSLPC_INFO *info = link->priv;
 
-	link->state |= DEV_SUSPEND;
 	info->stop = 1;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 
 	return 0;
 }
 
-static int mgslpc_resume(struct pcmcia_device *dev)
+static int mgslpc_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	MGSLPC_INFO *info = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
 	info->stop = 0;
 
 	return 0;
@@ -1280,7 +1246,7 @@
 	if (!info)
 		return IRQ_NONE;
 		
-	if (!(info->link.state & DEV_CONFIG))
+	if (!(info->p_dev->_locked))
 		return IRQ_HANDLED;
 
 	spin_lock(&info->lock);
@@ -3033,7 +2999,7 @@
 	.drv		= {
 		.name	= "synclink_cs",
 	},
-	.probe		= mgslpc_attach,
+	.probe		= mgslpc_probe,
 	.remove		= mgslpc_detach,
 	.id_table	= mgslpc_ids,
 	.suspend	= mgslpc_suspend,
diff -urN oldtree/drivers/char/sonypi.c newtree/drivers/char/sonypi.c
--- oldtree/drivers/char/sonypi.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/sonypi.c	2006-04-01 05:35:32.010620500 -0500
@@ -512,7 +512,7 @@
 
 #ifdef CONFIG_ACPI
 static struct acpi_device *sonypi_acpi_device;
-static int acpi_enabled;
+static int acpi_driver_registered;
 #endif
 
 static int sonypi_ec_write(u8 addr, u8 value)
@@ -869,7 +869,7 @@
 		sonypi_report_input_event(event);
 
 #ifdef CONFIG_ACPI
-	if (acpi_enabled)
+	if (sonypi_acpi_device)
 		acpi_bus_generate_event(sonypi_acpi_device, 1, event);
 #endif
 
@@ -1548,8 +1548,8 @@
 		goto err_free_device;
 
 #ifdef CONFIG_ACPI
-	if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0)
-		acpi_enabled = 1;
+	if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
+		acpi_driver_registered = 1;
 #endif
 
 	return 0;
@@ -1564,7 +1564,7 @@
 static void __exit sonypi_exit(void)
 {
 #ifdef CONFIG_ACPI
-	if (acpi_enabled)
+	if (acpi_driver_registered)
 		acpi_bus_unregister_driver(&sonypi_acpi_driver);
 #endif
 	platform_device_unregister(sonypi_platform_device);
diff -urN oldtree/drivers/char/watchdog/Kconfig newtree/drivers/char/watchdog/Kconfig
--- oldtree/drivers/char/watchdog/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/watchdog/Kconfig	2006-04-01 05:35:46.303513750 -0500
@@ -60,6 +60,13 @@
 
 # ARM Architecture
 
+config AT91_WATCHDOG
+	tristate "AT91RM9200 watchdog"
+	depends on WATCHDOG && ARCH_AT91RM9200
+	help
+	  Watchdog timer embedded into AT91RM9200 chips. This will reboot your
+	  system when the timeout is reached.
+
 config 21285_WATCHDOG
 	tristate "DC21285 watchdog"
 	depends on WATCHDOG && FOOTBRIDGE
diff -urN oldtree/drivers/char/watchdog/Makefile newtree/drivers/char/watchdog/Makefile
--- oldtree/drivers/char/watchdog/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/watchdog/Makefile	2006-04-01 05:35:46.303513750 -0500
@@ -23,6 +23,7 @@
 obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 
 # ARM Architecture
+obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
diff -urN oldtree/drivers/char/watchdog/at91_wdt.c newtree/drivers/char/watchdog/at91_wdt.c
--- oldtree/drivers/char/watchdog/at91_wdt.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/char/watchdog/at91_wdt.c	2006-04-01 05:35:46.303513750 -0500
@@ -0,0 +1,228 @@
+/*
+ * Watchdog driver for Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) 2003 SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+
+#define WDT_DEFAULT_TIME	5	/* 5 seconds */
+#define WDT_MAX_TIME		256	/* 256 seconds */
+
+static int wdt_time = WDT_DEFAULT_TIME;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(wdt_time, int, 0);
+MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+
+static unsigned long at91wdt_busy;
+
+/* ......................................................................... */
+
+/*
+ * Disable the watchdog.
+ */
+static void inline at91_wdt_stop(void)
+{
+	at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
+}
+
+/*
+ * Enable and reset the watchdog.
+ */
+static void inline at91_wdt_start(void)
+{
+	at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
+	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+}
+
+/*
+ * Reload the watchdog timer.  (ie, pat the watchdog)
+ */
+static void inline at91_wdt_reload(void)
+{
+	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+}
+
+/* ......................................................................... */
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &at91wdt_busy))
+		return -EBUSY;
+
+	at91_wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
+ *  disabled.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+	if (!nowayout)
+		at91_wdt_stop();	/* Disable the watchdog when file is closed */
+
+	clear_bit(0, &at91wdt_busy);
+	return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at91_wdt_settimeout(int new_time)
+{
+	/*
+	 * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
+	 *
+	 * Since WDV is a 16-bit counter, the maximum period is
+	 * 65536 / 0.256 = 256 seconds.
+	 */
+	if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+		return -EINVAL;
+
+	/* Set new watchdog time. It will be used when at91_wdt_start() is called. */
+	wdt_time = new_time;
+	return 0;
+}
+
+static struct watchdog_info at91_wdt_info = {
+	.identity	= "at91 watchdog",
+	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static int at91_wdt_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_value;
+
+	switch(cmd) {
+		case WDIOC_KEEPALIVE:
+			at91_wdt_reload();	/* pat the watchdog */
+			return 0;
+
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_value, p))
+				return -EFAULT;
+				
+			if (at91_wdt_settimeout(new_value))
+				return -EINVAL;
+
+			/* Enable new time value */
+			at91_wdt_start();
+
+			/* Return current value */
+			return put_user(wdt_time, p);
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(wdt_time, p);
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_SETOPTIONS:
+			if (get_user(new_value, p))
+				return -EFAULT;
+
+			if (new_value & WDIOS_DISABLECARD)
+				at91_wdt_stop();
+			if (new_value & WDIOS_ENABLECARD)
+				at91_wdt_start();
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	at91_wdt_reload();		/* pat the watchdog */
+	return len;
+}
+
+/* ......................................................................... */
+
+static struct file_operations at91wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.ioctl		= at91_wdt_ioctl,
+	.open		= at91_wdt_open,
+	.release	= at91_wdt_close,
+	.write		= at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &at91wdt_fops,
+};
+
+static int __init at91_wdt_init(void)
+{
+	int res;
+
+	/* Check that the heartbeat value is within range; if not reset to the default */
+	if (at91_wdt_settimeout(wdt_time)) {
+		at91_wdt_settimeout(WDT_DEFAULT_TIME);
+		printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+	}
+
+	res = misc_register(&at91wdt_miscdev);
+	if (res)
+		return res;
+
+	printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
+	return 0;
+}
+
+static void __exit at91_wdt_exit(void)
+{
+	misc_deregister(&at91wdt_miscdev);
+}
+
+module_init(at91_wdt_init);
+module_exit(at91_wdt_exit);
+
+MODULE_AUTHOR("Andrew Victor");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -urN oldtree/drivers/char/watchdog/pcwd.c newtree/drivers/char/watchdog/pcwd.c
--- oldtree/drivers/char/watchdog/pcwd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/watchdog/pcwd.c	2006-04-01 05:35:46.303513750 -0500
@@ -66,15 +66,13 @@
 #include <linux/fs.h>		/* For file operations */
 #include <linux/ioport.h>	/* For io-port access */
 #include <linux/spinlock.h>	/* For spin_lock/spin_unlock/... */
-#include <linux/sched.h>	/* TASK_INTERRUPTIBLE, set_current_state() and friends */
-#include <linux/slab.h>		/* For kmalloc */
 
 #include <asm/uaccess.h>	/* For copy_to_user/put_user/... */
 #include <asm/io.h>		/* For inb/outb/... */
 
 /* Module and version information */
-#define WATCHDOG_VERSION "1.16"
-#define WATCHDOG_DATE "03 Jan 2006"
+#define WATCHDOG_VERSION "1.17"
+#define WATCHDOG_DATE "12 Feb 2006"
 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
 #define WATCHDOG_NAME "pcwd"
 #define PFX WATCHDOG_NAME ": "
@@ -96,15 +94,19 @@
  * PCI-PC Watchdog card.
 */
 /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */
-#define WD_WDRST                0x01	/* Previously reset state */
-#define WD_T110                 0x02	/* Temperature overheat sense */
-#define WD_HRTBT                0x04	/* Heartbeat sense */
-#define WD_RLY2                 0x08	/* External relay triggered */
-#define WD_SRLY2                0x80	/* Software external relay triggered */
+#define WD_WDRST		0x01	/* Previously reset state */
+#define WD_T110			0x02	/* Temperature overheat sense */
+#define WD_HRTBT		0x04	/* Heartbeat sense */
+#define WD_RLY2			0x08	/* External relay triggered */
+#define WD_SRLY2		0x80	/* Software external relay triggered */
 /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */
-#define WD_REVC_WTRP            0x01	/* Watchdog Trip status */
-#define WD_REVC_HRBT            0x02	/* Watchdog Heartbeat */
-#define WD_REVC_TTRP            0x04	/* Temperature Trip status */
+#define WD_REVC_WTRP		0x01	/* Watchdog Trip status */
+#define WD_REVC_HRBT		0x02	/* Watchdog Heartbeat */
+#define WD_REVC_TTRP		0x04	/* Temperature Trip status */
+#define WD_REVC_RL2A		0x08	/* Relay 2 activated by on-board processor */
+#define WD_REVC_RL1A		0x10	/* Relay 1 active */
+#define WD_REVC_R2DS		0x40	/* Relay 2 disable */
+#define WD_REVC_RLY2		0x80	/* Relay 2 activated? */
 /* Port 2 : Control Status #2 */
 #define WD_WDIS			0x10	/* Watchdog Disabled */
 #define WD_ENTP			0x20	/* Watchdog Enable Temperature Trip */
@@ -122,9 +124,14 @@
 #define CMD_ISA_VERSION_HUNDRETH	0x03
 #define CMD_ISA_VERSION_MINOR		0x04
 #define CMD_ISA_SWITCH_SETTINGS		0x05
+#define CMD_ISA_RESET_PC		0x06
+#define CMD_ISA_ARM_0			0x07
+#define CMD_ISA_ARM_30			0x08
+#define CMD_ISA_ARM_60			0x09
 #define CMD_ISA_DELAY_TIME_2SECS	0x0A
 #define CMD_ISA_DELAY_TIME_4SECS	0x0B
 #define CMD_ISA_DELAY_TIME_8SECS	0x0C
+#define CMD_ISA_RESET_RELAYS		0x0D
 
 /*
  * We are using an kernel timer to do the pinging of the watchdog
@@ -142,6 +149,7 @@
 static char expect_close;
 static int temp_panic;
 static struct {				/* this is private data for each ISA-PC watchdog card */
+	char fw_ver_str[6];		/* The cards firmware version */
 	int revision;			/* The card's revision */
 	int supports_temp;		/* Wether or not the card has a temperature device */
 	int command_mode;		/* Wether or not the card is in command mode */
@@ -153,6 +161,13 @@
 } pcwd_private;
 
 /* module parameters */
+#define QUIET	0	/* Default */
+#define VERBOSE	1	/* Verbose */
+#define DEBUG	2	/* print fancy stuff too */
+static int debug = QUIET;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
+
 #define WATCHDOG_HEARTBEAT 60		/* 60 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;
 module_param(heartbeat, int, 0);
@@ -172,6 +187,10 @@
 	int control_status;
 	int port0, last_port0;	/* Double read for stabilising */
 
+	if (debug >= DEBUG)
+		printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
+			cmd);
+
 	/* The WCMD bit must be 1 and the command is only 4 bits in size */
 	control_status = (cmd & 0x0F) | WD_WCMD;
 	outb_p(control_status, pcwd_private.io_addr + 2);
@@ -188,6 +207,10 @@
 		udelay (250);
 	}
 
+	if (debug >= DEBUG)
+		printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
+			cmd, port0, last_port0);
+
 	return port0;
 }
 
@@ -214,6 +237,10 @@
 	spin_unlock(&pcwd_private.io_lock);
 	pcwd_private.command_mode = found;
 
+	if (debug >= DEBUG)
+		printk(KERN_DEBUG PFX "command_mode=%d\n",
+				pcwd_private.command_mode);
+
 	return(found);
 }
 
@@ -226,6 +253,10 @@
 	spin_unlock(&pcwd_private.io_lock);
 
 	pcwd_private.command_mode = 0;
+
+	if (debug >= DEBUG)
+		printk(KERN_DEBUG PFX "command_mode=%d\n",
+				pcwd_private.command_mode);
 }
 
 static inline void pcwd_check_temperature_support(void)
@@ -234,27 +265,22 @@
 		pcwd_private.supports_temp = 1;
 }
 
-static inline char *get_firmware(void)
+static inline void pcwd_get_firmware(void)
 {
 	int one, ten, hund, minor;
-	char *ret;
 
-	ret = kmalloc(6, GFP_KERNEL);
-	if(ret == NULL)
-		return NULL;
+	strcpy(pcwd_private.fw_ver_str, "ERROR");
 
 	if (set_command_mode()) {
 		one = send_isa_command(CMD_ISA_VERSION_INTEGER);
 		ten = send_isa_command(CMD_ISA_VERSION_TENTH);
 		hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
 		minor = send_isa_command(CMD_ISA_VERSION_MINOR);
-		sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
+		sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor);
 	}
-	else
-		sprintf(ret, "ERROR");
-
 	unset_command_mode();
-	return(ret);
+
+	return;
 }
 
 static inline int pcwd_get_option_switches(void)
@@ -272,17 +298,15 @@
 
 static void pcwd_show_card_info(void)
 {
-	char *firmware;
 	int option_switches;
 
 	/* Get some extra info from the hardware (in command/debug/diag mode) */
 	if (pcwd_private.revision == PCWD_REVISION_A)
 		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr);
 	else if (pcwd_private.revision == PCWD_REVISION_C) {
-		firmware = get_firmware();
+		pcwd_get_firmware();
 		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
-			pcwd_private.io_addr, firmware);
-		kfree(firmware);
+			pcwd_private.io_addr, pcwd_private.fw_ver_str);
 		option_switches = pcwd_get_option_switches();
 		printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
 			option_switches,
@@ -362,6 +386,10 @@
 			return -EIO;
 		}
 	}
+
+	if (debug >= VERBOSE)
+		printk(KERN_DEBUG PFX "Watchdog started\n");
+
 	return 0;
 }
 
@@ -386,6 +414,10 @@
 			return -EIO;
 		}
 	}
+
+	if (debug >= VERBOSE)
+		printk(KERN_DEBUG PFX "Watchdog stopped\n");
+
 	return 0;
 }
 
@@ -393,6 +425,10 @@
 {
 	/* user land ping */
 	pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
+
+	if (debug >= DEBUG)
+		printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+
 	return 0;
 }
 
@@ -402,12 +438,17 @@
 		return -EINVAL;
 
 	heartbeat = t;
+
+	if (debug >= VERBOSE)
+		printk(KERN_DEBUG PFX "New heartbeat: %d\n",
+		       heartbeat);
+
 	return 0;
 }
 
 static int pcwd_get_status(int *status)
 {
-	int card_status;
+	int control_status;
 
 	*status=0;
 	spin_lock(&pcwd_private.io_lock);
@@ -415,37 +456,39 @@
 		/* Rev A cards return status information from
 		 * the base register, which is used for the
 		 * temperature in other cards. */
-		card_status = inb(pcwd_private.io_addr);
+		control_status = inb(pcwd_private.io_addr);
 	else {
 		/* Rev C cards return card status in the base
 		 * address + 1 register. And use different bits
 		 * to indicate a card initiated reset, and an
 		 * over-temperature condition. And the reboot
 		 * status can be reset. */
-		card_status = inb(pcwd_private.io_addr + 1);
+		control_status = inb(pcwd_private.io_addr + 1);
 	}
 	spin_unlock(&pcwd_private.io_lock);
 
 	if (pcwd_private.revision == PCWD_REVISION_A) {
-		if (card_status & WD_WDRST)
+		if (control_status & WD_WDRST)
 			*status |= WDIOF_CARDRESET;
 
-		if (card_status & WD_T110) {
+		if (control_status & WD_T110) {
 			*status |= WDIOF_OVERHEAT;
 			if (temp_panic) {
 				printk (KERN_INFO PFX "Temperature overheat trip!\n");
 				kernel_power_off();
+				/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
 			}
 		}
 	} else {
-		if (card_status & WD_REVC_WTRP)
+		if (control_status & WD_REVC_WTRP)
 			*status |= WDIOF_CARDRESET;
 
-		if (card_status & WD_REVC_TTRP) {
+		if (control_status & WD_REVC_TTRP) {
 			*status |= WDIOF_OVERHEAT;
 			if (temp_panic) {
 				printk (KERN_INFO PFX "Temperature overheat trip!\n");
 				kernel_power_off();
+				/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
 			}
 		}
 	}
@@ -455,9 +498,25 @@
 
 static int pcwd_clear_status(void)
 {
+	int control_status;
+
 	if (pcwd_private.revision == PCWD_REVISION_C) {
 		spin_lock(&pcwd_private.io_lock);
-		outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */
+
+		if (debug >= VERBOSE)
+			printk(KERN_INFO PFX "clearing watchdog trip status\n");
+
+		control_status = inb_p(pcwd_private.io_addr + 1);
+
+		if (debug >= DEBUG) {
+			printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
+			printk(KERN_DEBUG PFX "sending: 0x%02x\n",
+				(control_status & WD_REVC_R2DS));
+		}
+
+		/* clear reset status & Keep Relay 2 disable state as it is */
+		outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1);
+
 		spin_unlock(&pcwd_private.io_lock);
 	}
 	return 0;
@@ -481,6 +540,11 @@
 	*temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;
 	spin_unlock(&pcwd_private.io_lock);
 
+	if (debug >= DEBUG) {
+		printk(KERN_DEBUG PFX "temperature is: %d F\n",
+			*temperature);
+	}
+
 	return 0;
 }
 
@@ -599,6 +663,8 @@
 static int pcwd_open(struct inode *inode, struct file *file)
 {
 	if (!atomic_dec_and_test(&open_allowed) ) {
+		if (debug >= VERBOSE)
+			printk(KERN_ERR PFX "Attempt to open already opened device.\n");
 		atomic_inc( &open_allowed );
 		return -EBUSY;
 	}
@@ -922,7 +988,8 @@
 {
 	if (pcwd_private.io_addr)
 		pcwatchdog_exit();
-	return;
+
+	printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
 }
 
 module_init(pcwd_init_module);
diff -urN oldtree/drivers/char/watchdog/pcwd_usb.c newtree/drivers/char/watchdog/pcwd_usb.c
--- oldtree/drivers/char/watchdog/pcwd_usb.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/char/watchdog/pcwd_usb.c	2006-04-01 05:35:46.303513750 -0500
@@ -704,7 +704,8 @@
 err_out_unregister_reboot:
 	unregister_reboot_notifier(&usb_pcwd_notifier);
 error:
-	usb_pcwd_delete (usb_pcwd);
+	if (usb_pcwd)
+		usb_pcwd_delete(usb_pcwd);
 	usb_pcwd_device = NULL;
 	return retval;
 }
diff -urN oldtree/drivers/dlm/Kconfig newtree/drivers/dlm/Kconfig
--- oldtree/drivers/dlm/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/Kconfig	2006-04-01 05:36:01.024433750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/Makefile	2006-04-01 05:36:01.044435000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/ast.c	2006-04-01 05:36:01.380456000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/ast.h	2006-04-01 05:35:59.168317750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/config.c	2006-04-01 05:36:01.384456250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/config.h	2006-04-01 05:36:01.012433000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/debug_fs.c	2006-04-01 05:36:00.928427750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/device.c	2006-04-01 05:36:01.384456250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/dir.c	2006-04-01 05:36:01.364455000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/dir.h	2006-04-01 05:36:00.948429000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/dlm_internal.h	2006-04-01 05:36:01.384456250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lock.c	2006-04-01 05:36:01.384456250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lock.h	2006-04-01 05:36:01.384456250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lockspace.c	2006-04-01 05:36:01.388456500 -0500
@@ -0,0 +1,666 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  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);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lockspace.h	2006-04-01 05:36:01.348454000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lowcomms.c	2006-04-01 05:36:01.016433250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lowcomms.h	2006-04-01 05:36:01.016433250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/lvb_table.h	2006-04-01 05:35:59.172318000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/main.c	2006-04-01 05:36:01.044435000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/member.c	2006-04-01 05:36:01.044435000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/member.h	2006-04-01 05:36:00.908426500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/memory.c	2006-04-01 05:36:01.364455000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/memory.h	2006-04-01 05:35:59.172318000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/midcomms.c	2006-04-01 05:36:01.364455000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/midcomms.h	2006-04-01 05:35:59.556342000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/rcom.c	2006-04-01 05:36:00.988431500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/rcom.h	2006-04-01 05:35:59.576343250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/recover.c	2006-04-01 05:36:01.364455000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/recover.h	2006-04-01 05:36:00.912426750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/recoverd.c	2006-04-01 05:36:01.388456500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/recoverd.h	2006-04-01 05:35:59.576343250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/requestqueue.c	2006-04-01 05:36:01.388456500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/requestqueue.h	2006-04-01 05:35:59.580343500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/util.c	2006-04-01 05:36:01.364455000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/dlm/util.h	2006-04-01 05:36:01.064436250 -0500
@@ -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/ide/legacy/ide-cs.c newtree/drivers/ide/legacy/ide-cs.c
--- oldtree/drivers/ide/legacy/ide-cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/ide/legacy/ide-cs.c	2006-04-01 05:35:44.247385250 -0500
@@ -81,14 +81,14 @@
 };
 
 typedef struct ide_info_t {
-    dev_link_t	link;
+	struct pcmcia_device	*p_dev;
     int		ndev;
     dev_node_t	node;
     int		hd;
 } ide_info_t;
 
-static void ide_release(dev_link_t *);
-static void ide_config(dev_link_t *);
+static void ide_release(struct pcmcia_device *);
+static int ide_config(struct pcmcia_device *);
 
 static void ide_detach(struct pcmcia_device *p_dev);
 
@@ -103,10 +103,9 @@
 
 ======================================================================*/
 
-static int ide_attach(struct pcmcia_device *p_dev)
+static int ide_probe(struct pcmcia_device *link)
 {
     ide_info_t *info;
-    dev_link_t *link;
 
     DEBUG(0, "ide_attach()\n");
 
@@ -114,7 +113,9 @@
     info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info)
 	return -ENOMEM;
-    link = &info->link; link->priv = info;
+
+    info->p_dev = link;
+    link->priv = info;
 
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
@@ -122,16 +123,9 @@
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    ide_config(link);
-
-    return 0;
+    return ide_config(link);
 } /* ide_attach */
 
 /*======================================================================
@@ -143,14 +137,11 @@
 
 ======================================================================*/
 
-static void ide_detach(struct pcmcia_device *p_dev)
+static void ide_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
     DEBUG(0, "ide_detach(0x%p)\n", link);
 
-    if (link->state & DEV_CONFIG)
-	ide_release(link);
+    ide_release(link);
 
     kfree(link->priv);
 } /* ide_detach */
@@ -177,9 +168,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void ide_config(dev_link_t *link)
+static int ide_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     ide_info_t *info = link->priv;
     tuple_t tuple;
     struct {
@@ -203,34 +193,30 @@
     tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &stk->parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &stk->parse));
     link->conf.ConfigBase = stk->parse.config.base;
     link->conf.Present = stk->parse.config.rmask[0];
 
     tuple.DesiredTuple = CISTPL_MANFID;
-    if (!pcmcia_get_first_tuple(handle, &tuple) &&
-	!pcmcia_get_tuple_data(handle, &tuple) &&
-	!pcmcia_parse_tuple(handle, &tuple, &stk->parse))
+    if (!pcmcia_get_first_tuple(link, &tuple) &&
+	!pcmcia_get_tuple_data(link, &tuple) &&
+	!pcmcia_parse_tuple(link, &tuple, &stk->parse))
 	is_kme = ((stk->parse.manfid.manf == MANFID_KME) &&
 		  ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) ||
 		   (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &stk->conf));
-    link->conf.Vcc = stk->conf.Vcc;
+    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
 
     pass = io_base = ctl_base = 0;
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
     tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (1) {
-    	if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry;
-	if (pcmcia_parse_tuple(handle, &tuple, &stk->parse) != 0) goto next_entry;
+    	if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry;
+	if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry;
 
 	/* Check for matching Vcc, unless we're desperate */
 	if (!pass) {
@@ -244,10 +230,10 @@
 	}
 
 	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
+	    link->conf.Vpp =
 		cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 	else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
+	    link->conf.Vpp =
 		stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 
 	if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
@@ -261,14 +247,14 @@
 		link->io.NumPorts1 = 8;
 		link->io.BasePort2 = io->win[1].base;
 		link->io.NumPorts2 = (is_kme) ? 2 : 1;
-		if (pcmcia_request_io(link->handle, &link->io) != 0)
+		if (pcmcia_request_io(link, &link->io) != 0)
 			goto next_entry;
 		io_base = link->io.BasePort1;
 		ctl_base = link->io.BasePort2;
 	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
 		link->io.NumPorts1 = io->win[0].len;
 		link->io.NumPorts2 = 0;
-		if (pcmcia_request_io(link->handle, &link->io) != 0)
+		if (pcmcia_request_io(link, &link->io) != 0)
 			goto next_entry;
 		io_base = link->io.BasePort1;
 		ctl_base = link->io.BasePort1 + 0x0e;
@@ -281,16 +267,16 @@
 	if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 	    memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
 	if (pass) {
-	    CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
-	} else if (pcmcia_get_next_tuple(handle, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	    CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+	} else if (pcmcia_get_next_tuple(link, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	    memset(&stk->dflt, 0, sizeof(stk->dflt));
 	    pass++;
 	}
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     /* disable drive interrupts during IDE probe */
     outb(0x02, ctl_base);
@@ -301,12 +287,12 @@
 
     /* retry registration in case device is still spinning up */
     for (hd = -1, i = 0; i < 10; i++) {
-	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, handle);
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
 	    outb(0x02, ctl_base + 0x10);
 	    hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
-				link->irq.AssignedIRQ, handle);
+				link->irq.AssignedIRQ, link);
 	    if (hd >= 0) {
 		io_base += 0x10;
 		ctl_base += 0x10;
@@ -328,25 +314,23 @@
     info->node.major = ide_major[hd];
     info->node.minor = 0;
     info->hd = hd;
-    link->dev = &info->node;
-    printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	   info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10,
-	   link->conf.Vpp1 / 10, link->conf.Vpp1 % 10);
+    link->dev_node = &info->node;
+    printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10);
 
-    link->state &= ~DEV_CONFIG_PENDING;
     kfree(stk);
-    return;
+    return 0;
 
 err_mem:
     printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
     goto failed;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     kfree(stk);
     ide_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
+    return -ENODEV;
 } /* ide_config */
 
 /*======================================================================
@@ -357,7 +341,7 @@
     
 ======================================================================*/
 
-void ide_release(dev_link_t *link)
+void ide_release(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
     
@@ -369,37 +353,10 @@
 	ide_unregister(info->hd);
     }
     info->ndev = 0;
-    link->dev = NULL;
-    
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
 
+    pcmcia_disable_device(link);
 } /* ide_release */
 
-static int ide_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int ide_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
-}
 
 /*======================================================================
 
@@ -459,11 +416,9 @@
 	.drv		= {
 		.name	= "ide-cs",
 	},
-	.probe		= ide_attach,
+	.probe		= ide_probe,
 	.remove		= ide_detach,
 	.id_table       = ide_ids,
-	.suspend	= ide_suspend,
-	.resume		= ide_resume,
 };
 
 static int __init init_ide_cs(void)
diff -urN oldtree/drivers/ieee1394/Kconfig newtree/drivers/ieee1394/Kconfig
--- oldtree/drivers/ieee1394/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/ieee1394/Kconfig	2006-04-01 05:36:15.329327750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/ieee1394/hosts.c	2006-04-01 05:35:38.074999500 -0500
@@ -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/input/evbug.c newtree/drivers/input/evbug.c
--- oldtree/drivers/input/evbug.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/evbug.c	2006-04-01 05:35:38.119002250 -0500
@@ -49,9 +49,8 @@
 {
 	struct input_handle *handle;
 
-	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
 		return NULL;
-	memset(handle, 0, sizeof(struct input_handle));
 
 	handle->dev = dev;
 	handle->handler = handler;
diff -urN oldtree/drivers/input/evdev.c newtree/drivers/input/evdev.c
--- oldtree/drivers/input/evdev.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/evdev.c	2006-04-01 05:35:38.119002250 -0500
@@ -130,9 +130,8 @@
 	if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
 		return accept_err;
 
-	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct evdev_list));
 
 	list->evdev = evdev_table[i];
 	list_add_tail(&list->node, &evdev_table[i]->list);
@@ -609,9 +608,8 @@
 		return NULL;
 	}
 
-	if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+	if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
 		return NULL;
-	memset(evdev, 0, sizeof(struct evdev));
 
 	INIT_LIST_HEAD(&evdev->list);
 	init_waitqueue_head(&evdev->wait);
diff -urN oldtree/drivers/input/gameport/gameport.c newtree/drivers/input/gameport/gameport.c
--- oldtree/drivers/input/gameport/gameport.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/gameport/gameport.c	2006-04-01 05:35:38.119002250 -0500
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/sched.h>	/* HZ */
+#include <linux/mutex.h>
 
 /*#include <asm/io.h>*/
 
@@ -43,10 +44,10 @@
 EXPORT_SYMBOL(gameport_stop_polling);
 
 /*
- * gameport_sem protects entire gameport subsystem and is taken
+ * gameport_mutex protects entire gameport subsystem and is taken
  * every time gameport port or driver registrered or unregistered.
  */
-static DECLARE_MUTEX(gameport_sem);
+static DEFINE_MUTEX(gameport_mutex);
 
 static LIST_HEAD(gameport_list);
 
@@ -265,6 +266,7 @@
 	if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
 		if (!try_module_get(owner)) {
 			printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
+			kfree(event);
 			goto out;
 		}
 
@@ -342,7 +344,7 @@
 	struct gameport_event *event;
 	struct gameport_driver *gameport_drv;
 
-	down(&gameport_sem);
+	mutex_lock(&gameport_mutex);
 
 	/*
 	 * Note that we handle only one event here to give swsusp
@@ -379,7 +381,7 @@
 		gameport_free_event(event);
 	}
 
-	up(&gameport_sem);
+	mutex_unlock(&gameport_mutex);
 }
 
 /*
@@ -464,7 +466,7 @@
 	struct device_driver *drv;
 	int retval;
 
-	retval = down_interruptible(&gameport_sem);
+	retval = mutex_lock_interruptible(&gameport_mutex);
 	if (retval)
 		return retval;
 
@@ -484,7 +486,7 @@
 		retval = -EINVAL;
 	}
 
-	up(&gameport_sem);
+	mutex_unlock(&gameport_mutex);
 
 	return retval;
 }
@@ -521,7 +523,7 @@
 
 	__module_get(THIS_MODULE);
 
-	init_MUTEX(&gameport->drv_sem);
+	mutex_init(&gameport->drv_mutex);
 	device_initialize(&gameport->dev);
 	snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
 		 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
@@ -661,10 +663,10 @@
  */
 void gameport_unregister_port(struct gameport *gameport)
 {
-	down(&gameport_sem);
+	mutex_lock(&gameport_mutex);
 	gameport_disconnect_port(gameport);
 	gameport_destroy_port(gameport);
-	up(&gameport_sem);
+	mutex_unlock(&gameport_mutex);
 }
 
 
@@ -717,7 +719,7 @@
 {
 	struct gameport *gameport;
 
-	down(&gameport_sem);
+	mutex_lock(&gameport_mutex);
 	drv->ignore = 1;	/* so gameport_find_driver ignores it */
 
 start_over:
@@ -731,7 +733,7 @@
 	}
 
 	driver_unregister(&drv->driver);
-	up(&gameport_sem);
+	mutex_unlock(&gameport_mutex);
 }
 
 static int gameport_bus_match(struct device *dev, struct device_driver *drv)
@@ -743,9 +745,9 @@
 
 static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
 {
-	down(&gameport->drv_sem);
+	mutex_lock(&gameport->drv_mutex);
 	gameport->drv = drv;
-	up(&gameport->drv_sem);
+	mutex_unlock(&gameport->drv_mutex);
 }
 
 int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
@@ -796,5 +798,5 @@
 	kthread_stop(gameport_task);
 }
 
-module_init(gameport_init);
+subsys_initcall(gameport_init);
 module_exit(gameport_exit);
diff -urN oldtree/drivers/input/gameport/ns558.c newtree/drivers/input/gameport/ns558.c
--- oldtree/drivers/input/gameport/ns558.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/gameport/ns558.c	2006-04-01 05:35:38.123002500 -0500
@@ -252,14 +252,14 @@
 
 #endif
 
-static int pnp_registered = 0;
-
 static int __init ns558_init(void)
 {
 	int i = 0;
+	int error;
 
-	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
-		pnp_registered = 1;
+	error = pnp_register_driver(&ns558_pnp_driver);
+	if (error && error != -ENODEV)	/* should be ENOSYS really */
+		return error;
 
 /*
  * Probe ISA ports after PnP, so that PnP ports that are already
@@ -270,7 +270,7 @@
 	while (ns558_isa_portlist[i])
 		ns558_isa_probe(ns558_isa_portlist[i++]);
 
-	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
+	return list_empty(&ns558_list) && error ? -ENODEV : 0;
 }
 
 static void __exit ns558_exit(void)
@@ -283,8 +283,7 @@
 		kfree(ns558);
 	}
 
-	if (pnp_registered)
-		pnp_unregister_driver(&ns558_pnp_driver);
+	pnp_unregister_driver(&ns558_pnp_driver);
 }
 
 module_init(ns558_init);
diff -urN oldtree/drivers/input/input.c newtree/drivers/input/input.c
--- oldtree/drivers/input/input.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/input.c	2006-04-01 05:35:38.123002500 -0500
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input core");
@@ -224,7 +225,7 @@
 	struct input_dev *dev = handle->dev;
 	int err;
 
-	err = down_interruptible(&dev->sem);
+	err = mutex_lock_interruptible(&dev->mutex);
 	if (err)
 		return err;
 
@@ -236,7 +237,7 @@
 	if (err)
 		handle->open--;
 
-	up(&dev->sem);
+	mutex_unlock(&dev->mutex);
 
 	return err;
 }
@@ -255,13 +256,13 @@
 
 	input_release_device(handle);
 
-	down(&dev->sem);
+	mutex_lock(&dev->mutex);
 
 	if (!--dev->users && dev->close)
 		dev->close(dev);
 	handle->open--;
 
-	up(&dev->sem);
+	mutex_unlock(&dev->mutex);
 }
 
 static void input_link_handle(struct input_handle *handle)
@@ -512,13 +513,13 @@
 	struct input_dev *input_dev = to_input_dev(dev);			\
 	int retval;								\
 										\
-	retval = down_interruptible(&input_dev->sem);				\
+	retval = mutex_lock_interruptible(&input_dev->mutex);			\
 	if (retval)								\
 		return retval;							\
 										\
 	retval = sprintf(buf, "%s\n", input_dev->name ? input_dev->name : "");	\
 										\
-	up(&input_dev->sem);							\
+	mutex_unlock(&input_dev->mutex);					\
 										\
 	return retval;								\
 }										\
@@ -790,7 +791,7 @@
 		return -EINVAL;
 	}
 
-	init_MUTEX(&dev->sem);
+	mutex_init(&dev->mutex);
 	set_bit(EV_SYN, dev->evbit);
 
 	/*
diff -urN oldtree/drivers/input/joydev.c newtree/drivers/input/joydev.c
--- oldtree/drivers/input/joydev.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joydev.c	2006-04-01 05:35:38.123002500 -0500
@@ -171,9 +171,8 @@
 	if (i >= JOYDEV_MINORS || !joydev_table[i])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct joydev_list));
 
 	list->joydev = joydev_table[i];
 	list_add_tail(&list->node, &joydev_table[i]->list);
@@ -457,9 +456,8 @@
 		return NULL;
 	}
 
-	if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
+	if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
 		return NULL;
-	memset(joydev, 0, sizeof(struct joydev));
 
 	INIT_LIST_HEAD(&joydev->list);
 	init_waitqueue_head(&joydev->wait);
diff -urN oldtree/drivers/input/joystick/amijoy.c newtree/drivers/input/joystick/amijoy.c
--- oldtree/drivers/input/joystick/amijoy.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/amijoy.c	2006-04-01 05:35:38.123002500 -0500
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 
 #include <asm/system.h>
 #include <asm/amigahw.h>
@@ -52,7 +53,7 @@
 __obsolete_setup("amijoy=");
 
 static int amijoy_used;
-static DECLARE_MUTEX(amijoy_sem);
+static DEFINE_MUTEX(amijoy_mutex);
 static struct input_dev *amijoy_dev[2];
 static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 
@@ -85,7 +86,7 @@
 {
 	int err;
 
-	err = down_interruptible(&amijoy_sem);
+	err = mutex_lock_interruptible(&amijoy_mutex);
 	if (err)
 		return err;
 
@@ -97,16 +98,16 @@
 
 	amijoy_used++;
 out:
-	up(&amijoy_sem);
+	mutex_unlock(&amijoy_mutex);
 	return err;
 }
 
 static void amijoy_close(struct input_dev *dev)
 {
-	down(&amijoy_sem);
+	mutex_lock(&amijoy_mutex);
 	if (!--amijoy_used)
 		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
-	up(&amijoy_sem);
+	mutex_unlock(&amijoy_mutex);
 }
 
 static int __init amijoy_init(void)
diff -urN oldtree/drivers/input/joystick/db9.c newtree/drivers/input/joystick/db9.c
--- oldtree/drivers/input/joystick/db9.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/db9.c	2006-04-01 05:35:38.123002500 -0500
@@ -38,6 +38,7 @@
 #include <linux/init.h>
 #include <linux/parport.h>
 #include <linux/input.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
@@ -111,7 +112,7 @@
 	struct pardevice *pd;
 	int mode;
 	int used;
-	struct semaphore sem;
+	struct mutex mutex;
 	char phys[DB9_MAX_DEVICES][32];
 };
 
@@ -525,7 +526,7 @@
 	struct parport *port = db9->pd->port;
 	int err;
 
-	err = down_interruptible(&db9->sem);
+	err = mutex_lock_interruptible(&db9->mutex);
 	if (err)
 		return err;
 
@@ -539,7 +540,7 @@
 		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
 	}
 
-	up(&db9->sem);
+	mutex_unlock(&db9->mutex);
 	return 0;
 }
 
@@ -548,14 +549,14 @@
 	struct db9 *db9 = dev->private;
 	struct parport *port = db9->pd->port;
 
-	down(&db9->sem);
+	mutex_lock(&db9->mutex);
 	if (!--db9->used) {
 		del_timer_sync(&db9->timer);
 		parport_write_control(port, 0x00);
 		parport_data_forward(port);
 		parport_release(db9->pd);
 	}
-	up(&db9->sem);
+	mutex_unlock(&db9->mutex);
 }
 
 static struct db9 __init *db9_probe(int parport, int mode)
@@ -603,7 +604,7 @@
 		goto err_unreg_pardev;
 	}
 
-	init_MUTEX(&db9->sem);
+	mutex_init(&db9->mutex);
 	db9->pd = pd;
 	db9->mode = mode;
 	init_timer(&db9->timer);
diff -urN oldtree/drivers/input/joystick/gamecon.c newtree/drivers/input/joystick/gamecon.c
--- oldtree/drivers/input/joystick/gamecon.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/gamecon.c	2006-04-01 05:35:38.123002500 -0500
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/parport.h>
 #include <linux/input.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
@@ -83,7 +84,7 @@
 	struct timer_list timer;
 	unsigned char pads[GC_MAX + 1];
 	int used;
-	struct semaphore sem;
+	struct mutex mutex;
 	char phys[GC_MAX_DEVICES][32];
 };
 
@@ -552,7 +553,7 @@
 	struct gc *gc = dev->private;
 	int err;
 
-	err = down_interruptible(&gc->sem);
+	err = mutex_lock_interruptible(&gc->mutex);
 	if (err)
 		return err;
 
@@ -562,7 +563,7 @@
 		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
 	}
 
-	up(&gc->sem);
+	mutex_unlock(&gc->mutex);
 	return 0;
 }
 
@@ -570,13 +571,13 @@
 {
 	struct gc *gc = dev->private;
 
-	down(&gc->sem);
+	mutex_lock(&gc->mutex);
 	if (!--gc->used) {
 		del_timer_sync(&gc->timer);
 		parport_write_control(gc->pd->port, 0x00);
 		parport_release(gc->pd);
 	}
-	up(&gc->sem);
+	mutex_unlock(&gc->mutex);
 }
 
 static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
@@ -693,7 +694,7 @@
 		goto err_unreg_pardev;
 	}
 
-	init_MUTEX(&gc->sem);
+	mutex_init(&gc->mutex);
 	gc->pd = pd;
 	init_timer(&gc->timer);
 	gc->timer.data = (long) gc;
diff -urN oldtree/drivers/input/joystick/iforce/iforce-ff.c newtree/drivers/input/joystick/iforce/iforce-ff.c
--- oldtree/drivers/input/joystick/iforce/iforce-ff.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/iforce/iforce-ff.c	2006-04-01 05:35:38.123002500 -0500
@@ -42,14 +42,14 @@
 	unsigned char data[3];
 
 	if (!no_alloc) {
-		down(&iforce->mem_mutex);
+		mutex_lock(&iforce->mem_mutex);
 		if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
-			up(&iforce->mem_mutex);
+			mutex_unlock(&iforce->mem_mutex);
 			return -ENOMEM;
 		}
-		up(&iforce->mem_mutex);
+		mutex_unlock(&iforce->mem_mutex);
 	}
 
 	data[0] = LO(mod_chunk->start);
@@ -75,14 +75,14 @@
 	period = TIME_SCALE(period);
 
 	if (!no_alloc) {
-		down(&iforce->mem_mutex);
+		mutex_lock(&iforce->mem_mutex);
 		if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
-			up(&iforce->mem_mutex);
+			mutex_unlock(&iforce->mem_mutex);
 			return -ENOMEM;
 		}
-		up(&iforce->mem_mutex);
+		mutex_unlock(&iforce->mem_mutex);
 	}
 
 	data[0] = LO(mod_chunk->start);
@@ -115,14 +115,14 @@
 	fade_duration = TIME_SCALE(fade_duration);
 
 	if (!no_alloc) {
-		down(&iforce->mem_mutex);
+		mutex_lock(&iforce->mem_mutex);
 		if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
-			up(&iforce->mem_mutex);
+			mutex_unlock(&iforce->mem_mutex);
 			return -ENOMEM;
 		}
-		up(&iforce->mem_mutex);
+		mutex_unlock(&iforce->mem_mutex);
 	}
 
 	data[0] = LO(mod_chunk->start);
@@ -152,14 +152,14 @@
 	unsigned char data[10];
 
 	if (!no_alloc) {
-		down(&iforce->mem_mutex);
+		mutex_lock(&iforce->mem_mutex);
 		if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
 			iforce->device_memory.start, iforce->device_memory.end, 2L,
 			NULL, NULL)) {
-			up(&iforce->mem_mutex);
+			mutex_unlock(&iforce->mem_mutex);
 			return -ENOMEM;
 		}
-		up(&iforce->mem_mutex);
+		mutex_unlock(&iforce->mem_mutex);
 	}
 
 	data[0] = LO(mod_chunk->start);
diff -urN oldtree/drivers/input/joystick/iforce/iforce-main.c newtree/drivers/input/joystick/iforce/iforce-main.c
--- oldtree/drivers/input/joystick/iforce/iforce-main.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/iforce/iforce-main.c	2006-04-01 05:35:38.127002750 -0500
@@ -350,7 +350,7 @@
 
 	init_waitqueue_head(&iforce->wait);
 	spin_lock_init(&iforce->xmit_lock);
-	init_MUTEX(&iforce->mem_mutex);
+	mutex_init(&iforce->mem_mutex);
 	iforce->xmit.buf = iforce->xmit_data;
 	iforce->dev = input_dev;
 
diff -urN oldtree/drivers/input/joystick/iforce/iforce.h newtree/drivers/input/joystick/iforce/iforce.h
--- oldtree/drivers/input/joystick/iforce/iforce.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/iforce/iforce.h	2006-04-01 05:35:38.127002750 -0500
@@ -37,7 +37,7 @@
 #include <linux/serio.h>
 #include <linux/config.h>
 #include <linux/circ_buf.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 /* This module provides arbitrary resource management routines.
  * I use it to manage the device's memory.
@@ -45,6 +45,7 @@
  */
 #include <linux/ioport.h>
 
+
 #define IFORCE_MAX_LENGTH	16
 
 /* iforce::bus */
@@ -146,7 +147,7 @@
 	wait_queue_head_t wait;
 	struct resource device_memory;
 	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
-	struct semaphore mem_mutex;
+	struct mutex mem_mutex;
 };
 
 /* Get hi and low bytes of a 16-bits int */
diff -urN oldtree/drivers/input/joystick/turbografx.c newtree/drivers/input/joystick/turbografx.c
--- oldtree/drivers/input/joystick/turbografx.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/joystick/turbografx.c	2006-04-01 05:35:38.127002750 -0500
@@ -37,6 +37,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("TurboGraFX parallel port interface driver");
@@ -86,7 +87,7 @@
 	char phys[TGFX_MAX_DEVICES][32];
 	int sticks;
 	int used;
-	struct semaphore sem;
+	struct mutex sem;
 } *tgfx_base[TGFX_MAX_PORTS];
 
 /*
@@ -128,7 +129,7 @@
 	struct tgfx *tgfx = dev->private;
 	int err;
 
-	err = down_interruptible(&tgfx->sem);
+	err = mutex_lock_interruptible(&tgfx->sem);
 	if (err)
 		return err;
 
@@ -138,7 +139,7 @@
 		mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 	}
 
-	up(&tgfx->sem);
+	mutex_unlock(&tgfx->sem);
 	return 0;
 }
 
@@ -146,13 +147,13 @@
 {
 	struct tgfx *tgfx = dev->private;
 
-	down(&tgfx->sem);
+	mutex_lock(&tgfx->sem);
 	if (!--tgfx->used) {
 		del_timer_sync(&tgfx->timer);
 		parport_write_control(tgfx->pd->port, 0x00);
 		parport_release(tgfx->pd);
 	}
-	up(&tgfx->sem);
+	mutex_unlock(&tgfx->sem);
 }
 
 
@@ -191,7 +192,7 @@
 		goto err_unreg_pardev;
 	}
 
-	init_MUTEX(&tgfx->sem);
+	mutex_init(&tgfx->sem);
 	tgfx->pd = pd;
 	init_timer(&tgfx->timer);
 	tgfx->timer.data = (long) tgfx;
diff -urN oldtree/drivers/input/keyboard/Kconfig newtree/drivers/input/keyboard/Kconfig
--- oldtree/drivers/input/keyboard/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/keyboard/Kconfig	2006-04-01 05:35:38.127002750 -0500
@@ -13,7 +13,7 @@
 if INPUT_KEYBOARD
 
 config KEYBOARD_ATKBD
-	tristate "AT keyboard" if !X86_PC
+	tristate "AT keyboard" if EMBEDDED || !X86_PC
 	default y
 	select SERIO
 	select SERIO_LIBPS2
diff -urN oldtree/drivers/input/keyboard/atkbd.c newtree/drivers/input/keyboard/atkbd.c
--- oldtree/drivers/input/keyboard/atkbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/keyboard/atkbd.c	2006-04-01 05:35:38.127002750 -0500
@@ -27,6 +27,7 @@
 #include <linux/serio.h>
 #include <linux/workqueue.h>
 #include <linux/libps2.h>
+#include <linux/mutex.h>
 
 #define DRIVER_DESC	"AT and PS/2 keyboard driver"
 
@@ -216,7 +217,7 @@
 	unsigned long time;
 
 	struct work_struct event_work;
-	struct semaphore event_sem;
+	struct mutex event_mutex;
 	unsigned long event_mask;
 };
 
@@ -302,19 +303,19 @@
 	if (atkbd->translated) {
 
 		if (atkbd->emul ||
-		    !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
-		      code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
-		     (code == ATKBD_RET_ERR && !atkbd->err_xl) ||
-	             (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
+		    (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 &&
+		     code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA &&
+		     (code != ATKBD_RET_ERR || atkbd->err_xl) &&
+	             (code != ATKBD_RET_BAT || atkbd->bat_xl))) {
 			atkbd->release = code >> 7;
 			code &= 0x7f;
 		}
 
 		if (!atkbd->emul) {
 		     if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
-			atkbd->bat_xl = !atkbd->release;
+			atkbd->bat_xl = !(data >> 7);
 		     if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
-			atkbd->err_xl = !atkbd->release;
+			atkbd->err_xl = !(data >> 7);
 		}
 	}
 
@@ -449,7 +450,7 @@
 	unsigned char param[2];
 	int i, j;
 
-	down(&atkbd->event_sem);
+	mutex_lock(&atkbd->event_mutex);
 
 	if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
 		param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
@@ -480,7 +481,7 @@
 		ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
 	}
 
-	up(&atkbd->event_sem);
+	mutex_unlock(&atkbd->event_mutex);
 }
 
 /*
@@ -846,7 +847,7 @@
 	atkbd->dev = dev;
 	ps2_init(&atkbd->ps2dev, serio);
 	INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd);
-	init_MUTEX(&atkbd->event_sem);
+	mutex_init(&atkbd->event_mutex);
 
 	switch (serio->id.type) {
 
@@ -862,9 +863,6 @@
 	atkbd->softrepeat = atkbd_softrepeat;
 	atkbd->scroll = atkbd_scroll;
 
-	if (!atkbd->write)
-		atkbd->softrepeat = 1;
-
 	if (atkbd->softrepeat)
 		atkbd->softraw = 1;
 
diff -urN oldtree/drivers/input/keyboard/corgikbd.c newtree/drivers/input/keyboard/corgikbd.c
--- oldtree/drivers/input/keyboard/corgikbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/keyboard/corgikbd.c	2006-04-01 05:35:38.127002750 -0500
@@ -29,11 +29,11 @@
 #define KB_COLS				12
 #define KB_ROWMASK(r)		(1 << (r))
 #define SCANCODE(r,c)		( ((r)<<4) + (c) + 1 )
-/* zero code, 124 scancodes + 3 hinge combinations */
-#define	NR_SCANCODES		( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 )
-#define SCAN_INTERVAL		(HZ/10)
+/* zero code, 124 scancodes */
+#define	NR_SCANCODES		( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 )
 
-#define HINGE_SCAN_INTERVAL		(HZ/4)
+#define SCAN_INTERVAL		(50) /* ms */
+#define HINGE_SCAN_INTERVAL	(250) /* ms */
 
 #define CORGI_KEY_CALENDER	KEY_F1
 #define CORGI_KEY_ADDRESS	KEY_F2
@@ -49,9 +49,6 @@
 #define CORGI_KEY_MAIL		KEY_F10
 #define CORGI_KEY_OK		KEY_F11
 #define CORGI_KEY_MENU		KEY_F12
-#define CORGI_HINGE_0		KEY_KP0
-#define CORGI_HINGE_1		KEY_KP1
-#define CORGI_HINGE_2		KEY_KP2
 
 static unsigned char corgikbd_keycode[NR_SCANCODES] = {
 	0,                                                                                                                /* 0 */
@@ -63,7 +60,6 @@
 	CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
 	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
-	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
 };
 
 
@@ -187,7 +183,7 @@
 
 	/* if any keys are pressed, enable the timer */
 	if (num_pressed)
-		mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL);
+		mod_timer(&corgikbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL));
 
 	spin_unlock_irqrestore(&corgikbd_data->lock, flags);
 }
@@ -228,6 +224,7 @@
  *          0x0c - Keyboard and Screen Closed
  */
 
+#define READ_GPIO_BIT(x)    (GPLR(x) & GPIO_bit(x))
 #define HINGE_STABLE_COUNT 2
 static int sharpsl_hinge_state;
 static int hinge_count;
@@ -239,6 +236,7 @@
 	unsigned long flags;
 
 	gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
+	gprr |= (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0);
 	if (gprr != sharpsl_hinge_state) {
 		hinge_count = 0;
 		sharpsl_hinge_state = gprr;
@@ -249,27 +247,38 @@
 
 			input_report_switch(corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
 			input_report_switch(corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
+			input_report_switch(corgikbd_data->input, SW_2, (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0));
 			input_sync(corgikbd_data->input);
 
 			spin_unlock_irqrestore(&corgikbd_data->lock, flags);
 		}
 	}
-	mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL);
+	mod_timer(&corgikbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
 }
 
 #ifdef CONFIG_PM
 static int corgikbd_suspend(struct platform_device *dev, pm_message_t state)
 {
+	int i;
 	struct corgikbd *corgikbd = platform_get_drvdata(dev);
+
 	corgikbd->suspended = 1;
+	/* strobe 0 is the power key so this can't be made an input for
+	   powersaving therefore i = 1 */
+	for (i = 1; i < CORGI_KEY_STROBE_NUM; i++)
+		pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_IN);
 
 	return 0;
 }
 
 static int corgikbd_resume(struct platform_device *dev)
 {
+	int i;
 	struct corgikbd *corgikbd = platform_get_drvdata(dev);
 
+	for (i = 1; i < CORGI_KEY_STROBE_NUM; i++)
+		pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
+
 	/* Upon resume, ignore the suspend key for a short while */
 	corgikbd->suspend_jiffies=jiffies;
 	corgikbd->suspended = 0;
@@ -333,10 +342,11 @@
 	clear_bit(0, input_dev->keybit);
 	set_bit(SW_0, input_dev->swbit);
 	set_bit(SW_1, input_dev->swbit);
+	set_bit(SW_2, input_dev->swbit);
 
 	input_register_device(corgikbd->input);
 
-	mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL);
+	mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
 
 	/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
 	for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
@@ -351,6 +361,9 @@
 	for (i = 0; i < CORGI_KEY_STROBE_NUM; i++)
 		pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
 
+	/* Setup the headphone jack as an input */
+	pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN);
+
 	return 0;
 }
 
diff -urN oldtree/drivers/input/keyboard/hil_kbd.c newtree/drivers/input/keyboard/hil_kbd.c
--- oldtree/drivers/input/keyboard/hil_kbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/keyboard/hil_kbd.c	2006-04-01 05:35:38.127002750 -0500
@@ -251,10 +251,9 @@
 	uint8_t		did, *idd;
 	int		i;
 	
-	kbd = kmalloc(sizeof(*kbd), GFP_KERNEL);
+	kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
 	if (!kbd)
 		return -ENOMEM;
-	memset(kbd, 0, sizeof(struct hil_kbd));
 
 	if (serio_open(serio, drv)) goto bail0;
 
diff -urN oldtree/drivers/input/keyboard/spitzkbd.c newtree/drivers/input/keyboard/spitzkbd.c
--- oldtree/drivers/input/keyboard/spitzkbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/keyboard/spitzkbd.c	2006-04-01 05:35:38.131003000 -0500
@@ -30,6 +30,7 @@
 #define SCANCODE(r,c)		(((r)<<4) + (c) + 1)
 #define	NR_SCANCODES		((KB_ROWS<<4) + 1)
 
+#define SCAN_INTERVAL		(50) /* ms */
 #define HINGE_SCAN_INTERVAL	(150) /* ms */
 
 #define SPITZ_KEY_CALENDER	KEY_F1
@@ -230,7 +231,7 @@
 
 	/* if any keys are pressed, enable the timer */
 	if (num_pressed)
-		mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100));
+		mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL));
 
 	spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
 }
@@ -287,6 +288,7 @@
 	unsigned long flags;
 
 	state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB));
+	state |= (GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT));
 	if (state != sharpsl_hinge_state) {
 		hinge_count = 0;
 		sharpsl_hinge_state = state;
@@ -299,6 +301,7 @@
 
 		input_report_switch(spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
 		input_report_switch(spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
+		input_report_switch(spitzkbd_data->input, SW_2, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0));
 		input_sync(spitzkbd_data->input);
 
 		spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
@@ -397,6 +400,7 @@
 	clear_bit(0, input_dev->keybit);
 	set_bit(SW_0, input_dev->swbit);
 	set_bit(SW_1, input_dev->swbit);
+	set_bit(SW_2, input_dev->swbit);
 
 	input_register_device(input_dev);
 
@@ -432,6 +436,9 @@
 	request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
 		    SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
 		    "Spitzkbd SWB", spitzkbd);
+ 	request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
+		    SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+		    "Spitzkbd HP", spitzkbd);
 
 	printk(KERN_INFO "input: Spitz Keyboard Registered\n");
 
@@ -450,6 +457,7 @@
 	free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd);
 	free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd);
 	free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd);
+	free_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd);
 
 	del_timer_sync(&spitzkbd->htimer);
 	del_timer_sync(&spitzkbd->timer);
diff -urN oldtree/drivers/input/misc/pcspkr.c newtree/drivers/input/misc/pcspkr.c
--- oldtree/drivers/input/misc/pcspkr.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/misc/pcspkr.c	2006-04-01 05:35:38.131003000 -0500
@@ -24,7 +24,6 @@
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
 
-static struct platform_device *pcspkr_platform_device;
 static DEFINE_SPINLOCK(i8253_beep_lock);
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -135,35 +134,11 @@
 
 static int __init pcspkr_init(void)
 {
-	int err;
-
-	err = platform_driver_register(&pcspkr_platform_driver);
-	if (err)
-		return err;
-
-	pcspkr_platform_device = platform_device_alloc("pcspkr", -1);
-	if (!pcspkr_platform_device) {
-		err = -ENOMEM;
-		goto err_unregister_driver;
-	}
-
-	err = platform_device_add(pcspkr_platform_device);
-	if (err)
-		goto err_free_device;
-
-	return 0;
-
- err_free_device:
-	platform_device_put(pcspkr_platform_device);
- err_unregister_driver:
-	platform_driver_unregister(&pcspkr_platform_driver);
-
-	return err;
+	return platform_driver_register(&pcspkr_platform_driver);
 }
 
 static void __exit pcspkr_exit(void)
 {
-	platform_device_unregister(pcspkr_platform_device);
 	platform_driver_unregister(&pcspkr_platform_driver);
 }
 
diff -urN oldtree/drivers/input/misc/uinput.c newtree/drivers/input/misc/uinput.c
--- oldtree/drivers/input/misc/uinput.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/misc/uinput.c	2006-04-01 05:35:38.131003000 -0500
@@ -194,7 +194,7 @@
 	if (!newdev)
 		return -ENOMEM;
 
-	init_MUTEX(&newdev->sem);
+	mutex_init(&newdev->mutex);
 	spin_lock_init(&newdev->requests_lock);
 	init_waitqueue_head(&newdev->requests_waitq);
 	init_waitqueue_head(&newdev->waitq);
@@ -340,7 +340,7 @@
 	struct uinput_device *udev = file->private_data;
 	int retval;
 
-	retval = down_interruptible(&udev->sem);
+	retval = mutex_lock_interruptible(&udev->mutex);
 	if (retval)
 		return retval;
 
@@ -348,7 +348,7 @@
 			uinput_inject_event(udev, buffer, count) :
 			uinput_setup_device(udev, buffer, count);
 
-	up(&udev->sem);
+	mutex_unlock(&udev->mutex);
 
 	return retval;
 }
@@ -369,7 +369,7 @@
 	if (retval)
 		return retval;
 
-	retval = down_interruptible(&udev->sem);
+	retval = mutex_lock_interruptible(&udev->mutex);
 	if (retval)
 		return retval;
 
@@ -388,7 +388,7 @@
 	}
 
  out:
-	up(&udev->sem);
+	mutex_unlock(&udev->mutex);
 
 	return retval;
 }
@@ -439,7 +439,7 @@
 
 	udev = file->private_data;
 
-	retval = down_interruptible(&udev->sem);
+	retval = mutex_lock_interruptible(&udev->mutex);
 	if (retval)
 		return retval;
 
@@ -589,7 +589,7 @@
 	}
 
  out:
-	up(&udev->sem);
+	mutex_unlock(&udev->mutex);
 	return retval;
 }
 
diff -urN oldtree/drivers/input/mouse/Makefile newtree/drivers/input/mouse/Makefile
--- oldtree/drivers/input/mouse/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mouse/Makefile	2006-04-01 05:35:49.623721250 -0500
@@ -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/hil_ptr.c newtree/drivers/input/mouse/hil_ptr.c
--- oldtree/drivers/input/mouse/hil_ptr.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mouse/hil_ptr.c	2006-04-01 05:35:38.131003000 -0500
@@ -245,10 +245,11 @@
 	unsigned int	i, naxsets, btntype;
 	uint8_t		did, *idd;
 
-	if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM;
-	memset(ptr, 0, sizeof(struct hil_ptr));
+	if (!(ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL)))
+		return -ENOMEM;
 
-	if (serio_open(serio, driver)) goto bail0;
+	if (serio_open(serio, driver))
+		goto bail0;
 
 	serio_set_drvdata(serio, ptr);
 	ptr->serio = serio;
diff -urN oldtree/drivers/input/mouse/psmouse-base.c newtree/drivers/input/mouse/psmouse-base.c
--- oldtree/drivers/input/mouse/psmouse-base.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mouse/psmouse-base.c	2006-04-01 05:35:49.627721500 -0500
@@ -20,12 +20,15 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 #include <linux/libps2.h>
+#include <linux/mutex.h>
+
 #include "psmouse.h"
 #include "synaptics.h"
 #include "logips2pp.h"
 #include "alps.h"
 #include "lifebook.h"
 #include "trackpoint.h"
+#include "touchkit_ps2.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -98,13 +101,13 @@
 __obsolete_setup("psmouse_rate=");
 
 /*
- * psmouse_sem protects all operations changing state of mouse
+ * psmouse_mutex protects all operations changing state of mouse
  * (connecting, disconnecting, changing rate or resolution via
  * sysfs). We could use a per-device semaphore but since there
  * rarely more than one PS/2 mouse connected and since semaphore
  * is taken in "slow" paths it is not worth it.
  */
-static DECLARE_MUTEX(psmouse_sem);
+static DEFINE_MUTEX(psmouse_mutex);
 
 static struct workqueue_struct *kpsmoused_wq;
 
@@ -609,6 +612,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 +705,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",
@@ -868,7 +885,7 @@
 	int failed = 0, enabled = 0;
 	int i;
 
-	down(&psmouse_sem);
+	mutex_lock(&psmouse_mutex);
 
 	if (psmouse->state != PSMOUSE_RESYNCING)
 		goto out;
@@ -948,7 +965,7 @@
 	if (parent)
 		psmouse_activate(parent);
  out:
-	up(&psmouse_sem);
+	mutex_unlock(&psmouse_mutex);
 }
 
 /*
@@ -974,14 +991,14 @@
 
 	sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group);
 
-	down(&psmouse_sem);
+	mutex_lock(&psmouse_mutex);
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
 	/* make sure we don't have a resync in progress */
-	up(&psmouse_sem);
+	mutex_unlock(&psmouse_mutex);
 	flush_workqueue(kpsmoused_wq);
-	down(&psmouse_sem);
+	mutex_lock(&psmouse_mutex);
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
@@ -1004,7 +1021,7 @@
 	if (parent)
 		psmouse_activate(parent);
 
-	up(&psmouse_sem);
+	mutex_unlock(&psmouse_mutex);
 }
 
 static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
@@ -1076,7 +1093,7 @@
 	struct input_dev *input_dev;
 	int retval = -ENOMEM;
 
-	down(&psmouse_sem);
+	mutex_lock(&psmouse_mutex);
 
 	/*
 	 * If this is a pass-through port deactivate parent so the device
@@ -1144,7 +1161,7 @@
 	if (parent)
 		psmouse_activate(parent);
 
-	up(&psmouse_sem);
+	mutex_unlock(&psmouse_mutex);
 	return retval;
 }
 
@@ -1161,7 +1178,7 @@
 		return -1;
 	}
 
-	down(&psmouse_sem);
+	mutex_lock(&psmouse_mutex);
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
@@ -1195,7 +1212,7 @@
 	if (parent)
 		psmouse_activate(parent);
 
-	up(&psmouse_sem);
+	mutex_unlock(&psmouse_mutex);
 	return rc;
 }
 
@@ -1273,7 +1290,7 @@
 		goto out_unpin;
 	}
 
-	retval = down_interruptible(&psmouse_sem);
+	retval = mutex_lock_interruptible(&psmouse_mutex);
 	if (retval)
 		goto out_unpin;
 
@@ -1281,7 +1298,7 @@
 
 	if (psmouse->state == PSMOUSE_IGNORE) {
 		retval = -ENODEV;
-		goto out_up;
+		goto out_unlock;
 	}
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
@@ -1299,8 +1316,8 @@
 	if (parent)
 		psmouse_activate(parent);
 
- out_up:
-	up(&psmouse_sem);
+ out_unlock:
+	mutex_unlock(&psmouse_mutex);
  out_unpin:
 	serio_unpin_driver(serio);
 	return retval;
@@ -1357,11 +1374,11 @@
 			return -EIO;
 		}
 
-		up(&psmouse_sem);
+		mutex_unlock(&psmouse_mutex);
 		serio_unpin_driver(serio);
 		serio_unregister_child_port(serio);
 		serio_pin_driver_uninterruptible(serio);
-		down(&psmouse_sem);
+		mutex_lock(&psmouse_mutex);
 
 		if (serio->drv != &psmouse_drv) {
 			input_free_device(new_dev);
diff -urN oldtree/drivers/input/mouse/psmouse.h newtree/drivers/input/mouse/psmouse.h
--- oldtree/drivers/input/mouse/psmouse.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mouse/psmouse.h	2006-04-01 05:35:49.627721500 -0500
@@ -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/synaptics.c newtree/drivers/input/mouse/synaptics.c
--- oldtree/drivers/input/mouse/synaptics.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mouse/synaptics.c	2006-04-01 05:35:38.135003250 -0500
@@ -247,14 +247,12 @@
 {
 	struct serio *serio;
 
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!serio) {
 		printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
 		return;
 	}
 
-	memset(serio, 0, sizeof(struct serio));
-
 	serio->id.type = SERIO_PS_PSTHRU;
 	strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
 	strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
@@ -623,10 +621,9 @@
 {
 	struct synaptics_data *priv;
 
-	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+	psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
 	if (!priv)
 		return -1;
-	memset(priv, 0, sizeof(struct synaptics_data));
 
 	if (synaptics_query_hardware(psmouse)) {
 		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
diff -urN oldtree/drivers/input/mouse/touchkit_ps2.c newtree/drivers/input/mouse/touchkit_ps2.c
--- oldtree/drivers/input/mouse/touchkit_ps2.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/input/mouse/touchkit_ps2.c	2006-04-01 05:35:49.627721500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/input/mouse/touchkit_ps2.h	2006-04-01 05:35:49.627721500 -0500
@@ -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/input/mousedev.c newtree/drivers/input/mousedev.c
--- oldtree/drivers/input/mousedev.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/mousedev.c	2006-04-01 05:35:38.131003000 -0500
@@ -412,9 +412,8 @@
 	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct mousedev_list));
 
 	spin_lock_init(&list->packet_lock);
 	list->pos_x = xres / 2;
@@ -626,9 +625,8 @@
 		return NULL;
 	}
 
-	if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
+	if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
 		return NULL;
-	memset(mousedev, 0, sizeof(struct mousedev));
 
 	INIT_LIST_HEAD(&mousedev->list);
 	init_waitqueue_head(&mousedev->wait);
diff -urN oldtree/drivers/input/power.c newtree/drivers/input/power.c
--- oldtree/drivers/input/power.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/power.c	2006-04-01 05:35:38.135003250 -0500
@@ -103,9 +103,8 @@
 {
 	struct input_handle *handle;
 
-	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
 		return NULL;
-	memset(handle, 0, sizeof(struct input_handle));
 
 	handle->dev = dev;
 	handle->handler = handler;
diff -urN oldtree/drivers/input/serio/hil_mlc.c newtree/drivers/input/serio/hil_mlc.c
--- oldtree/drivers/input/serio/hil_mlc.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/hil_mlc.c	2006-04-01 05:35:38.135003250 -0500
@@ -872,9 +872,8 @@
 	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
 		struct serio *mlc_serio;
 		hil_mlc_copy_di_scratch(mlc, i);
-		mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL);
+		mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
 		mlc->serio[i] = mlc_serio;
-		memset(mlc_serio, 0, sizeof(*mlc_serio));
 		mlc_serio->id			= hil_mlc_serio_id;
 		mlc_serio->write		= hil_mlc_serio_write;
 		mlc_serio->open			= hil_mlc_serio_open;
diff -urN oldtree/drivers/input/serio/i8042-x86ia64io.h newtree/drivers/input/serio/i8042-x86ia64io.h
--- oldtree/drivers/input/serio/i8042-x86ia64io.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/i8042-x86ia64io.h	2006-04-01 05:35:38.135003250 -0500
@@ -192,7 +192,9 @@
 #include <linux/pnp.h>
 
 static int i8042_pnp_kbd_registered;
+static unsigned int i8042_pnp_kbd_devices;
 static int i8042_pnp_aux_registered;
+static unsigned int i8042_pnp_aux_devices;
 
 static int i8042_pnp_command_reg;
 static int i8042_pnp_data_reg;
@@ -219,6 +221,7 @@
 		strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
 	}
 
+	i8042_pnp_kbd_devices++;
 	return 0;
 }
 
@@ -239,6 +242,7 @@
 		strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
 	}
 
+	i8042_pnp_aux_devices++;
 	return 0;
 }
 
@@ -287,21 +291,23 @@
 
 static int __init i8042_pnp_init(void)
 {
-	int result_kbd = 0, result_aux = 0;
 	char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+	int err;
 
 	if (i8042_nopnp) {
 		printk(KERN_INFO "i8042: PNP detection disabled\n");
 		return 0;
 	}
 
-	if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0)
+	err = pnp_register_driver(&i8042_pnp_kbd_driver);
+	if (!err)
 		i8042_pnp_kbd_registered = 1;
 
-	if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0)
+	err = pnp_register_driver(&i8042_pnp_aux_driver);
+	if (!err)
 		i8042_pnp_aux_registered = 1;
 
-	if (result_kbd <= 0 && result_aux <= 0) {
+	if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) {
 		i8042_pnp_exit();
 #if defined(__ia64__)
 		return -ENODEV;
@@ -311,24 +317,24 @@
 #endif
 	}
 
-	if (result_kbd > 0)
+	if (i8042_pnp_kbd_devices)
 		snprintf(kbd_irq_str, sizeof(kbd_irq_str),
 			"%d", i8042_pnp_kbd_irq);
-	if (result_aux > 0)
+	if (i8042_pnp_aux_devices)
 		snprintf(aux_irq_str, sizeof(aux_irq_str),
 			"%d", i8042_pnp_aux_irq);
 
 	printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
-		i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "",
+		i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "",
 		i8042_pnp_aux_name,
 		i8042_pnp_data_reg, i8042_pnp_command_reg,
-		kbd_irq_str, (result_kbd > 0 && result_aux > 0) ? "," : "",
+		kbd_irq_str, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "",
 		aux_irq_str);
 
 #if defined(__ia64__)
-	if (result_kbd <= 0)
+	if (!i8042_pnp_kbd_devices)
 		i8042_nokbd = 1;
-	if (result_aux <= 0)
+	if (!i8042_pnp_aux_devices)
 		i8042_noaux = 1;
 #endif
 
diff -urN oldtree/drivers/input/serio/libps2.c newtree/drivers/input/serio/libps2.c
--- oldtree/drivers/input/serio/libps2.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/libps2.c	2006-04-01 05:35:38.135003250 -0500
@@ -84,7 +84,7 @@
 		maxbytes = sizeof(ps2dev->cmdbuf);
 	}
 
-	down(&ps2dev->cmd_sem);
+	mutex_lock(&ps2dev->cmd_mutex);
 
 	serio_pause_rx(ps2dev->serio);
 	ps2dev->flags = PS2_FLAG_CMD;
@@ -94,7 +94,7 @@
 	wait_event_timeout(ps2dev->wait,
 			   !(ps2dev->flags & PS2_FLAG_CMD),
 			   msecs_to_jiffies(timeout));
-	up(&ps2dev->cmd_sem);
+	mutex_unlock(&ps2dev->cmd_mutex);
 }
 
 /*
@@ -177,7 +177,7 @@
 		return -1;
 	}
 
-	down(&ps2dev->cmd_sem);
+	mutex_lock(&ps2dev->cmd_mutex);
 
 	serio_pause_rx(ps2dev->serio);
 	ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
@@ -229,7 +229,7 @@
 	ps2dev->flags = 0;
 	serio_continue_rx(ps2dev->serio);
 
-	up(&ps2dev->cmd_sem);
+	mutex_unlock(&ps2dev->cmd_mutex);
 	return rc;
 }
 
@@ -281,7 +281,7 @@
 
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
 {
-	init_MUTEX(&ps2dev->cmd_sem);
+	mutex_init(&ps2dev->cmd_mutex);
 	init_waitqueue_head(&ps2dev->wait);
 	ps2dev->serio = serio;
 }
diff -urN oldtree/drivers/input/serio/parkbd.c newtree/drivers/input/serio/parkbd.c
--- oldtree/drivers/input/serio/parkbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/parkbd.c	2006-04-01 05:35:38.135003250 -0500
@@ -171,9 +171,8 @@
 {
 	struct serio *serio;
 
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (serio) {
-		memset(serio, 0, sizeof(struct serio));
 		serio->id.type = parkbd_mode;
 		serio->write = parkbd_write,
 		strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name));
diff -urN oldtree/drivers/input/serio/rpckbd.c newtree/drivers/input/serio/rpckbd.c
--- oldtree/drivers/input/serio/rpckbd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/rpckbd.c	2006-04-01 05:35:38.135003250 -0500
@@ -111,11 +111,10 @@
 {
 	struct serio *serio;
 
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!serio)
 		return -ENOMEM;
 
-	memset(serio, 0, sizeof(struct serio));
 	serio->id.type		= SERIO_8042;
 	serio->write		= rpckbd_write;
 	serio->open		= rpckbd_open;
diff -urN oldtree/drivers/input/serio/serio.c newtree/drivers/input/serio/serio.c
--- oldtree/drivers/input/serio/serio.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/serio.c	2006-04-01 05:35:38.135003250 -0500
@@ -34,6 +34,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -52,10 +53,10 @@
 EXPORT_SYMBOL(serio_reconnect);
 
 /*
- * serio_sem protects entire serio subsystem and is taken every time
+ * serio_mutex protects entire serio subsystem and is taken every time
  * serio port or driver registrered or unregistered.
  */
-static DECLARE_MUTEX(serio_sem);
+static DEFINE_MUTEX(serio_mutex);
 
 static LIST_HEAD(serio_list);
 
@@ -70,9 +71,9 @@
 {
 	int retval;
 
-	down(&serio->drv_sem);
+	mutex_lock(&serio->drv_mutex);
 	retval = drv->connect(serio, drv);
-	up(&serio->drv_sem);
+	mutex_unlock(&serio->drv_mutex);
 
 	return retval;
 }
@@ -81,20 +82,20 @@
 {
 	int retval = -1;
 
-	down(&serio->drv_sem);
+	mutex_lock(&serio->drv_mutex);
 	if (serio->drv && serio->drv->reconnect)
 		retval = serio->drv->reconnect(serio);
-	up(&serio->drv_sem);
+	mutex_unlock(&serio->drv_mutex);
 
 	return retval;
 }
 
 static void serio_disconnect_driver(struct serio *serio)
 {
-	down(&serio->drv_sem);
+	mutex_lock(&serio->drv_mutex);
 	if (serio->drv)
 		serio->drv->disconnect(serio);
-	up(&serio->drv_sem);
+	mutex_unlock(&serio->drv_mutex);
 }
 
 static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
@@ -195,6 +196,7 @@
 	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
 		if (!try_module_get(owner)) {
 			printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
+			kfree(event);
 			goto out;
 		}
 
@@ -272,7 +274,7 @@
 	struct serio_event *event;
 	struct serio_driver *serio_drv;
 
-	down(&serio_sem);
+	mutex_lock(&serio_mutex);
 
 	/*
 	 * Note that we handle only one event here to give swsusp
@@ -314,7 +316,7 @@
 		serio_free_event(event);
 	}
 
-	up(&serio_sem);
+	mutex_unlock(&serio_mutex);
 }
 
 /*
@@ -449,7 +451,7 @@
 	struct device_driver *drv;
 	int retval;
 
-	retval = down_interruptible(&serio_sem);
+	retval = mutex_lock_interruptible(&serio_mutex);
 	if (retval)
 		return retval;
 
@@ -469,7 +471,7 @@
 		retval = -EINVAL;
 	}
 
-	up(&serio_sem);
+	mutex_unlock(&serio_mutex);
 
 	return retval;
 }
@@ -524,7 +526,7 @@
 	__module_get(THIS_MODULE);
 
 	spin_lock_init(&serio->lock);
-	init_MUTEX(&serio->drv_sem);
+	mutex_init(&serio->drv_mutex);
 	device_initialize(&serio->dev);
 	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id),
 		 "serio%ld", (long)atomic_inc_return(&serio_no) - 1);
@@ -661,10 +663,10 @@
  */
 void serio_unregister_port(struct serio *serio)
 {
-	down(&serio_sem);
+	mutex_lock(&serio_mutex);
 	serio_disconnect_port(serio);
 	serio_destroy_port(serio);
-	up(&serio_sem);
+	mutex_unlock(&serio_mutex);
 }
 
 /*
@@ -672,17 +674,17 @@
  */
 void serio_unregister_child_port(struct serio *serio)
 {
-	down(&serio_sem);
+	mutex_lock(&serio_mutex);
 	if (serio->child) {
 		serio_disconnect_port(serio->child);
 		serio_destroy_port(serio->child);
 	}
-	up(&serio_sem);
+	mutex_unlock(&serio_mutex);
 }
 
 /*
  * Submits register request to kseriod for subsequent execution.
- * Can be used when it is not obvious whether the serio_sem is
+ * Can be used when it is not obvious whether the serio_mutex is
  * taken or not and when delayed execution is feasible.
  */
 void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
@@ -765,7 +767,7 @@
 {
 	struct serio *serio;
 
-	down(&serio_sem);
+	mutex_lock(&serio_mutex);
 	drv->manual_bind = 1;	/* so serio_find_driver ignores it */
 
 start_over:
@@ -779,7 +781,7 @@
 	}
 
 	driver_unregister(&drv->driver);
-	up(&serio_sem);
+	mutex_unlock(&serio_mutex);
 }
 
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
@@ -858,7 +860,7 @@
 	return 0;
 }
 
-/* called from serio_driver->connect/disconnect methods under serio_sem */
+/* called from serio_driver->connect/disconnect methods under serio_mutex */
 int serio_open(struct serio *serio, struct serio_driver *drv)
 {
 	serio_set_drv(serio, drv);
@@ -870,7 +872,7 @@
 	return 0;
 }
 
-/* called from serio_driver->connect/disconnect methods under serio_sem */
+/* called from serio_driver->connect/disconnect methods under serio_mutex */
 void serio_close(struct serio *serio)
 {
 	if (serio->close)
@@ -923,5 +925,5 @@
 	kthread_stop(serio_task);
 }
 
-module_init(serio_init);
+subsys_initcall(serio_init);
 module_exit(serio_exit);
diff -urN oldtree/drivers/input/serio/serio_raw.c newtree/drivers/input/serio/serio_raw.c
--- oldtree/drivers/input/serio/serio_raw.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/serio/serio_raw.c	2006-04-01 05:35:38.139003500 -0500
@@ -19,6 +19,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #define DRIVER_DESC	"Raw serio driver"
 
@@ -46,7 +47,7 @@
 	struct list_head node;
 };
 
-static DECLARE_MUTEX(serio_raw_sem);
+static DEFINE_MUTEX(serio_raw_mutex);
 static LIST_HEAD(serio_raw_list);
 static unsigned int serio_raw_no;
 
@@ -81,7 +82,7 @@
 	struct serio_raw_list *list;
 	int retval = 0;
 
-	retval = down_interruptible(&serio_raw_sem);
+	retval = mutex_lock_interruptible(&serio_raw_mutex);
 	if (retval)
 		return retval;
 
@@ -95,12 +96,11 @@
 		goto out;
 	}
 
-	if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
+	if (!(list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
 		retval = -ENOMEM;
 		goto out;
 	}
 
-	memset(list, 0, sizeof(struct serio_raw_list));
 	list->serio_raw = serio_raw;
 	file->private_data = list;
 
@@ -108,7 +108,7 @@
 	list_add_tail(&list->node, &serio_raw->list);
 
 out:
-	up(&serio_raw_sem);
+	mutex_unlock(&serio_raw_mutex);
 	return retval;
 }
 
@@ -130,12 +130,12 @@
 	struct serio_raw_list *list = file->private_data;
 	struct serio_raw *serio_raw = list->serio_raw;
 
-	down(&serio_raw_sem);
+	mutex_lock(&serio_raw_mutex);
 
 	serio_raw_fasync(-1, file, 0);
 	serio_raw_cleanup(serio_raw);
 
-	up(&serio_raw_sem);
+	mutex_unlock(&serio_raw_mutex);
 	return 0;
 }
 
@@ -194,7 +194,7 @@
 	int retval;
 	unsigned char c;
 
-	retval = down_interruptible(&serio_raw_sem);
+	retval = mutex_lock_interruptible(&serio_raw_mutex);
 	if (retval)
 		return retval;
 
@@ -219,7 +219,7 @@
 	};
 
 out:
-	up(&serio_raw_sem);
+	mutex_unlock(&serio_raw_mutex);
 	return written;
 }
 
@@ -275,14 +275,13 @@
 	struct serio_raw *serio_raw;
 	int err;
 
-	if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
+	if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
 		printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
 		return -ENOMEM;
 	}
 
-	down(&serio_raw_sem);
+	mutex_lock(&serio_raw_mutex);
 
-	memset(serio_raw, 0, sizeof(struct serio_raw));
 	snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
 	serio_raw->refcnt = 1;
 	serio_raw->serio = serio;
@@ -325,7 +324,7 @@
 	serio_set_drvdata(serio, NULL);
 	kfree(serio_raw);
 out:
-	up(&serio_raw_sem);
+	mutex_unlock(&serio_raw_mutex);
 	return err;
 }
 
@@ -350,7 +349,7 @@
 {
 	struct serio_raw *serio_raw;
 
-	down(&serio_raw_sem);
+	mutex_lock(&serio_raw_mutex);
 
 	serio_raw = serio_get_drvdata(serio);
 
@@ -361,7 +360,7 @@
 	if (!serio_raw_cleanup(serio_raw))
 		wake_up_interruptible(&serio_raw->wait);
 
-	up(&serio_raw_sem);
+	mutex_unlock(&serio_raw_mutex);
 }
 
 static struct serio_device_id serio_raw_serio_ids[] = {
diff -urN oldtree/drivers/input/tsdev.c newtree/drivers/input/tsdev.c
--- oldtree/drivers/input/tsdev.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/input/tsdev.c	2006-04-01 05:35:38.139003500 -0500
@@ -157,9 +157,8 @@
 	if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct tsdev_list));
 
 	list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
 
@@ -379,9 +378,8 @@
 		return NULL;
 	}
 
-	if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
+	if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
 		return NULL;
-	memset(tsdev, 0, sizeof(struct tsdev));
 
 	INIT_LIST_HEAD(&tsdev->list);
 	init_waitqueue_head(&tsdev->wait);
diff -urN oldtree/drivers/isdn/hardware/avm/avm_cs.c newtree/drivers/isdn/hardware/avm/avm_cs.c
--- oldtree/drivers/isdn/hardware/avm/avm_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/isdn/hardware/avm/avm_cs.c	2006-04-01 05:35:44.247385250 -0500
@@ -51,8 +51,8 @@
    handler.
 */
 
-static void avmcs_config(dev_link_t *link);
-static void avmcs_release(dev_link_t *link);
+static int avmcs_config(struct pcmcia_device *link);
+static void avmcs_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -65,10 +65,10 @@
 /*
    A linked list of "instances" of the skeleton device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
+   by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
+   memory card driver uses an array of struct pcmcia_device pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -78,7 +78,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally can't be allocated dynamically.
 */
@@ -99,54 +99,38 @@
     
 ======================================================================*/
 
-static int avmcs_attach(struct pcmcia_device *p_dev)
+static int avmcs_probe(struct pcmcia_device *p_dev)
 {
-    dev_link_t *link;
     local_info_t *local;
 
-    /* Initialize the dev_link_t structure */
-    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-    if (!link)
-        goto err;
-    memset(link, 0, sizeof(struct dev_link_t));
-
     /* The io structure describes IO port mapping */
-    link->io.NumPorts1 = 16;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts2 = 0;
+    p_dev->io.NumPorts1 = 16;
+    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    p_dev->io.NumPorts2 = 0;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+
+    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
 
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-    
     /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
+    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+    p_dev->conf.IntType = INT_MEMORY_AND_IO;
+    p_dev->conf.ConfigIndex = 1;
+    p_dev->conf.Present = PRESENT_OPTION;
 
     /* Allocate space for private device-specific data */
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
     if (!local)
-        goto err_kfree;
+        goto err;
     memset(local, 0, sizeof(local_info_t));
-    link->priv = local;
+    p_dev->priv = local;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
+    return avmcs_config(p_dev);
 
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    avmcs_config(link);
-
-    return 0;
-
- err_kfree:
-    kfree(link);
  err:
-    return -EINVAL;
+    return -ENOMEM;
 } /* avmcs_attach */
 
 /*======================================================================
@@ -158,15 +142,10 @@
 
 ======================================================================*/
 
-static void avmcs_detach(struct pcmcia_device *p_dev)
+static void avmcs_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
-    if (link->state & DEV_CONFIG)
 	avmcs_release(link);
-
-    kfree(link->priv);
-    kfree(link);
+	kfree(link->priv);
 } /* avmcs_detach */
 
 /*======================================================================
@@ -177,7 +156,7 @@
     
 ======================================================================*/
 
-static int get_tuple(client_handle_t handle, tuple_t *tuple,
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_tuple_data(handle, tuple);
@@ -185,7 +164,7 @@
     return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_first_tuple(handle, tuple);
@@ -193,7 +172,7 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_next_tuple(handle, tuple);
@@ -201,9 +180,8 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static void avmcs_config(dev_link_t *link)
+static int avmcs_config(struct pcmcia_device *link)
 {
-    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
@@ -213,8 +191,7 @@
     char devname[128];
     int cardtype;
     int (*addcard)(unsigned int port, unsigned irq);
-    
-    handle = link->handle;
+
     dev = link->priv;
 
     /*
@@ -223,25 +200,21 @@
     */
     do {
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	i = pcmcia_get_first_tuple(handle, &tuple);
+	i = pcmcia_get_first_tuple(link, &tuple);
 	if (i != CS_SUCCESS) break;
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
-	i = pcmcia_get_tuple_data(handle, &tuple);
+	i = pcmcia_get_tuple_data(link, &tuple);
 	if (i != CS_SUCCESS) break;
-	i = pcmcia_parse_tuple(handle, &tuple, &parse);
+	i = pcmcia_parse_tuple(link, &tuple, &parse);
 	if (i != CS_SUCCESS) break;
 	link->conf.ConfigBase = parse.config.base;
     } while (0);
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, ParseTuple, i);
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	cs_error(link, ParseTuple, i);
+	return -ENODEV;
     }
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
     do {
 
@@ -252,7 +225,7 @@
 	tuple.DesiredTuple = CISTPL_VERS_1;
 
 	devname[0] = 0;
-	if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
+	if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) {
 	    strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], 
 			sizeof(devname));
 	}
@@ -263,7 +236,7 @@
 	tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
 	tuple.Attributes = 0;
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(link, &tuple, &parse);
 	while (i == CS_SUCCESS) {
 	    if (cf->io.nwin > 0) {
 		link->conf.ConfigIndex = cf->index;
@@ -273,36 +246,36 @@
                 printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
 			link->io.BasePort1,
 		        link->io.BasePort1+link->io.NumPorts1-1);
-		i = pcmcia_request_io(link->handle, &link->io);
+		i = pcmcia_request_io(link, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
-	    i = next_tuple(handle, &tuple, &parse);
+	    i = next_tuple(link, &tuple, &parse);
 	}
 
 found_port:
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestIO, i);
+	    cs_error(link, RequestIO, i);
 	    break;
 	}
-	
+
 	/*
 	 * allocate an interrupt line
 	 */
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestIRQ, i);
-	    pcmcia_release_io(link->handle, &link->io);
+	    cs_error(link, RequestIRQ, i);
+	    /* undo */
+	    pcmcia_disable_device(link);
 	    break;
 	}
-	
+
 	/*
          * configure the PCMCIA socket
 	  */
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestConfiguration, i);
-	    pcmcia_release_io(link->handle, &link->io);
-	    pcmcia_release_irq(link->handle, &link->irq);
+	    cs_error(link, RequestConfiguration, i);
+	    pcmcia_disable_device(link);
 	    break;
 	}
 
@@ -331,13 +304,12 @@
 
     dev->node.major = 64;
     dev->node.minor = 0;
-    link->dev = &dev->node;
-    
-    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev_node = &dev->node;
+
     /* If any step failed, release any partially configured state */
     if (i != 0) {
 	avmcs_release(link);
-	return;
+	return -ENODEV;
     }
 
 
@@ -351,9 +323,10 @@
         printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
 		dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
 	avmcs_release(link);
-	return;
+	return -ENODEV;
     }
     dev->node.minor = i;
+    return 0;
 
 } /* avmcs_config */
 
@@ -365,56 +338,12 @@
     
 ======================================================================*/
 
-static void avmcs_release(dev_link_t *link)
+static void avmcs_release(struct pcmcia_device *link)
 {
-    b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
-
-    /* Unlink the device chain */
-    link->dev = NULL;
-    
-    /* Don't bother checking to see if these succeed or not */
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
+	b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
+	pcmcia_disable_device(link);
 } /* avmcs_release */
 
-static int avmcs_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int avmcs_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
-}
-
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the net drivers from trying
-    to talk to the card any more.
-
-    When a CARD_REMOVAL event is received, we immediately set a flag
-    to block future accesses to this device.  All the functions that
-    actually access the device should check this flag to make sure
-    the card is still present.
-    
-======================================================================*/
-
 
 static struct pcmcia_device_id avmcs_ids[] = {
 	PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
@@ -429,11 +358,9 @@
 	.drv	= {
 		.name	= "avm_cs",
 	},
-	.probe = avmcs_attach,
+	.probe = avmcs_probe,
 	.remove	= avmcs_detach,
 	.id_table = avmcs_ids,
-	.suspend= avmcs_suspend,
-	.resume = avmcs_resume,
 };
 
 static int __init avmcs_init(void)
diff -urN oldtree/drivers/isdn/hisax/avma1_cs.c newtree/drivers/isdn/hisax/avma1_cs.c
--- oldtree/drivers/isdn/hisax/avma1_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/isdn/hisax/avma1_cs.c	2006-04-01 05:35:44.247385250 -0500
@@ -67,8 +67,8 @@
    handler.
 */
 
-static void avma1cs_config(dev_link_t *link);
-static void avma1cs_release(dev_link_t *link);
+static int avma1cs_config(struct pcmcia_device *link);
+static void avma1cs_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -82,10 +82,10 @@
 /*
    A linked list of "instances" of the skeleton device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
+   by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
+   memory card driver uses an array of struct pcmcia_device pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -95,7 +95,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally can't be allocated dynamically.
 */
@@ -116,55 +116,40 @@
     
 ======================================================================*/
 
-static int avma1cs_attach(struct pcmcia_device *p_dev)
+static int avma1cs_probe(struct pcmcia_device *p_dev)
 {
-    dev_link_t *link;
     local_info_t *local;
 
     DEBUG(0, "avma1cs_attach()\n");
 
-    /* Initialize the dev_link_t structure */
-    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-    if (!link)
-	return -ENOMEM;
-    memset(link, 0, sizeof(struct dev_link_t));
-
     /* Allocate space for private device-specific data */
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
-    if (!local) {
-	kfree(link);
+    if (!local)
 	return -ENOMEM;
-    }
+
     memset(local, 0, sizeof(local_info_t));
-    link->priv = local;
+    p_dev->priv = local;
 
     /* The io structure describes IO port mapping */
-    link->io.NumPorts1 = 16;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts2 = 16;
-    link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
-    link->io.IOAddrLines = 5;
+    p_dev->io.NumPorts1 = 16;
+    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    p_dev->io.NumPorts2 = 16;
+    p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+    p_dev->io.IOAddrLines = 5;
 
     /* Interrupt setup */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
 
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
 
     /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
+    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+    p_dev->conf.IntType = INT_MEMORY_AND_IO;
+    p_dev->conf.ConfigIndex = 1;
+    p_dev->conf.Present = PRESENT_OPTION;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    avma1cs_config(link);
-
-    return 0;
+    return avma1cs_config(p_dev);
 } /* avma1cs_attach */
 
 /*======================================================================
@@ -176,17 +161,11 @@
 
 ======================================================================*/
 
-static void avma1cs_detach(struct pcmcia_device *p_dev)
+static void avma1cs_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
-    DEBUG(0, "avma1cs_detach(0x%p)\n", link);
-
-    if (link->state & DEV_CONFIG)
-	    avma1cs_release(link);
-
-    kfree(link->priv);
-    kfree(link);
+	DEBUG(0, "avma1cs_detach(0x%p)\n", link);
+	avma1cs_release(link);
+	kfree(link->priv);
 } /* avma1cs_detach */
 
 /*======================================================================
@@ -197,7 +176,7 @@
     
 ======================================================================*/
 
-static int get_tuple(client_handle_t handle, tuple_t *tuple,
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_tuple_data(handle, tuple);
@@ -205,7 +184,7 @@
     return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_first_tuple(handle, tuple);
@@ -213,7 +192,7 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		     cisparse_t *parse)
 {
     int i = pcmcia_get_next_tuple(handle, tuple);
@@ -221,9 +200,8 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static void avma1cs_config(dev_link_t *link)
+static int avma1cs_config(struct pcmcia_device *link)
 {
-    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
@@ -233,8 +211,7 @@
     char devname[128];
     IsdnCard_t	icard;
     int busy = 0;
-    
-    handle = link->handle;
+
     dev = link->priv;
 
     DEBUG(0, "avma1cs_config(0x%p)\n", link);
@@ -245,25 +222,21 @@
     */
     do {
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	i = pcmcia_get_first_tuple(handle, &tuple);
+	i = pcmcia_get_first_tuple(link, &tuple);
 	if (i != CS_SUCCESS) break;
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
-	i = pcmcia_get_tuple_data(handle, &tuple);
+	i = pcmcia_get_tuple_data(link, &tuple);
 	if (i != CS_SUCCESS) break;
-	i = pcmcia_parse_tuple(handle, &tuple, &parse);
+	i = pcmcia_parse_tuple(link, &tuple, &parse);
 	if (i != CS_SUCCESS) break;
 	link->conf.ConfigBase = parse.config.base;
     } while (0);
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, ParseTuple, i);
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	cs_error(link, ParseTuple, i);
+	return -ENODEV;
     }
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
     do {
 
@@ -274,7 +247,7 @@
 	tuple.DesiredTuple = CISTPL_VERS_1;
 
 	devname[0] = 0;
-	if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
+	if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) {
 	    strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], 
 			sizeof(devname));
 	}
@@ -285,7 +258,7 @@
 	tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
 	tuple.Attributes = 0;
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	i = first_tuple(handle, &tuple, &parse);
+	i = first_tuple(link, &tuple, &parse);
 	while (i == CS_SUCCESS) {
 	    if (cf->io.nwin > 0) {
 		link->conf.ConfigIndex = cf->index;
@@ -295,36 +268,36 @@
 		printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
 			link->io.BasePort1,
 			link->io.BasePort1+link->io.NumPorts1 - 1);
-		i = pcmcia_request_io(link->handle, &link->io);
+		i = pcmcia_request_io(link, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
-	    i = next_tuple(handle, &tuple, &parse);
+	    i = next_tuple(link, &tuple, &parse);
 	}
 
 found_port:
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestIO, i);
+	    cs_error(link, RequestIO, i);
 	    break;
 	}
 	
 	/*
 	 * allocate an interrupt line
 	 */
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestIRQ, i);
-	    pcmcia_release_io(link->handle, &link->io);
+	    cs_error(link, RequestIRQ, i);
+	    /* undo */
+	    pcmcia_disable_device(link);
 	    break;
 	}
-	
+
 	/*
 	 * configure the PCMCIA socket
 	 */
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-	    cs_error(link->handle, RequestConfiguration, i);
-	    pcmcia_release_io(link->handle, &link->io);
-	    pcmcia_release_irq(link->handle, &link->irq);
+	    cs_error(link, RequestConfiguration, i);
+	    pcmcia_disable_device(link);
 	    break;
 	}
 
@@ -336,13 +309,12 @@
     strcpy(dev->node.dev_name, "A1");
     dev->node.major = 45;
     dev->node.minor = 0;
-    link->dev = &dev->node;
-    
-    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev_node = &dev->node;
+
     /* If any step failed, release any partially configured state */
     if (i != 0) {
 	avma1cs_release(link);
-	return;
+	return -ENODEV;
     }
 
     printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
@@ -357,10 +329,11 @@
     if (i < 0) {
     	printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
 	avma1cs_release(link);
-	return;
+	return -ENODEV;
     }
     dev->node.minor = i;
 
+    return 0;
 } /* avma1cs_config */
 
 /*======================================================================
@@ -371,47 +344,18 @@
     
 ======================================================================*/
 
-static void avma1cs_release(dev_link_t *link)
+static void avma1cs_release(struct pcmcia_device *link)
 {
-    local_info_t *local = link->priv;
+	local_info_t *local = link->priv;
 
-    DEBUG(0, "avma1cs_release(0x%p)\n", link);
+	DEBUG(0, "avma1cs_release(0x%p)\n", link);
 
-    /* no unregister function with hisax */
-    HiSax_closecard(local->node.minor);
+	/* now unregister function with hisax */
+	HiSax_closecard(local->node.minor);
 
-    /* Unlink the device chain */
-    link->dev = NULL;
-    
-    /* Don't bother checking to see if these succeed or not */
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 } /* avma1cs_release */
 
-static int avma1cs_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int avma1cs_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
-}
-
 
 static struct pcmcia_device_id avma1cs_ids[] = {
 	PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
@@ -425,13 +369,11 @@
 	.drv		= {
 		.name	= "avma1_cs",
 	},
-	.probe		= avma1cs_attach,
+	.probe		= avma1cs_probe,
 	.remove		= avma1cs_detach,
 	.id_table	= avma1cs_ids,
-	.suspend	= avma1cs_suspend,
-	.resume		= avma1cs_resume,
 };
- 
+
 /*====================================================================*/
 
 static int __init init_avma1_cs(void)
diff -urN oldtree/drivers/isdn/hisax/elsa_cs.c newtree/drivers/isdn/hisax/elsa_cs.c
--- oldtree/drivers/isdn/hisax/elsa_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/isdn/hisax/elsa_cs.c	2006-04-01 05:35:44.247385250 -0500
@@ -94,8 +94,8 @@
    handler.
 */
 
-static void elsa_cs_config(dev_link_t *link);
-static void elsa_cs_release(dev_link_t *link);
+static int elsa_cs_config(struct pcmcia_device *link);
+static void elsa_cs_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -111,7 +111,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
    In this case, we also provide a flag to indicate if a device is
@@ -121,7 +121,7 @@
 */
 
 typedef struct local_info_t {
-    dev_link_t          link;
+	struct pcmcia_device	*p_dev;
     dev_node_t          node;
     int                 busy;
     int			cardnr;
@@ -139,9 +139,8 @@
 
 ======================================================================*/
 
-static int elsa_cs_attach(struct pcmcia_device *p_dev)
+static int elsa_cs_probe(struct pcmcia_device *link)
 {
-    dev_link_t *link;
     local_info_t *local;
 
     DEBUG(0, "elsa_cs_attach()\n");
@@ -150,8 +149,11 @@
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
     if (!local) return -ENOMEM;
     memset(local, 0, sizeof(local_info_t));
+
+    local->p_dev = link;
+    link->priv = local;
+
     local->cardnr = -1;
-    link = &local->link; link->priv = local;
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
@@ -170,16 +172,9 @@
     link->io.IOAddrLines = 3;
 
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    elsa_cs_config(link);
-
-    return 0;
+    return elsa_cs_config(link);
 } /* elsa_cs_attach */
 
 /*======================================================================
@@ -191,20 +186,16 @@
 
 ======================================================================*/
 
-static void elsa_cs_detach(struct pcmcia_device *p_dev)
+static void elsa_cs_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-    local_info_t *info = link->priv;
+	local_info_t *info = link->priv;
 
-    DEBUG(0, "elsa_cs_detach(0x%p)\n", link);
+	DEBUG(0, "elsa_cs_detach(0x%p)\n", link);
 
-    if (link->state & DEV_CONFIG) {
-	    info->busy = 1;
-	    elsa_cs_release(link);
-    }
-
-    kfree(info);
+	info->busy = 1;
+	elsa_cs_release(link);
 
+	kfree(info);
 } /* elsa_cs_detach */
 
 /*======================================================================
@@ -214,7 +205,7 @@
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(client_handle_t handle, tuple_t *tuple,
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_tuple_data(handle, tuple);
@@ -222,7 +213,7 @@
     return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_first_tuple(handle, tuple);
@@ -230,7 +221,7 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_next_tuple(handle, tuple);
@@ -238,9 +229,8 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static void elsa_cs_config(dev_link_t *link)
+static int elsa_cs_config(struct pcmcia_device *link)
 {
-    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     local_info_t *dev;
@@ -250,7 +240,6 @@
     IsdnCard_t icard;
 
     DEBUG(0, "elsa_config(0x%p)\n", link);
-    handle = link->handle;
     dev = link->priv;
 
     /*
@@ -262,7 +251,7 @@
     tuple.TupleDataMax = 255;
     tuple.TupleOffset = 0;
     tuple.Attributes = 0;
-    i = first_tuple(handle, &tuple, &parse);
+    i = first_tuple(link, &tuple, &parse);
     if (i != CS_SUCCESS) {
         last_fn = ParseTuple;
 	goto cs_failed;
@@ -270,32 +259,29 @@
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(handle, &tuple, &parse);
+    i = first_tuple(link, &tuple, &parse);
     while (i == CS_SUCCESS) {
         if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
             printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
             link->conf.ConfigIndex = cf->index;
             link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link->handle, &link->io);
+            i = pcmcia_request_io(link, &link->io);
             if (i == CS_SUCCESS) break;
         } else {
           printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
           link->conf.ConfigIndex = cf->index;
           for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
             link->io.BasePort1 = j;
-            i = pcmcia_request_io(link->handle, &link->io);
+            i = pcmcia_request_io(link, &link->io);
             if (i == CS_SUCCESS) break;
           }
           break;
         }
-        i = next_tuple(handle, &tuple, &parse);
+        i = next_tuple(link, &tuple, &parse);
     }
 
     if (i != CS_SUCCESS) {
@@ -303,14 +289,14 @@
 	goto cs_failed;
     }
 
-    i = pcmcia_request_irq(link->handle, &link->irq);
+    i = pcmcia_request_irq(link, &link->irq);
     if (i != CS_SUCCESS) {
         link->irq.AssignedIRQ = 0;
 	last_fn = RequestIRQ;
         goto cs_failed;
     }
 
-    i = pcmcia_request_configuration(link->handle, &link->conf);
+    i = pcmcia_request_configuration(link, &link->conf);
     if (i != CS_SUCCESS) {
       last_fn = RequestConfiguration;
       goto cs_failed;
@@ -321,14 +307,11 @@
     sprintf(dev->node.dev_name, "elsa");
     dev->node.major = dev->node.minor = 0x0;
 
-    link->dev = &dev->node;
+    link->dev_node = &dev->node;
 
     /* Finally, report what we've done */
-    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-           dev->node.dev_name, link->conf.ConfigIndex,
-           link->conf.Vcc/10, link->conf.Vcc%10);
-    if (link->conf.Vpp1)
-        printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    printk(KERN_INFO "%s: index 0x%02x: ",
+           dev->node.dev_name, link->conf.ConfigIndex);
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
         printk(", irq %d", link->irq.AssignedIRQ);
     if (link->io.NumPorts1)
@@ -339,8 +322,6 @@
                link->io.BasePort2+link->io.NumPorts2-1);
     printk("\n");
 
-    link->state &= ~DEV_CONFIG_PENDING;
-
     icard.para[0] = link->irq.AssignedIRQ;
     icard.para[1] = link->io.BasePort1;
     icard.protocol = protocol;
@@ -354,10 +335,11 @@
     } else
     	((local_info_t*)link->priv)->cardnr = i;
 
-    return;
+    return 0;
 cs_failed:
-    cs_error(link->handle, last_fn, i);
+    cs_error(link, last_fn, i);
     elsa_cs_release(link);
+    return -ENODEV;
 } /* elsa_cs_config */
 
 /*======================================================================
@@ -368,7 +350,7 @@
 
 ======================================================================*/
 
-static void elsa_cs_release(dev_link_t *link)
+static void elsa_cs_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
 
@@ -380,39 +362,23 @@
 	    HiSax_closecard(local->cardnr);
 	}
     }
-    /* Unlink the device chain */
-    link->dev = NULL;
 
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win)
-        pcmcia_release_window(link->win);
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
+    pcmcia_disable_device(link);
 } /* elsa_cs_release */
 
-static int elsa_suspend(struct pcmcia_device *p_dev)
+static int elsa_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
         dev->busy = 1;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 
 	return 0;
 }
 
-static int elsa_resume(struct pcmcia_device *p_dev)
+static int elsa_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
         dev->busy = 0;
 
 	return 0;
@@ -430,7 +396,7 @@
 	.drv		= {
 		.name	= "elsa_cs",
 	},
-	.probe		= elsa_cs_attach,
+	.probe		= elsa_cs_probe,
 	.remove		= elsa_cs_detach,
 	.id_table	= elsa_ids,
 	.suspend	= elsa_suspend,
diff -urN oldtree/drivers/isdn/hisax/sedlbauer_cs.c newtree/drivers/isdn/hisax/sedlbauer_cs.c
--- oldtree/drivers/isdn/hisax/sedlbauer_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/isdn/hisax/sedlbauer_cs.c	2006-04-01 05:35:44.251385500 -0500
@@ -95,8 +95,8 @@
    event handler. 
 */
 
-static void sedlbauer_config(dev_link_t *link);
-static void sedlbauer_release(dev_link_t *link);
+static int sedlbauer_config(struct pcmcia_device *link);
+static void sedlbauer_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -119,7 +119,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
 
@@ -130,7 +130,7 @@
 */
    
 typedef struct local_info_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t		node;
     int			stop;
     int			cardnr;
@@ -148,11 +148,10 @@
     
 ======================================================================*/
 
-static int sedlbauer_attach(struct pcmcia_device *p_dev)
+static int sedlbauer_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
-    dev_link_t *link;
-    
+
     DEBUG(0, "sedlbauer_attach()\n");
 
     /* Allocate space for private device-specific data */
@@ -160,8 +159,10 @@
     if (!local) return -ENOMEM;
     memset(local, 0, sizeof(local_info_t));
     local->cardnr = -1;
-    link = &local->link; link->priv = local;
-    
+
+    local->p_dev = link;
+    link->priv = local;
+
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
@@ -182,18 +183,10 @@
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
     link->io.IOAddrLines = 3;
 
-
     link->conf.Attributes = 0;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    sedlbauer_config(link);
-
-    return 0;
+    return sedlbauer_config(link);
 } /* sedlbauer_attach */
 
 /*======================================================================
@@ -205,19 +198,15 @@
 
 ======================================================================*/
 
-static void sedlbauer_detach(struct pcmcia_device *p_dev)
+static void sedlbauer_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
-    DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
+	DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
 
-    if (link->state & DEV_CONFIG) {
-	    ((local_info_t *)link->priv)->stop = 1;
-	    sedlbauer_release(link);
-    }
+	((local_info_t *)link->priv)->stop = 1;
+	sedlbauer_release(link);
 
-    /* This points to the parent local_info_t struct */
-    kfree(link->priv);
+	/* This points to the parent local_info_t struct */
+	kfree(link->priv);
 } /* sedlbauer_detach */
 
 /*======================================================================
@@ -230,9 +219,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void sedlbauer_config(dev_link_t *link)
+static int sedlbauer_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     local_info_t *dev = link->priv;
     tuple_t tuple;
     cisparse_t parse;
@@ -254,18 +242,13 @@
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
-    /* Look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
+    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
 
     /*
       In this loop, we scan the CIS for configuration table entries,
@@ -280,12 +263,12 @@
       will only use the CIS to fill in implementation-defined details.
     */
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (1) {
 	cistpl_cftable_entry_t dflt = { 0 };
 	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 	    goto next_entry;
 
 	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
@@ -309,10 +292,10 @@
 	}
 	    
 	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
+	    link->conf.Vpp =
 		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
 	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
+	    link->conf.Vpp =
 		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
 	
 	/* Do we need to allocate an interrupt? */
@@ -339,13 +322,13 @@
 		link->io.NumPorts2 = io->win[1].len;
 	    }
 	    /* This reserves IO space but doesn't actually enable it */
-	    if (pcmcia_request_io(link->handle, &link->io) != 0)
+	    if (pcmcia_request_io(link, &link->io) != 0)
 		goto next_entry;
 	}
 
 	/*
 	  Now set up a common memory window, if needed.  There is room
-	  in the dev_link_t structure for one memory window handle,
+	  in the struct pcmcia_device structure for one memory window handle,
 	  but if the base addresses need to be saved, or if multiple
 	  windows are needed, the info should go in the private data
 	  structure for this device.
@@ -366,7 +349,7 @@
                 req.Size = 0x1000;
 */
 	    req.AccessSpeed = 0;
-	    if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
+	    if (pcmcia_request_window(&link, &req, &link->win) != 0)
 		goto next_entry;
 	    map.Page = 0; map.CardOffset = mem->win[0].card_addr;
 	    if (pcmcia_map_mem_page(link->win, &map) != 0)
@@ -374,29 +357,25 @@
 	}
 	/* If we got this far, we're cool! */
 	break;
-	
+
     next_entry:
-/* new in dummy.cs 2001/01/28 MN 
-        if (link->io.NumPorts1)
-           pcmcia_release_io(link->handle, &link->io);
-*/
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
     }
-    
+
     /*
        Allocate an interrupt line.  Note that this does not assign a
        handler to the interrupt, unless the 'Handler' member of the
        irq structure is initialized.
     */
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 	
     /*
        This actually configures the PCMCIA socket -- setting up
        the I/O windows and the interrupt mapping, and putting the
        card and host interface into "Memory and IO" mode.
     */
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     /*
       At this point, the dev_node_t structure(s) need to be
@@ -404,14 +383,13 @@
     */
     sprintf(dev->node.dev_name, "sedlbauer");
     dev->node.major = dev->node.minor = 0;
-    link->dev = &dev->node;
+    link->dev_node = &dev->node;
 
     /* Finally, report what we've done */
-    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-	   dev->node.dev_name, link->conf.ConfigIndex,
-	   link->conf.Vcc/10, link->conf.Vcc%10);
-    if (link->conf.Vpp1)
-	printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    printk(KERN_INFO "%s: index 0x%02x:",
+	   dev->node.dev_name, link->conf.ConfigIndex);
+    if (link->conf.Vpp)
+	printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
 	printk(", irq %d", link->irq.AssignedIRQ);
     if (link->io.NumPorts1)
@@ -424,8 +402,6 @@
 	printk(", mem 0x%06lx-0x%06lx", req.Base,
 	       req.Base+req.Size-1);
     printk("\n");
-    
-    link->state &= ~DEV_CONFIG_PENDING;
 
     icard.para[0] = link->irq.AssignedIRQ;
     icard.para[1] = link->io.BasePort1;
@@ -437,14 +413,16 @@
     	printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
     		last_ret, link->io.BasePort1);
     	sedlbauer_release(link);
+	return -ENODEV;
     } else
     	((local_info_t*)link->priv)->cardnr = last_ret;
 
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
     sedlbauer_release(link);
+    return -ENODEV;
 
 } /* sedlbauer_config */
 
@@ -456,7 +434,7 @@
     
 ======================================================================*/
 
-static void sedlbauer_release(dev_link_t *link)
+static void sedlbauer_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
     DEBUG(0, "sedlbauer_release(0x%p)\n", link);
@@ -467,46 +445,23 @@
 	    HiSax_closecard(local->cardnr);
 	}
     }
-    /* Unlink the device chain */
-    link->dev = NULL;
 
-    /*
-      In a normal driver, additional code may be needed to release
-      other kernel data structures associated with this device. 
-    */
-    
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win)
-	pcmcia_release_window(link->win);
-    pcmcia_release_configuration(link->handle);
-    if (link->io.NumPorts1)
-	pcmcia_release_io(link->handle, &link->io);
-    if (link->irq.AssignedIRQ)
-	pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
+    pcmcia_disable_device(link);
 } /* sedlbauer_release */
 
-static int sedlbauer_suspend(struct pcmcia_device *p_dev)
+static int sedlbauer_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
 	dev->stop = 1;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 
 	return 0;
 }
 
-static int sedlbauer_resume(struct pcmcia_device *p_dev)
+static int sedlbauer_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
 	dev->stop = 0;
 
 	return 0;
@@ -530,7 +485,7 @@
 	.drv		= {
 		.name	= "sedlbauer_cs",
 	},
-	.probe		= sedlbauer_attach,
+	.probe		= sedlbauer_probe,
 	.remove		= sedlbauer_detach,
 	.id_table	= sedlbauer_ids,
 	.suspend	= sedlbauer_suspend,
diff -urN oldtree/drivers/isdn/hisax/teles_cs.c newtree/drivers/isdn/hisax/teles_cs.c
--- oldtree/drivers/isdn/hisax/teles_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/isdn/hisax/teles_cs.c	2006-04-01 05:35:44.251385500 -0500
@@ -75,8 +75,8 @@
    handler.
 */
 
-static void teles_cs_config(dev_link_t *link);
-static void teles_cs_release(dev_link_t *link);
+static int teles_cs_config(struct pcmcia_device *link);
+static void teles_cs_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -89,10 +89,10 @@
 /*
    A linked list of "instances" of the teles_cs device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
+   by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
+   memory card driver uses an array of struct pcmcia_device pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -102,7 +102,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
    In this case, we also provide a flag to indicate if a device is
@@ -112,7 +112,7 @@
 */
 
 typedef struct local_info_t {
-    dev_link_t          link;
+	struct pcmcia_device	*p_dev;
     dev_node_t          node;
     int                 busy;
     int			cardnr;
@@ -130,9 +130,8 @@
 
 ======================================================================*/
 
-static int teles_attach(struct pcmcia_device *p_dev)
+static int teles_probe(struct pcmcia_device *link)
 {
-    dev_link_t *link;
     local_info_t *local;
 
     DEBUG(0, "teles_attach()\n");
@@ -142,7 +141,9 @@
     if (!local) return -ENOMEM;
     memset(local, 0, sizeof(local_info_t));
     local->cardnr = -1;
-    link = &local->link; link->priv = local;
+
+    local->p_dev = link;
+    link->priv = local;
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
@@ -161,16 +162,9 @@
     link->io.IOAddrLines = 5;
 
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    teles_cs_config(link);
-
-    return 0;
+    return teles_cs_config(link);
 } /* teles_attach */
 
 /*======================================================================
@@ -182,20 +176,16 @@
 
 ======================================================================*/
 
-static void teles_detach(struct pcmcia_device *p_dev)
+static void teles_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-    local_info_t *info = link->priv;
-
-    DEBUG(0, "teles_detach(0x%p)\n", link);
+	local_info_t *info = link->priv;
 
-    if (link->state & DEV_CONFIG) {
-	    info->busy = 1;
-	    teles_cs_release(link);
-    }
+	DEBUG(0, "teles_detach(0x%p)\n", link);
 
-    kfree(info);
+	info->busy = 1;
+	teles_cs_release(link);
 
+	kfree(info);
 } /* teles_detach */
 
 /*======================================================================
@@ -205,7 +195,7 @@
     device available to the system.
 
 ======================================================================*/
-static int get_tuple(client_handle_t handle, tuple_t *tuple,
+static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_tuple_data(handle, tuple);
@@ -213,7 +203,7 @@
     return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_first_tuple(handle, tuple);
@@ -221,7 +211,7 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
                      cisparse_t *parse)
 {
     int i = pcmcia_get_next_tuple(handle, tuple);
@@ -229,9 +219,8 @@
     return get_tuple(handle, tuple, parse);
 }
 
-static void teles_cs_config(dev_link_t *link)
+static int teles_cs_config(struct pcmcia_device *link)
 {
-    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     local_info_t *dev;
@@ -241,7 +230,6 @@
     IsdnCard_t icard;
 
     DEBUG(0, "teles_config(0x%p)\n", link);
-    handle = link->handle;
     dev = link->priv;
 
     /*
@@ -253,7 +241,7 @@
     tuple.TupleDataMax = 255;
     tuple.TupleOffset = 0;
     tuple.Attributes = 0;
-    i = first_tuple(handle, &tuple, &parse);
+    i = first_tuple(link, &tuple, &parse);
     if (i != CS_SUCCESS) {
         last_fn = ParseTuple;
 	goto cs_failed;
@@ -261,32 +249,29 @@
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    i = first_tuple(handle, &tuple, &parse);
+    i = first_tuple(link, &tuple, &parse);
     while (i == CS_SUCCESS) {
         if ( (cf->io.nwin > 0) && cf->io.win[0].base) {
             printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
             link->conf.ConfigIndex = cf->index;
             link->io.BasePort1 = cf->io.win[0].base;
-            i = pcmcia_request_io(link->handle, &link->io);
+            i = pcmcia_request_io(link, &link->io);
             if (i == CS_SUCCESS) break;
         } else {
           printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
           link->conf.ConfigIndex = cf->index;
           for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) {
             link->io.BasePort1 = j;
-            i = pcmcia_request_io(link->handle, &link->io);
+            i = pcmcia_request_io(link, &link->io);
             if (i == CS_SUCCESS) break;
           }
           break;
         }
-        i = next_tuple(handle, &tuple, &parse);
+        i = next_tuple(link, &tuple, &parse);
     }
 
     if (i != CS_SUCCESS) {
@@ -294,14 +279,14 @@
 	goto cs_failed;
     }
 
-    i = pcmcia_request_irq(link->handle, &link->irq);
+    i = pcmcia_request_irq(link, &link->irq);
     if (i != CS_SUCCESS) {
         link->irq.AssignedIRQ = 0;
 	last_fn = RequestIRQ;
         goto cs_failed;
     }
 
-    i = pcmcia_request_configuration(link->handle, &link->conf);
+    i = pcmcia_request_configuration(link, &link->conf);
     if (i != CS_SUCCESS) {
       last_fn = RequestConfiguration;
       goto cs_failed;
@@ -312,14 +297,11 @@
     sprintf(dev->node.dev_name, "teles");
     dev->node.major = dev->node.minor = 0x0;
 
-    link->dev = &dev->node;
+    link->dev_node = &dev->node;
 
     /* Finally, report what we've done */
-    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-           dev->node.dev_name, link->conf.ConfigIndex,
-           link->conf.Vcc/10, link->conf.Vcc%10);
-    if (link->conf.Vpp1)
-        printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    printk(KERN_INFO "%s: index 0x%02x:",
+           dev->node.dev_name, link->conf.ConfigIndex);
     if (link->conf.Attributes & CONF_ENABLE_IRQ)
         printk(", irq %d", link->irq.AssignedIRQ);
     if (link->io.NumPorts1)
@@ -330,8 +312,6 @@
                link->io.BasePort2+link->io.NumPorts2-1);
     printk("\n");
 
-    link->state &= ~DEV_CONFIG_PENDING;
-
     icard.para[0] = link->irq.AssignedIRQ;
     icard.para[1] = link->io.BasePort1;
     icard.protocol = protocol;
@@ -342,13 +322,16 @@
     	printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
     		i, link->io.BasePort1);
     	teles_cs_release(link);
-    } else
-    	((local_info_t*)link->priv)->cardnr = i;
+	return -ENODEV;
+    }
+
+    ((local_info_t*)link->priv)->cardnr = i;
+    return 0;
 
-    return;
 cs_failed:
-    cs_error(link->handle, last_fn, i);
+    cs_error(link, last_fn, i);
     teles_cs_release(link);
+    return -ENODEV;
 } /* teles_cs_config */
 
 /*======================================================================
@@ -359,7 +342,7 @@
 
 ======================================================================*/
 
-static void teles_cs_release(dev_link_t *link)
+static void teles_cs_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
 
@@ -371,39 +354,23 @@
 	    HiSax_closecard(local->cardnr);
 	}
     }
-    /* Unlink the device chain */
-    link->dev = NULL;
 
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win)
-        pcmcia_release_window(link->win);
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
+    pcmcia_disable_device(link);
 } /* teles_cs_release */
 
-static int teles_suspend(struct pcmcia_device *p_dev)
+static int teles_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
         dev->busy = 1;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 
 	return 0;
 }
 
-static int teles_resume(struct pcmcia_device *p_dev)
+static int teles_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
         dev->busy = 0;
 
 	return 0;
@@ -421,7 +388,7 @@
 	.drv		= {
 		.name	= "teles_cs",
 	},
-	.probe		= teles_attach,
+	.probe		= teles_probe,
 	.remove		= teles_detach,
 	.id_table       = teles_ids,
 	.suspend	= teles_suspend,
diff -urN oldtree/drivers/leds/Kconfig newtree/drivers/leds/Kconfig
--- oldtree/drivers/leds/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/Kconfig	2006-04-01 05:35:57.424208750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/Makefile	2006-04-01 05:35:57.424208750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/led-class.c	2006-04-01 05:35:57.320202250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/led-core.c	2006-04-01 05:35:57.300201000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/led-triggers.c	2006-04-01 05:35:57.340203500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds-corgi.c	2006-04-01 05:35:57.372205500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds-ixp4xx-gpio.c	2006-04-01 05:35:57.404207500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds-locomo.c	2006-04-01 05:35:57.388206500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds-spitz.c	2006-04-01 05:35:57.372205500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds-tosa.c	2006-04-01 05:35:57.424208750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/leds.h	2006-04-01 05:35:57.320202250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/leds/ledtrig-timer.c	2006-04-01 05:35:57.336203250 -0500
@@ -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/via-pmu68k.c newtree/drivers/macintosh/via-pmu68k.c
--- oldtree/drivers/macintosh/via-pmu68k.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/macintosh/via-pmu68k.c	2006-04-01 05:36:15.305326250 -0500
@@ -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/media/dvb/frontends/Kconfig newtree/drivers/media/dvb/frontends/Kconfig
--- oldtree/drivers/media/dvb/frontends/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/media/dvb/frontends/Kconfig	2006-04-01 05:36:15.373330500 -0500
@@ -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/ttpci/Kconfig newtree/drivers/media/dvb/ttpci/Kconfig
--- oldtree/drivers/media/dvb/ttpci/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/media/dvb/ttpci/Kconfig	2006-04-01 05:36:15.373330500 -0500
@@ -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/ttusb-budget/Kconfig newtree/drivers/media/dvb/ttusb-budget/Kconfig
--- oldtree/drivers/media/dvb/ttusb-budget/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/media/dvb/ttusb-budget/Kconfig	2006-04-01 05:36:15.373330500 -0500
@@ -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/mtd/devices/blkmtd.c newtree/drivers/mtd/devices/blkmtd.c
--- oldtree/drivers/mtd/devices/blkmtd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/devices/blkmtd.c	2006-04-01 05:35:39.571093000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/devices/block2mtd.c	2006-04-01 05:35:39.571093000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/devices/doc2000.c	2006-04-01 05:35:39.571093000 -0500
@@ -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/maps/pcmciamtd.c newtree/drivers/mtd/maps/pcmciamtd.c
--- oldtree/drivers/mtd/maps/pcmciamtd.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/maps/pcmciamtd.c	2006-04-01 05:35:44.251385500 -0500
@@ -54,7 +54,7 @@
 #define MAX_PCMCIA_ADDR	0x4000000
 
 struct pcmciamtd_dev {
-	dev_link_t	link;		/* PCMCIA link */
+	struct pcmcia_device	*p_dev;
 	dev_node_t	node;		/* device node */
 	caddr_t		win_base;	/* ioremapped address of PCMCIA window */
 	unsigned int	win_size;	/* size of window */
@@ -111,8 +111,8 @@
 	memreq_t mrq;
 	int ret;
 
-	if(!(dev->link.state & DEV_PRESENT)) {
-		DEBUG(1, "device removed state = 0x%4.4X", dev->link.state);
+	if (!pcmcia_dev_present(dev->p_dev)) {
+		DEBUG(1, "device removed");
 		return 0;
 	}
 
@@ -122,7 +122,7 @@
 		      dev->offset, mrq.CardOffset);
 		mrq.Page = 0;
 		if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) {
-			cs_error(dev->link.handle, MapMemPage, ret);
+			cs_error(dev->p_dev, MapMemPage, ret);
 			return NULL;
 		}
 		dev->offset = mrq.CardOffset;
@@ -238,7 +238,7 @@
 
 /* read/write{8,16} copy_{from,to} routines with direct access */
 
-#define DEV_REMOVED(x)  (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
+#define DEV_REMOVED(x)  (!(pcmcia_dev_present(((struct pcmciamtd_dev *)map->map_priv_1)->p_dev)))
 
 static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
 {
@@ -319,7 +319,7 @@
 static void pcmciamtd_set_vpp(struct map_info *map, int on)
 {
 	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
-	dev_link_t *link = &dev->link;
+	struct pcmcia_device *link = dev->p_dev;
 	modconf_t mod;
 	int ret;
 
@@ -328,9 +328,9 @@
 	mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
 
 	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
-	ret = pcmcia_modify_configuration(link->handle, &mod);
+	ret = pcmcia_modify_configuration(link, &mod);
 	if(ret != CS_SUCCESS) {
-		cs_error(link->handle, ModifyConfiguration, ret);
+		cs_error(link, ModifyConfiguration, ret);
 	}
 }
 
@@ -340,7 +340,7 @@
  * still open, this will be postponed until it is closed.
  */
 
-static void pcmciamtd_release(dev_link_t *link)
+static void pcmciamtd_release(struct pcmcia_device *link)
 {
 	struct pcmciamtd_dev *dev = link->priv;
 
@@ -353,12 +353,11 @@
 		}
 		pcmcia_release_window(link->win);
 	}
-	pcmcia_release_configuration(link->handle);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
 
-static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, int *new_name)
 {
 	int rc;
 	tuple_t tuple;
@@ -371,16 +370,16 @@
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
 
-	rc = pcmcia_get_first_tuple(link->handle, &tuple);
+	rc = pcmcia_get_first_tuple(link, &tuple);
 	while(rc == CS_SUCCESS) {
-		rc = pcmcia_get_tuple_data(link->handle, &tuple);
+		rc = pcmcia_get_tuple_data(link, &tuple);
 		if(rc != CS_SUCCESS) {
-			cs_error(link->handle, GetTupleData, rc);
+			cs_error(link, GetTupleData, rc);
 			break;
 		}
-		rc = pcmcia_parse_tuple(link->handle, &tuple, &parse);
+		rc = pcmcia_parse_tuple(link, &tuple, &parse);
 		if(rc != CS_SUCCESS) {
-			cs_error(link->handle, ParseTuple, rc);
+			cs_error(link, ParseTuple, rc);
 			break;
 		}
 
@@ -451,7 +450,7 @@
 			DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
 		}
 
-		rc = pcmcia_get_next_tuple(link->handle, &tuple);
+		rc = pcmcia_get_next_tuple(link, &tuple);
 	}
 	if(!dev->pcmcia_map.size)
 		dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
@@ -488,7 +487,7 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void pcmciamtd_config(dev_link_t *link)
+static int pcmciamtd_config(struct pcmcia_device *link)
 {
 	struct pcmciamtd_dev *dev = link->priv;
 	struct mtd_info *mtd = NULL;
@@ -504,13 +503,10 @@
 
 	DEBUG(3, "link=0x%p", link);
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	DEBUG(2, "Validating CIS");
-	ret = pcmcia_validate_cis(link->handle, &cisinfo);
+	ret = pcmcia_validate_cis(link, &cisinfo);
 	if(ret != CS_SUCCESS) {
-		cs_error(link->handle, GetTupleData, ret);
+		cs_error(link, GetTupleData, ret);
 	} else {
 		DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
 	}
@@ -538,7 +534,7 @@
 	req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
 	req.Base = 0;
 	req.AccessSpeed = mem_speed;
-	link->win = (window_handle_t)link->handle;
+	link->win = (window_handle_t)link;
 	req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
 	dev->win_size = 0;
 
@@ -546,7 +542,7 @@
 		int ret;
 		DEBUG(2, "requesting window with size = %dKiB memspeed = %d",
 		      req.Size >> 10, req.AccessSpeed);
-		ret = pcmcia_request_window(&link->handle, &req, &link->win);
+		ret = pcmcia_request_window(&link, &req, &link->win);
 		DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
 		if(ret) {
 			req.Size >>= 1;
@@ -562,19 +558,19 @@
 	if(!dev->win_size) {
 		err("Cant allocate memory window");
 		pcmciamtd_release(link);
-		return;
+		return -ENODEV;
 	}
 	DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
 
 	/* Get write protect status */
-	CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status));
+	CS_CHECK(GetStatus, pcmcia_get_status(link, &status));
 	DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
 	      status.CardState, (unsigned long)link->win);
 	dev->win_base = ioremap(req.Base, req.Size);
 	if(!dev->win_base) {
 		err("ioremap(%lu, %u) failed", req.Base, req.Size);
 		pcmciamtd_release(link);
-		return;
+		return -ENODEV;
 	}
 	DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
 	      dev, req.Base, dev->win_base, req.Size);
@@ -584,17 +580,14 @@
 	dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
 
 	DEBUG(2, "Getting configuration");
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link->handle, &t));
+	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &t));
 	DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
 	dev->vpp = (vpp) ? vpp : t.Vpp1;
 	link->conf.Attributes = 0;
-	link->conf.Vcc = t.Vcc;
 	if(setvpp == 2) {
-		link->conf.Vpp1 = dev->vpp;
-		link->conf.Vpp2 = dev->vpp;
+		link->conf.Vpp = dev->vpp;
 	} else {
-		link->conf.Vpp1 = 0;
-		link->conf.Vpp2 = 0;
+		link->conf.Vpp = 0;
 	}
 
 	link->conf.IntType = INT_MEMORY;
@@ -606,9 +599,10 @@
 	link->conf.ConfigIndex = 0;
 	link->conf.Present = t.Present;
 	DEBUG(2, "Setting Configuration");
-	ret = pcmcia_request_configuration(link->handle, &link->conf);
+	ret = pcmcia_request_configuration(link, &link->conf);
 	if(ret != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, ret);
+		cs_error(link, RequestConfiguration, ret);
+		return -ENODEV;
 	}
 
 	if(mem_type == 1) {
@@ -629,7 +623,7 @@
 	if(!mtd) {
 		DEBUG(1, "Cant find an MTD");
 		pcmciamtd_release(link);
-		return;
+		return -ENODEV;
 	}
 
 	dev->mtd_info = mtd;
@@ -654,7 +648,6 @@
 	   use the faster non-remapping read/write functions */
 	if(mtd->size <= dev->win_size) {
 		DEBUG(1, "Using non remapping memory functions");
-		dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
 		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
 		if (dev->pcmcia_map.bankwidth == 1) {
 			dev->pcmcia_map.read = pcmcia_read8;
@@ -672,19 +665,18 @@
 		dev->mtd_info = NULL;
 		err("Couldnt register MTD device");
 		pcmciamtd_release(link);
-		return;
+		return -ENODEV;
 	}
 	snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index);
 	info("mtd%d: %s", mtd->index, mtd->name);
-	link->state &= ~DEV_CONFIG_PENDING;
-	link->dev = &dev->node;
-	return;
+	link->dev_node = &dev->node;
+	return 0;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	err("CS Error, exiting");
 	pcmciamtd_release(link);
-	return;
+	return -ENODEV;
 }
 
 
@@ -713,21 +705,18 @@
  * when the device is released.
  */
 
-static void pcmciamtd_detach(struct pcmcia_device *p_dev)
+static void pcmciamtd_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
+	struct pcmciamtd_dev *dev = link->priv;
 
 	DEBUG(3, "link=0x%p", link);
 
-	if(link->state & DEV_CONFIG) {
-		struct pcmciamtd_dev *dev = link->priv;
-		if(dev->mtd_info) {
-			del_mtd_device(dev->mtd_info);
-			info("mtd%d: Removed", dev->mtd_info->index);
-		}
-
-		pcmciamtd_release(link);
+	if(dev->mtd_info) {
+		del_mtd_device(dev->mtd_info);
+		info("mtd%d: Removed", dev->mtd_info->index);
 	}
+
+	pcmciamtd_release(link);
 }
 
 
@@ -736,10 +725,9 @@
  * with Card Services.
  */
 
-static int pcmciamtd_attach(struct pcmcia_device *p_dev)
+static int pcmciamtd_probe(struct pcmcia_device *link)
 {
 	struct pcmciamtd_dev *dev;
-	dev_link_t *link;
 
 	/* Create new memory card device */
 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
@@ -747,20 +735,13 @@
 	DEBUG(1, "dev=0x%p", dev);
 
 	memset(dev, 0, sizeof(*dev));
-	link = &dev->link;
+	dev->p_dev = link;
 	link->priv = dev;
 
 	link->conf.Attributes = 0;
 	link->conf.IntType = INT_MEMORY;
 
-	link->next = NULL;
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	pcmciamtd_config(link);
-
-	return 0;
+	return pcmciamtd_config(link);
 }
 
 static struct pcmcia_device_id pcmciamtd_ids[] = {
@@ -794,7 +775,7 @@
 	.drv		= {
 		.name	= "pcmciamtd"
 	},
-	.probe		= pcmciamtd_attach,
+	.probe		= pcmciamtd_probe,
 	.remove		= pcmciamtd_detach,
 	.owner		= THIS_MODULE,
 	.id_table	= pcmciamtd_ids,
diff -urN oldtree/drivers/mtd/mtd_blkdevs.c newtree/drivers/mtd/mtd_blkdevs.c
--- oldtree/drivers/mtd/mtd_blkdevs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/mtd_blkdevs.c	2006-04-01 05:35:39.571093000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/mtdblock.c	2006-04-01 05:35:39.575093250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/mtdcore.c	2006-04-01 05:35:39.575093250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/mtd/nand/nand_base.c	2006-04-01 05:35:57.440209750 -0500
@@ -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/Kconfig newtree/drivers/net/Kconfig
--- oldtree/drivers/net/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/Kconfig	2006-04-01 05:36:15.281324750 -0500
@@ -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
diff -urN oldtree/drivers/net/pcmcia/3c574_cs.c newtree/drivers/net/pcmcia/3c574_cs.c
--- oldtree/drivers/net/pcmcia/3c574_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/3c574_cs.c	2006-04-01 05:35:44.251385500 -0500
@@ -204,7 +204,7 @@
 #define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
 
 struct el3_private {
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 	struct net_device_stats stats;
 	u16 advertising, partner;		/* NWay media advertisement */
@@ -225,8 +225,8 @@
 
 /* Index of functions. */
 
-static void tc574_config(dev_link_t *link);
-static void tc574_release(dev_link_t *link);
+static int tc574_config(struct pcmcia_device *link);
+static void tc574_release(struct pcmcia_device *link);
 
 static void mdio_sync(kio_addr_t ioaddr, int bits);
 static int mdio_read(kio_addr_t ioaddr, int phy_id, int location);
@@ -256,10 +256,9 @@
 	with Card Services.
 */
 
-static int tc574_attach(struct pcmcia_device *p_dev)
+static int tc574_probe(struct pcmcia_device *link)
 {
 	struct el3_private *lp;
-	dev_link_t *link;
 	struct net_device *dev;
 
 	DEBUG(0, "3c574_attach()\n");
@@ -269,8 +268,8 @@
 	if (!dev)
 		return -ENOMEM;
 	lp = netdev_priv(dev);
-	link = &lp->link;
 	link->priv = dev;
+	lp->p_dev = link;
 
 	spin_lock_init(&lp->window_lock);
 	link->io.NumPorts1 = 32;
@@ -280,7 +279,6 @@
 	link->irq.Handler = &el3_interrupt;
 	link->irq.Instance = dev;
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	link->conf.ConfigIndex = 1;
 	link->conf.Present = PRESENT_OPTION;
@@ -298,13 +296,7 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 #endif
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	tc574_config(link);
-
-	return 0;
+	return tc574_config(link);
 } /* tc574_attach */
 
 /*
@@ -316,18 +308,16 @@
 
 */
 
-static void tc574_detach(struct pcmcia_device *p_dev)
+static void tc574_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
 	DEBUG(0, "3c574_detach(0x%p)\n", link);
 
-	if (link->dev)
+	if (link->dev_node)
 		unregister_netdev(dev);
 
-	if (link->state & DEV_CONFIG)
-		tc574_release(link);
+	tc574_release(link);
 
 	free_netdev(dev);
 } /* tc574_detach */
@@ -343,9 +333,8 @@
 
 static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 
-static void tc574_config(dev_link_t *link)
+static int tc574_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	struct net_device *dev = link->priv;
 	struct el3_private *lp = netdev_priv(dev);
 	tuple_t tuple;
@@ -363,30 +352,27 @@
 
 	tuple.Attributes = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	tuple.TupleData = (cisdata_t *)buf;
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	link->io.IOAddrLines = 16;
 	for (i = j = 0; j < 0x400; j += 0x20) {
 		link->io.BasePort1 = j ^ 0x300;
-		i = pcmcia_request_io(link->handle, &link->io);
+		i = pcmcia_request_io(link, &link->io);
 		if (i == CS_SUCCESS) break;
 	}
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
@@ -397,8 +383,8 @@
 	   the hardware address.  The future products may include a modem chip
 	   and put the address in the CIS. */
 	tuple.DesiredTuple = 0x88;
-	if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) {
-		pcmcia_get_tuple_data(handle, &tuple);
+	if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+		pcmcia_get_tuple_data(link, &tuple);
 		for (i = 0; i < 3; i++)
 			phys_addr[i] = htons(buf[i]);
 	} else {
@@ -412,9 +398,9 @@
 		}
 	}
 	tuple.DesiredTuple = CISTPL_VERS_1;
-	if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS &&
-		pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS &&
-		pcmcia_parse_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+	if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS &&
+		pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS &&
+		pcmcia_parse_tuple(link, &tuple, &parse) == CS_SUCCESS) {
 		cardname = parse.version_1.str + parse.version_1.ofs[1];
 	} else
 		cardname = "3Com 3c574";
@@ -473,13 +459,12 @@
 		}
 	}
 
-	link->state &= ~DEV_CONFIG_PENDING;
-	link->dev = &lp->node;
-	SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+	link->dev_node = &lp->node;
+	SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
 	if (register_netdev(dev) != 0) {
 		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
-		link->dev = NULL;
+		link->dev_node = NULL;
 		goto failed;
 	}
 
@@ -493,13 +478,13 @@
 		   8 << config.u.ram_size, ram_split[config.u.ram_split],
 		   config.u.autoselect ? "autoselect " : "");
 
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 failed:
 	tc574_release(link);
-	return;
+	return -ENODEV;
 
 } /* tc574_config */
 
@@ -509,44 +494,28 @@
 	still open, this will be postponed until it is closed.
 */
 
-static void tc574_release(dev_link_t *link)
+static void tc574_release(struct pcmcia_device *link)
 {
-	DEBUG(0, "3c574_release(0x%p)\n", link);
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int tc574_suspend(struct pcmcia_device *p_dev)
+static int tc574_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int tc574_resume(struct pcmcia_device *p_dev)
+static int tc574_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			tc574_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		tc574_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -757,9 +726,9 @@
 static int el3_open(struct net_device *dev)
 {
 	struct el3_private *lp = netdev_priv(dev);
-	dev_link_t *link = &lp->link;
+	struct pcmcia_device *link = lp->p_dev;
 
-	if (!DEV_OK(link))
+	if (!pcmcia_dev_present(link))
 		return -ENODEV;
 	
 	link->open++;
@@ -1203,11 +1172,11 @@
 {
 	kio_addr_t ioaddr = dev->base_addr;
 	struct el3_private *lp = netdev_priv(dev);
-	dev_link_t *link = &lp->link;
+	struct pcmcia_device *link = lp->p_dev;
 
 	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
 	
-	if (DEV_OK(link)) {
+	if (pcmcia_dev_present(link)) {
 		unsigned long flags;
 
 		/* Turn off statistics ASAP.  We update lp->stats below. */
@@ -1246,7 +1215,7 @@
 	.drv		= {
 		.name	= "3c574_cs",
 	},
-	.probe		= tc574_attach,
+	.probe		= tc574_probe,
 	.remove		= tc574_detach,
 	.id_table       = tc574_ids,
 	.suspend	= tc574_suspend,
diff -urN oldtree/drivers/net/pcmcia/3c589_cs.c newtree/drivers/net/pcmcia/3c589_cs.c
--- oldtree/drivers/net/pcmcia/3c589_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/3c589_cs.c	2006-04-01 05:35:44.255385750 -0500
@@ -104,7 +104,7 @@
 #define TX_TIMEOUT	((400*HZ)/1000)
 
 struct el3_private {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t 		node;
     struct net_device_stats stats;
     /* For transceiver monitoring */
@@ -141,8 +141,8 @@
 
 /*====================================================================*/
 
-static void tc589_config(dev_link_t *link);
-static void tc589_release(dev_link_t *link);
+static int tc589_config(struct pcmcia_device *link);
+static void tc589_release(struct pcmcia_device *link);
 
 static u16 read_eeprom(kio_addr_t ioaddr, int index);
 static void tc589_reset(struct net_device *dev);
@@ -169,10 +169,9 @@
 
 ======================================================================*/
 
-static int tc589_attach(struct pcmcia_device *p_dev)
+static int tc589_probe(struct pcmcia_device *link)
 {
     struct el3_private *lp;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "3c589_attach()\n");
@@ -182,8 +181,8 @@
     if (!dev)
 	 return -ENOMEM;
     lp = netdev_priv(dev);
-    link = &lp->link;
     link->priv = dev;
+    lp->p_dev = link;
 
     spin_lock_init(&lp->lock);
     link->io.NumPorts1 = 16;
@@ -193,7 +192,6 @@
     link->irq.Handler = &el3_interrupt;
     link->irq.Instance = dev;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
@@ -212,13 +210,7 @@
 #endif
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    tc589_config(link);
-
-    return 0;
+    return tc589_config(link);
 } /* tc589_attach */
 
 /*======================================================================
@@ -230,18 +222,16 @@
 
 ======================================================================*/
 
-static void tc589_detach(struct pcmcia_device *p_dev)
+static void tc589_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "3c589_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	tc589_release(link);
+    tc589_release(link);
 
     free_netdev(dev);
 } /* tc589_detach */
@@ -257,9 +247,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void tc589_config(dev_link_t *link)
+static int tc589_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct el3_private *lp = netdev_priv(dev);
     tuple_t tuple;
@@ -274,43 +263,40 @@
     phys_addr = (u16 *)dev->dev_addr;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
     
     /* Is this a 3c562? */
     tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
-    if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
-	(pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) {
+    if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) &&
+	(pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) {
 	if (le16_to_cpu(buf[0]) != MANFID_3COM)
 	    printk(KERN_INFO "3c589_cs: hmmm, is this really a "
 		   "3Com card??\n");
 	multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562);
     }
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
     /* For the 3c562, the base address must be xx00-xx7f */
     link->io.IOAddrLines = 16;
     for (i = j = 0; j < 0x400; j += 0x10) {
 	if (multi && (j & 0x80)) continue;
 	link->io.BasePort1 = j ^ 0x300;
-	i = pcmcia_request_io(link->handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
 	if (i == CS_SUCCESS) break;
     }
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
+	cs_error(link, RequestIO, i);
 	goto failed;
     }
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 	
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
@@ -320,8 +306,8 @@
     /* The 3c589 has an extra EEPROM for configuration info, including
        the hardware address.  The 3c562 puts the address in the CIS. */
     tuple.DesiredTuple = 0x88;
-    if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) {
-	pcmcia_get_tuple_data(handle, &tuple);
+    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
+	pcmcia_get_tuple_data(link, &tuple);
 	for (i = 0; i < 3; i++)
 	    phys_addr[i] = htons(buf[i]);
     } else {
@@ -345,13 +331,12 @@
     else
 	printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
     
-    link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &lp->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -365,14 +350,13 @@
     printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
 	   (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
 	   if_names[dev->if_port]);
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     tc589_release(link);
-    return;
-    
+    return -ENODEV;
 } /* tc589_config */
 
 /*======================================================================
@@ -383,44 +367,28 @@
     
 ======================================================================*/
 
-static void tc589_release(dev_link_t *link)
+static void tc589_release(struct pcmcia_device *link)
 {
-    DEBUG(0, "3c589_release(0x%p)\n", link);
-    
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int tc589_suspend(struct pcmcia_device *p_dev)
+static int tc589_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int tc589_resume(struct pcmcia_device *p_dev)
+static int tc589_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			tc589_reset(dev);
-			netif_device_attach(dev);
-		}
+ 	if (link->open) {
+		tc589_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -586,9 +554,9 @@
 static int el3_open(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
     
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
     link->open++;
@@ -847,9 +815,9 @@
 {
     struct el3_private *lp = netdev_priv(dev);
     unsigned long flags;
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
 
-    if (DEV_OK(link)) {
+    if (pcmcia_dev_present(link)) {
     	spin_lock_irqsave(&lp->lock, flags);
 	update_stats(dev);
 	spin_unlock_irqrestore(&lp->lock, flags);
@@ -949,11 +917,11 @@
 static void set_multicast_list(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
     kio_addr_t ioaddr = dev->base_addr;
     u16 opts = SetRxFilter | RxStation | RxBroadcast;
 
-    if (!(DEV_OK(link))) return;
+    if (!pcmcia_dev_present(link)) return;
     if (dev->flags & IFF_PROMISC)
 	opts |= RxMulticast | RxProm;
     else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
@@ -964,12 +932,12 @@
 static int el3_close(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
     kio_addr_t ioaddr = dev->base_addr;
     
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
 
-    if (DEV_OK(link)) {
+    if (pcmcia_dev_present(link)) {
 	/* Turn off statistics ASAP.  We update lp->stats below. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
 	
@@ -1019,7 +987,7 @@
 	.drv		= {
 		.name	= "3c589_cs",
 	},
-	.probe		= tc589_attach,
+	.probe		= tc589_probe,
 	.remove		= tc589_detach,
         .id_table       = tc589_ids,
 	.suspend	= tc589_suspend,
diff -urN oldtree/drivers/net/pcmcia/axnet_cs.c newtree/drivers/net/pcmcia/axnet_cs.c
--- oldtree/drivers/net/pcmcia/axnet_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/axnet_cs.c	2006-04-01 05:35:44.255385750 -0500
@@ -85,8 +85,8 @@
 
 /*====================================================================*/
 
-static void axnet_config(dev_link_t *link);
-static void axnet_release(dev_link_t *link);
+static int axnet_config(struct pcmcia_device *link);
+static void axnet_release(struct pcmcia_device *link);
 static int axnet_open(struct net_device *dev);
 static int axnet_close(struct net_device *dev);
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -116,7 +116,7 @@
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t		node;
     caddr_t		base;
     struct timer_list	watchdog;
@@ -141,10 +141,9 @@
 
 ======================================================================*/
 
-static int axnet_attach(struct pcmcia_device *p_dev)
+static int axnet_probe(struct pcmcia_device *link)
 {
     axnet_dev_t *info;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "axnet_attach()\n");
@@ -156,7 +155,7 @@
 	return -ENOMEM;
 
     info = PRIV(dev);
-    link = &info->link;
+    info->p_dev = link;
     link->priv = dev;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
@@ -168,13 +167,7 @@
     dev->do_ioctl = &axnet_ioctl;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    axnet_config(link);
-
-    return 0;
+    return axnet_config(link);
 } /* axnet_attach */
 
 /*======================================================================
@@ -186,18 +179,16 @@
 
 ======================================================================*/
 
-static void axnet_detach(struct pcmcia_device *p_dev)
+static void axnet_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "axnet_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	axnet_release(link);
+    axnet_release(link);
 
     free_netdev(dev);
 } /* axnet_detach */
@@ -208,7 +199,7 @@
 
 ======================================================================*/
 
-static int get_prom(dev_link_t *link)
+static int get_prom(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -262,7 +253,7 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int try_io_port(dev_link_t *link)
+static int try_io_port(struct pcmcia_device *link)
 {
     int j, ret;
     if (link->io.NumPorts1 == 32) {
@@ -283,25 +274,23 @@
 	for (j = 0; j < 0x400; j += 0x20) {
 	    link->io.BasePort1 = j ^ 0x300;
 	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
-	    ret = pcmcia_request_io(link->handle, &link->io);
+	    ret = pcmcia_request_io(link, &link->io);
 	    if (ret == CS_SUCCESS) return ret;
 	}
 	return ret;
     } else {
-	return pcmcia_request_io(link->handle, &link->io);
+	return pcmcia_request_io(link, &link->io);
     }
 }
 
-static void axnet_config(dev_link_t *link)
+static int axnet_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     axnet_dev_t *info = PRIV(dev);
     tuple_t tuple;
     cisparse_t parse;
     int i, j, last_ret, last_fn;
     u_short buf[64];
-    config_info_t conf;
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
@@ -310,29 +299,22 @@
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     /* don't trust the CIS on this; Linksys got it wrong */
     link->conf.Present = 0x63;
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Look up current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
-
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
     tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (last_ret == CS_SUCCESS) {
 	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 	cistpl_io_t *io = &(parse.cftable_entry.io);
 	
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		pcmcia_parse_tuple(handle, &tuple, &parse) != 0 ||
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
 		cfg->index == 0 || cfg->io.nwin == 0)
 	    goto next_entry;
 	
@@ -354,21 +336,21 @@
 	    if (last_ret == CS_SUCCESS) break;
 	}
     next_entry:
-	last_ret = pcmcia_get_next_tuple(handle, &tuple);
+	last_ret = pcmcia_get_next_tuple(link, &tuple);
     }
     if (last_ret != CS_SUCCESS) {
-	cs_error(handle, RequestIO, last_ret);
+	cs_error(link, RequestIO, last_ret);
 	goto failed;
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     
     if (link->io.NumPorts2 == 8) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
 	link->conf.Status = CCSR_AUDIO_ENA;
     }
     
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
 
@@ -405,7 +387,7 @@
        Bit 2 of CCSR is active low. */ 
     if (i == 32) {
 	conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
- 	pcmcia_access_configuration_register(link->handle, &reg);
+ 	pcmcia_access_configuration_register(link, &reg);
 	for (i = 0; i < 32; i++) {
 	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
@@ -413,13 +395,12 @@
     }
 
     info->phy_id = (i < 32) ? i : -1;
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &info->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -435,14 +416,13 @@
     } else {
 	printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     axnet_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
+    return -ENODEV;
 } /* axnet_config */
 
 /*======================================================================
@@ -453,45 +433,29 @@
 
 ======================================================================*/
 
-static void axnet_release(dev_link_t *link)
+static void axnet_release(struct pcmcia_device *link)
 {
-    DEBUG(0, "axnet_release(0x%p)\n", link);
-
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-
-    link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int axnet_suspend(struct pcmcia_device *p_dev)
+static int axnet_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int axnet_resume(struct pcmcia_device *p_dev)
+static int axnet_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			axnet_reset_8390(dev);
-			AX88190_init(dev, 1);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		axnet_reset_8390(dev);
+		AX88190_init(dev, 1);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -561,11 +525,11 @@
 static int axnet_open(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
+    struct pcmcia_device *link = info->p_dev;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
     link->open++;
@@ -587,7 +551,7 @@
 static int axnet_close(struct net_device *dev)
 {
     axnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
+    struct pcmcia_device *link = info->p_dev;
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
@@ -832,7 +796,7 @@
 	.drv		= {
 		.name	= "axnet_cs",
 	},
-	.probe		= axnet_attach,
+	.probe		= axnet_probe,
 	.remove		= axnet_detach,
 	.id_table       = axnet_ids,
 	.suspend	= axnet_suspend,
diff -urN oldtree/drivers/net/pcmcia/com20020_cs.c newtree/drivers/net/pcmcia/com20020_cs.c
--- oldtree/drivers/net/pcmcia/com20020_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/com20020_cs.c	2006-04-01 05:35:44.255385750 -0500
@@ -118,8 +118,8 @@
 
 /*====================================================================*/
 
-static void com20020_config(dev_link_t *link);
-static void com20020_release(dev_link_t *link);
+static int com20020_config(struct pcmcia_device *link);
+static void com20020_release(struct pcmcia_device *link);
 
 static void com20020_detach(struct pcmcia_device *p_dev);
 
@@ -138,9 +138,8 @@
 
 ======================================================================*/
 
-static int com20020_attach(struct pcmcia_device *p_dev)
+static int com20020_probe(struct pcmcia_device *p_dev)
 {
-    dev_link_t *link;
     com20020_dev_t *info;
     struct net_device *dev;
     struct arcnet_local *lp;
@@ -148,10 +147,6 @@
     DEBUG(0, "com20020_attach()\n");
 
     /* Create new network device */
-    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-    if (!link)
-	return -ENOMEM;
-
     info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
     if (!info)
 	goto fail_alloc_info;
@@ -161,7 +156,6 @@
 	goto fail_alloc_dev;
 
     memset(info, 0, sizeof(struct com20020_dev_t));
-    memset(link, 0, sizeof(struct dev_link_t));
     lp = dev->priv;
     lp->timeout = timeout;
     lp->backplane = backplane;
@@ -172,28 +166,23 @@
     /* fill in our module parameters as defaults */
     dev->dev_addr[0] = node;
 
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts1 = 16;
-    link->io.IOAddrLines = 16;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.Present = PRESENT_OPTION;
-
-    link->irq.Instance = info->dev = dev;
-    link->priv = info;
+    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    p_dev->io.NumPorts1 = 16;
+    p_dev->io.IOAddrLines = 16;
+    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+    p_dev->conf.IntType = INT_MEMORY_AND_IO;
+    p_dev->conf.Present = PRESENT_OPTION;
 
-    link->state |= DEV_PRESENT;
-    com20020_config(link);
+    p_dev->irq.Instance = info->dev = dev;
+    p_dev->priv = info;
 
-    return 0;
+    return com20020_config(p_dev);
 
 fail_alloc_dev:
     kfree(info);
 fail_alloc_info:
-    kfree(link);
     return -ENOMEM;
 } /* com20020_attach */
 
@@ -206,9 +195,8 @@
 
 ======================================================================*/
 
-static void com20020_detach(struct pcmcia_device *p_dev)
+static void com20020_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct com20020_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
 
@@ -216,7 +204,7 @@
 
     DEBUG(0, "com20020_detach(0x%p)\n", link);
 
-    if (link->dev) {
+    if (link->dev_node) {
 	DEBUG(1,"unregister...\n");
 
 	unregister_netdev(dev);
@@ -229,8 +217,7 @@
 	    free_irq(dev->irq, dev);
     }
 
-    if (link->state & DEV_CONFIG)
-        com20020_release(link);
+    com20020_release(link);
 
     /* Unlink device structure, free bits */
     DEBUG(1,"unlinking...\n");
@@ -245,8 +232,6 @@
 	DEBUG(1,"kfree2...\n");
 	kfree(info);
     }
-    DEBUG(1,"kfree3...\n");
-    kfree(link);
 
 } /* com20020_detach */
 
@@ -261,10 +246,9 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void com20020_config(dev_link_t *link)
+static int com20020_config(struct pcmcia_device *link)
 {
     struct arcnet_local *lp;
-    client_handle_t handle;
     tuple_t tuple;
     cisparse_t parse;
     com20020_dev_t *info;
@@ -273,7 +257,6 @@
     u_char buf[64];
     int ioaddr;
 
-    handle = link->handle;
     info = link->priv;
     dev = info->dev;
 
@@ -286,14 +269,11 @@
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
     i = !CS_SUCCESS;
     if (!link->io.BasePort1)
@@ -301,13 +281,13 @@
 	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
 	{
 	    link->io.BasePort1 = ioaddr;
-	    i = pcmcia_request_io(link->handle, &link->io);
+	    i = pcmcia_request_io(link, &link->io);
 	    if (i == CS_SUCCESS)
 		break;
 	}
     }
     else
-	i = pcmcia_request_io(link->handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
     
     if (i != CS_SUCCESS)
     {
@@ -321,7 +301,7 @@
     DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
 	   link->irq.AssignedIRQ,
 	   link->irq.IRQInfo1, link->irq.IRQInfo2);
-    i = pcmcia_request_irq(link->handle, &link->irq);
+    i = pcmcia_request_irq(link, &link->irq);
     if (i != CS_SUCCESS)
     {
 	DEBUG(1,"arcnet: requestIRQ failed totally!\n");
@@ -330,7 +310,7 @@
 
     dev->irq = link->irq.AssignedIRQ;
 
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     if (com20020_check(dev))
     {
@@ -342,15 +322,14 @@
     lp->card_name = "PCMCIA COM20020";
     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
 
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &info->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     i = com20020_found(dev, 0);	/* calls register_netdev */
     
     if (i != 0) {
 	DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -358,13 +337,14 @@
 
     DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
            dev->name, dev->base_addr, dev->irq);
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     DEBUG(1,"com20020_config failed...\n");
     com20020_release(link);
+    return -ENODEV;
 } /* com20020_config */
 
 /*======================================================================
@@ -375,52 +355,33 @@
 
 ======================================================================*/
 
-static void com20020_release(dev_link_t *link)
+static void com20020_release(struct pcmcia_device *link)
 {
-
-    DEBUG(1,"release...\n");
-
-    DEBUG(0, "com20020_release(0x%p)\n", link);
-
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-
-    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+	DEBUG(0, "com20020_release(0x%p)\n", link);
+	pcmcia_disable_device(link);
 }
 
-static int com20020_suspend(struct pcmcia_device *p_dev)
+static int com20020_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	com20020_dev_t *info = link->priv;
 	struct net_device *dev = info->dev;
 
-	link->state |= DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		if (link->open) {
-			netif_device_detach(dev);
-		}
-		pcmcia_release_configuration(link->handle);
-        }
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int com20020_resume(struct pcmcia_device *p_dev)
+static int com20020_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	com20020_dev_t *info = link->priv;
 	struct net_device *dev = info->dev;
 
-	link->state &= ~DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			int ioaddr = dev->base_addr;
-			struct arcnet_local *lp = dev->priv;
-			ARCRESET;
-		}
-        }
+	if (link->open) {
+		int ioaddr = dev->base_addr;
+		struct arcnet_local *lp = dev->priv;
+		ARCRESET;
+	}
 
 	return 0;
 }
@@ -436,7 +397,7 @@
 	.drv		= {
 		.name	= "com20020_cs",
 	},
-	.probe		= com20020_attach,
+	.probe		= com20020_probe,
 	.remove		= com20020_detach,
 	.id_table	= com20020_ids,
 	.suspend	= com20020_suspend,
diff -urN oldtree/drivers/net/pcmcia/fmvj18x_cs.c newtree/drivers/net/pcmcia/fmvj18x_cs.c
--- oldtree/drivers/net/pcmcia/fmvj18x_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/fmvj18x_cs.c	2006-04-01 05:35:44.259386000 -0500
@@ -84,10 +84,10 @@
 /*
     PCMCIA event handlers
  */
-static void fmvj18x_config(dev_link_t *link);
-static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id);
-static int fmvj18x_setup_mfc(dev_link_t *link);
-static void fmvj18x_release(dev_link_t *link);
+static int fmvj18x_config(struct pcmcia_device *link);
+static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
+static int fmvj18x_setup_mfc(struct pcmcia_device *link);
+static void fmvj18x_release(struct pcmcia_device *link);
 static void fmvj18x_detach(struct pcmcia_device *p_dev);
 
 /*
@@ -116,7 +116,7 @@
     driver specific data structure
 */
 typedef struct local_info_t {
-    dev_link_t link;
+	struct pcmcia_device	*p_dev;
     dev_node_t node;
     struct net_device_stats stats;
     long open_time;
@@ -228,10 +228,9 @@
 #define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
 #define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
 
-static int fmvj18x_attach(struct pcmcia_device *p_dev)
+static int fmvj18x_probe(struct pcmcia_device *link)
 {
     local_info_t *lp;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "fmvj18x_attach()\n");
@@ -241,8 +240,8 @@
     if (!dev)
 	return -ENOMEM;
     lp = netdev_priv(dev);
-    link = &lp->link;
     link->priv = dev;
+    lp->p_dev = link;
 
     /* The io structure describes IO port mapping */
     link->io.NumPorts1 = 32;
@@ -257,7 +256,6 @@
 
     /* General socket configuration */
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The FMVJ18x specific entries in the device structure. */
@@ -274,29 +272,21 @@
 #endif
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    fmvj18x_config(link);
-
-    return 0;
+    return fmvj18x_config(link);
 } /* fmvj18x_attach */
 
 /*====================================================================*/
 
-static void fmvj18x_detach(struct pcmcia_device *p_dev)
+static void fmvj18x_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "fmvj18x_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	fmvj18x_release(link);
+    fmvj18x_release(link);
 
     free_netdev(dev);
 } /* fmvj18x_detach */
@@ -306,7 +296,7 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int mfc_try_io_port(dev_link_t *link)
+static int mfc_try_io_port(struct pcmcia_device *link)
 {
     int i, ret;
     static kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
@@ -318,13 +308,13 @@
 	    link->io.NumPorts2 = 0;
 	    printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
 	}
-	ret = pcmcia_request_io(link->handle, &link->io);
+	ret = pcmcia_request_io(link, &link->io);
 	if (ret == CS_SUCCESS) return ret;
     }
     return ret;
 }
 
-static int ungermann_try_io_port(dev_link_t *link)
+static int ungermann_try_io_port(struct pcmcia_device *link)
 {
     int ret;
     kio_addr_t ioaddr;
@@ -334,7 +324,7 @@
     */
     for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
 	link->io.BasePort1 = ioaddr;
-	ret = pcmcia_request_io(link->handle, &link->io);
+	ret = pcmcia_request_io(link, &link->io);
 	if (ret == CS_SUCCESS) {
 	    /* calculate ConfigIndex value */
 	    link->conf.ConfigIndex = 
@@ -345,9 +335,8 @@
     return ret;	/* RequestIO failed */
 }
 
-static void fmvj18x_config(dev_link_t *link)
+static int fmvj18x_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     local_info_t *lp = netdev_priv(dev);
     tuple_t tuple;
@@ -366,42 +355,34 @@
        registers.
     */
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     tuple.TupleData = (u_char *)buf;
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 
     link->conf.ConfigBase = parse.config.base; 
     link->conf.Present = parse.config.rmask[0];
 
     tuple.DesiredTuple = CISTPL_FUNCE;
     tuple.TupleOffset = 0;
-    if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) {
 	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigIndex = parse.cftable_entry.index;
 	tuple.DesiredTuple = CISTPL_MANFID;
-	if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS)
-	    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS)
+	    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 	else
 	    buf[0] = 0xffff;
 	switch (le16_to_cpu(buf[0])) {
 	case MANFID_TDK:
 	    cardtype = TDK;
-	    if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) {
-		cs_status_t status;
-		pcmcia_get_status(handle, &status);
-		if (status.CardState & CS_EVENT_3VCARD)
-		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
-	    } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410
+	    if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410
 			|| le16_to_cpu(buf[1]) == PRODID_TDK_NP9610
 			|| le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) {
 		/* MultiFunction Card */
@@ -429,8 +410,8 @@
     } else {
 	/* old type card */
 	tuple.DesiredTuple = CISTPL_MANFID;
-	if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS)
-	    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS)
+	    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 	else
 	    buf[0] = 0xffff;
 	switch (le16_to_cpu(buf[0])) {
@@ -461,10 +442,10 @@
 	ret = ungermann_try_io_port(link);
 	if (ret != CS_SUCCESS) goto cs_failed;
     } else { 
-	CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
+	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
 
@@ -493,17 +474,17 @@
     case CONTEC:
 	tuple.DesiredTuple = CISTPL_FUNCE;
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 	if (cardtype == MBH10304) {
 	    /* MBH10304's CIS_FUNCE is corrupted */
 	    node_id = &(tuple.TupleData[5]);
 	    card_name = "FMV-J182";
 	} else {
 	    while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) {
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
-		CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
+		CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 	    }
 	    node_id = &(tuple.TupleData[2]);
 	    if( cardtype == TDK ) {
@@ -545,13 +526,12 @@
     }
 
     lp->cardtype = cardtype;
-    link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &lp->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -564,19 +544,18 @@
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
-    return;
+    return 0;
     
 cs_failed:
     /* All Card Services errors end up here */
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     fmvj18x_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-
+    return -ENODEV;
 } /* fmvj18x_config */
 /*====================================================================*/
 
-static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id)
+static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
 {
     win_req_t req;
     memreq_t mem;
@@ -587,9 +566,9 @@
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
-    i = pcmcia_request_window(&link->handle, &req, &link->win);
+    i = pcmcia_request_window(&link, &req, &link->win);
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestWindow, i);
+	cs_error(link, RequestWindow, i);
 	return -1;
     }
 
@@ -623,13 +602,13 @@
     iounmap(base);
     j = pcmcia_release_window(link->win);
     if (j != CS_SUCCESS)
-	cs_error(link->handle, ReleaseWindow, j);
+	cs_error(link, ReleaseWindow, j);
     return (i != 0x200) ? 0 : -1;
 
 } /* fmvj18x_get_hwinfo */
 /*====================================================================*/
 
-static int fmvj18x_setup_mfc(dev_link_t *link)
+static int fmvj18x_setup_mfc(struct pcmcia_device *link)
 {
     win_req_t req;
     memreq_t mem;
@@ -642,9 +621,9 @@
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
-    i = pcmcia_request_window(&link->handle, &req, &link->win);
+    i = pcmcia_request_window(&link, &req, &link->win);
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestWindow, i);
+	cs_error(link, RequestWindow, i);
 	return -1;
     }
 
@@ -666,54 +645,35 @@
     iounmap(base);
     j = pcmcia_release_window(link->win);
     if (j != CS_SUCCESS)
-	cs_error(link->handle, ReleaseWindow, j);
+	cs_error(link, ReleaseWindow, j);
     return 0;
 
 }
 /*====================================================================*/
 
-static void fmvj18x_release(dev_link_t *link)
+static void fmvj18x_release(struct pcmcia_device *link)
 {
-
-    DEBUG(0, "fmvj18x_release(0x%p)\n", link);
-
-    /* Don't bother checking to see if these succeed or not */
-    pcmcia_release_window(link->win);
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
+	DEBUG(0, "fmvj18x_release(0x%p)\n", link);
+	pcmcia_disable_device(link);
 }
 
-static int fmvj18x_suspend(struct pcmcia_device *p_dev)
+static int fmvj18x_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
-
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int fmvj18x_resume(struct pcmcia_device *p_dev)
+static int fmvj18x_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			fjn_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		fjn_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -751,7 +711,7 @@
 	.drv		= {
 		.name	= "fmvj18x_cs",
 	},
-	.probe		= fmvj18x_attach,
+	.probe		= fmvj18x_probe,
 	.remove		= fmvj18x_detach,
 	.id_table       = fmvj18x_ids,
 	.suspend	= fmvj18x_suspend,
@@ -1148,11 +1108,11 @@
 static int fjn_open(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
 
     DEBUG(4, "fjn_open('%s').\n", dev->name);
 
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
     
     link->open++;
@@ -1173,7 +1133,7 @@
 static int fjn_close(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
     kio_addr_t ioaddr = dev->base_addr;
 
     DEBUG(4, "fjn_close('%s').\n", dev->name);
diff -urN oldtree/drivers/net/pcmcia/ibmtr_cs.c newtree/drivers/net/pcmcia/ibmtr_cs.c
--- oldtree/drivers/net/pcmcia/ibmtr_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/ibmtr_cs.c	2006-04-01 05:35:44.259386000 -0500
@@ -105,15 +105,15 @@
 
 /*====================================================================*/
 
-static void ibmtr_config(dev_link_t *link);
+static int ibmtr_config(struct pcmcia_device *link);
 static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
-static void ibmtr_release(dev_link_t *link);
+static void ibmtr_release(struct pcmcia_device *link);
 static void ibmtr_detach(struct pcmcia_device *p_dev);
 
 /*====================================================================*/
 
 typedef struct ibmtr_dev_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     struct net_device	*dev;
     dev_node_t          node;
     window_handle_t     sram_win_handle;
@@ -138,12 +138,11 @@
 
 ======================================================================*/
 
-static int ibmtr_attach(struct pcmcia_device *p_dev)
+static int ibmtr_attach(struct pcmcia_device *link)
 {
     ibmtr_dev_t *info;
-    dev_link_t *link;
     struct net_device *dev;
-    
+
     DEBUG(0, "ibmtr_attach()\n");
 
     /* Create new token-ring device */
@@ -156,7 +155,7 @@
 	return -ENOMEM;
     }
 
-    link = &info->link;
+    info->p_dev = link;
     link->priv = info;
     info->ti = netdev_priv(dev);
 
@@ -167,21 +166,14 @@
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->irq.Handler = &tok_interrupt;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.Present = PRESENT_OPTION;
 
     link->irq.Instance = info->dev = dev;
-    
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-
-    link->handle = p_dev;
-    p_dev->instance = link;
 
-    link->state |= DEV_PRESENT;
-    ibmtr_config(link);
+    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    return 0;
+    return ibmtr_config(link);
 } /* ibmtr_attach */
 
 /*======================================================================
@@ -193,23 +185,22 @@
 
 ======================================================================*/
 
-static void ibmtr_detach(struct pcmcia_device *p_dev)
+static void ibmtr_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
 
     DEBUG(0, "ibmtr_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
     {
 	struct tok_info *ti = netdev_priv(dev);
 	del_timer_sync(&(ti->tr_timer));
     }
-    if (link->state & DEV_CONFIG)
-        ibmtr_release(link);
+
+    ibmtr_release(link);
 
     free_netdev(dev);
     kfree(info);
@@ -226,9 +217,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void ibmtr_config(dev_link_t *link)
+static int ibmtr_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
     struct tok_info *ti = netdev_priv(dev);
@@ -246,29 +236,25 @@
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
-
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     link->conf.ConfigIndex = 0x61;
 
     /* Determine if this is PRIMARY or ALTERNATE. */
 
     /* Try PRIMARY card at 0xA20-0xA23 */
     link->io.BasePort1 = 0xA20;
-    i = pcmcia_request_io(link->handle, &link->io);
+    i = pcmcia_request_io(link, &link->io);
     if (i != CS_SUCCESS) {
 	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
 	link->io.BasePort1 = 0xA24;
-	CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
+	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
     dev->base_addr = link->io.BasePort1;
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     dev->irq = link->irq.AssignedIRQ;
     ti->irq = link->irq.AssignedIRQ;
     ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
@@ -279,7 +265,7 @@
     req.Base = 0; 
     req.Size = 0x2000;
     req.AccessSpeed = 250;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
 
     mem.CardOffset = mmiobase;
     mem.Page = 0;
@@ -292,7 +278,7 @@
     req.Base = 0;
     req.Size = sramsize * 1024;
     req.AccessSpeed = 250;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &info->sram_win_handle));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &info->sram_win_handle));
 
     mem.CardOffset = srambase;
     mem.Page = 0;
@@ -302,21 +288,20 @@
     ti->sram_virt = ioremap(req.Base, req.Size);
     ti->sram_phys = req.Base;
 
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     /*  Set up the Token-Ring Controller Configuration Register and
         turn on the card.  Check the "Local Area Network Credit Card
         Adapters Technical Reference"  SC30-3585 for this info.  */
     ibmtr_hw_setup(dev, mmiobase);
 
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &info->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     i = ibmtr_probe_card(dev);
     if (i != 0) {
 	printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -330,12 +315,13 @@
     for (i = 0; i < TR_ALEN; i++)
         printk("%02X", dev->dev_addr[i]);
     printk("\n");
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     ibmtr_release(link);
+    return -ENODEV;
 } /* ibmtr_config */
 
 /*======================================================================
@@ -346,56 +332,41 @@
 
 ======================================================================*/
 
-static void ibmtr_release(dev_link_t *link)
+static void ibmtr_release(struct pcmcia_device *link)
 {
-    ibmtr_dev_t *info = link->priv;
-    struct net_device *dev = info->dev;
-
-    DEBUG(0, "ibmtr_release(0x%p)\n", link);
+	ibmtr_dev_t *info = link->priv;
+	struct net_device *dev = info->dev;
 
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    if (link->win) {
-	struct tok_info *ti = netdev_priv(dev);
-	iounmap(ti->mmio);
-	pcmcia_release_window(link->win);
-	pcmcia_release_window(info->sram_win_handle);
-    }
+	DEBUG(0, "ibmtr_release(0x%p)\n", link);
 
-    link->state &= ~DEV_CONFIG;
+	if (link->win) {
+		struct tok_info *ti = netdev_priv(dev);
+		iounmap(ti->mmio);
+		pcmcia_release_window(info->sram_win_handle);
+	}
+	pcmcia_disable_device(link);
 }
 
-static int ibmtr_suspend(struct pcmcia_device *p_dev)
+static int ibmtr_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	ibmtr_dev_t *info = link->priv;
 	struct net_device *dev = info->dev;
 
-	link->state |= DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-        }
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int ibmtr_resume(struct pcmcia_device *p_dev)
+static int ibmtr_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	ibmtr_dev_t *info = link->priv;
 	struct net_device *dev = info->dev;
 
-	link->state &= ~DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			ibmtr_probe(dev);	/* really? */
-			netif_device_attach(dev);
-		}
-        }
+	if (link->open) {
+		ibmtr_probe(dev);	/* really? */
+		netif_device_attach(dev);
+	}
 
 	return 0;
 }
diff -urN oldtree/drivers/net/pcmcia/nmclan_cs.c newtree/drivers/net/pcmcia/nmclan_cs.c
--- oldtree/drivers/net/pcmcia/nmclan_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/nmclan_cs.c	2006-04-01 05:35:44.259386000 -0500
@@ -362,7 +362,7 @@
 } mace_statistics;
 
 typedef struct _mace_private {
-    dev_link_t link;
+	struct pcmcia_device	*p_dev;
     dev_node_t node;
     struct net_device_stats linux_stats; /* Linux statistics counters */
     mace_statistics mace_stats; /* MACE chip statistics counters */
@@ -417,8 +417,8 @@
 Function Prototypes
 ---------------------------------------------------------------------------- */
 
-static void nmclan_config(dev_link_t *link);
-static void nmclan_release(dev_link_t *link);
+static int nmclan_config(struct pcmcia_device *link);
+static void nmclan_release(struct pcmcia_device *link);
 
 static void nmclan_reset(struct net_device *dev);
 static int mace_config(struct net_device *dev, struct ifmap *map);
@@ -443,10 +443,9 @@
 	Services.
 ---------------------------------------------------------------------------- */
 
-static int nmclan_attach(struct pcmcia_device *p_dev)
+static int nmclan_probe(struct pcmcia_device *link)
 {
     mace_private *lp;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "nmclan_attach()\n");
@@ -457,7 +456,7 @@
     if (!dev)
 	    return -ENOMEM;
     lp = netdev_priv(dev);
-    link = &lp->link;
+    lp->p_dev = link;
     link->priv = dev;
     
     spin_lock_init(&lp->bank_lock);
@@ -469,7 +468,6 @@
     link->irq.Handler = &mace_interrupt;
     link->irq.Instance = dev;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
@@ -489,13 +487,7 @@
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    nmclan_config(link);
-
-    return 0;
+    return nmclan_config(link);
 } /* nmclan_attach */
 
 /* ----------------------------------------------------------------------------
@@ -506,18 +498,16 @@
 	when the device is released.
 ---------------------------------------------------------------------------- */
 
-static void nmclan_detach(struct pcmcia_device *p_dev)
+static void nmclan_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "nmclan_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	nmclan_release(link);
+    nmclan_release(link);
 
     free_netdev(dev);
 } /* nmclan_detach */
@@ -661,9 +651,8 @@
 #define CS_CHECK(fn, ret) \
   do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void nmclan_config(dev_link_t *link)
+static int nmclan_config(struct pcmcia_device *link)
 {
-  client_handle_t handle = link->handle;
   struct net_device *dev = link->priv;
   mace_private *lp = netdev_priv(dev);
   tuple_t tuple;
@@ -679,17 +668,14 @@
   tuple.TupleDataMax = 64;
   tuple.TupleOffset = 0;
   tuple.DesiredTuple = CISTPL_CONFIG;
-  CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-  CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-  CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+  CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+  CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+  CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
   link->conf.ConfigBase = parse.config.base;
 
-  /* Configure card */
-  link->state |= DEV_CONFIG;
-
-  CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
-  CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-  CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+  CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
+  CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+  CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
   dev->irq = link->irq.AssignedIRQ;
   dev->base_addr = link->io.BasePort1;
 
@@ -700,8 +686,8 @@
   tuple.TupleData = buf;
   tuple.TupleDataMax = 64;
   tuple.TupleOffset = 0;
-  CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-  CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+  CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+  CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
   memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN);
 
   /* Verify configuration by reading the MACE ID. */
@@ -716,8 +702,7 @@
     } else {
       printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should"
 	     " be 0x40 0x?9\n", sig[0], sig[1]);
-      link->state &= ~DEV_CONFIG_PENDING;
-      return;
+      return -ENODEV;
     }
   }
 
@@ -730,14 +715,13 @@
   else
     printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
 
-  link->dev = &lp->node;
-  link->state &= ~DEV_CONFIG_PENDING;
-  SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+  link->dev_node = &lp->node;
+  SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
   i = register_netdev(dev);
   if (i != 0) {
     printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
-    link->dev = NULL;
+    link->dev_node = NULL;
     goto failed;
   }
 
@@ -747,14 +731,13 @@
 	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
   for (i = 0; i < 6; i++)
       printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-  return;
+  return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 failed:
-    nmclan_release(link);
-    return;
-
+	nmclan_release(link);
+	return -ENODEV;
 } /* nmclan_config */
 
 /* ----------------------------------------------------------------------------
@@ -763,46 +746,29 @@
 	net device, and release the PCMCIA configuration.  If the device
 	is still open, this will be postponed until it is closed.
 ---------------------------------------------------------------------------- */
-static void nmclan_release(dev_link_t *link)
+static void nmclan_release(struct pcmcia_device *link)
 {
-
-  DEBUG(0, "nmclan_release(0x%p)\n", link);
-
-  pcmcia_release_configuration(link->handle);
-  pcmcia_release_io(link->handle, &link->io);
-  pcmcia_release_irq(link->handle, &link->irq);
-
-  link->state &= ~DEV_CONFIG;
+	DEBUG(0, "nmclan_release(0x%p)\n", link);
+	pcmcia_disable_device(link);
 }
 
-static int nmclan_suspend(struct pcmcia_device *p_dev)
+static int nmclan_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
-
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int nmclan_resume(struct pcmcia_device *p_dev)
+static int nmclan_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			nmclan_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		nmclan_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -818,7 +784,7 @@
   mace_private *lp = netdev_priv(dev);
 
 #if RESET_XILINX
-  dev_link_t *link = &lp->link;
+  struct pcmcia_device *link = &lp->link;
   conf_reg_t reg;
   u_long OrigCorValue; 
 
@@ -827,7 +793,7 @@
   reg.Action = CS_READ;
   reg.Offset = CISREG_COR;
   reg.Value = 0;
-  pcmcia_access_configuration_register(link->handle, &reg);
+  pcmcia_access_configuration_register(link, &reg);
   OrigCorValue = reg.Value;
 
   /* Reset Xilinx */
@@ -836,12 +802,12 @@
   DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n",
 	OrigCorValue);
   reg.Value = COR_SOFT_RESET;
-  pcmcia_access_configuration_register(link->handle, &reg);
+  pcmcia_access_configuration_register(link, &reg);
   /* Need to wait for 20 ms for PCMCIA to finish reset. */
 
   /* Restore original COR configuration index */
   reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK);
-  pcmcia_access_configuration_register(link->handle, &reg);
+  pcmcia_access_configuration_register(link, &reg);
   /* Xilinx is now completely reset along with the MACE chip. */
   lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
 
@@ -885,9 +851,9 @@
 {
   kio_addr_t ioaddr = dev->base_addr;
   mace_private *lp = netdev_priv(dev);
-  dev_link_t *link = &lp->link;
+  struct pcmcia_device *link = lp->p_dev;
 
-  if (!DEV_OK(link))
+  if (!pcmcia_dev_present(link))
     return -ENODEV;
 
   link->open++;
@@ -908,7 +874,7 @@
 {
   kio_addr_t ioaddr = dev->base_addr;
   mace_private *lp = netdev_priv(dev);
-  dev_link_t *link = &lp->link;
+  struct pcmcia_device *link = lp->p_dev;
 
   DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
 
@@ -963,12 +929,12 @@
 static void mace_tx_timeout(struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
-  dev_link_t *link = &lp->link;
+  struct pcmcia_device *link = lp->p_dev;
 
   printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
 #if RESET_ON_TIMEOUT
   printk("resetting card\n");
-  pcmcia_reset_card(link->handle, NULL);
+  pcmcia_reset_card(link, NULL);
 #else /* #if RESET_ON_TIMEOUT */
   printk("NOT resetting card\n");
 #endif /* #if RESET_ON_TIMEOUT */
@@ -1635,7 +1601,7 @@
 	.drv		= {
 		.name	= "nmclan_cs",
 	},
-	.probe		= nmclan_attach,
+	.probe		= nmclan_probe,
 	.remove		= nmclan_detach,
 	.id_table       = nmclan_ids,
 	.suspend	= nmclan_suspend,
diff -urN oldtree/drivers/net/pcmcia/pcnet_cs.c newtree/drivers/net/pcmcia/pcnet_cs.c
--- oldtree/drivers/net/pcmcia/pcnet_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/pcnet_cs.c	2006-04-01 05:35:44.263386250 -0500
@@ -103,8 +103,8 @@
 /*====================================================================*/
 
 static void mii_phy_probe(struct net_device *dev);
-static void pcnet_config(dev_link_t *link);
-static void pcnet_release(dev_link_t *link);
+static int pcnet_config(struct pcmcia_device *link);
+static void pcnet_release(struct pcmcia_device *link);
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -113,9 +113,9 @@
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
 static int set_config(struct net_device *dev, struct ifmap *map);
-static int setup_shmem_window(dev_link_t *link, int start_pg,
+static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
 			      int stop_pg, int cm_offset);
-static int setup_dma_config(dev_link_t *link, int start_pg,
+static int setup_dma_config(struct pcmcia_device *link, int start_pg,
 			    int stop_pg);
 
 static void pcnet_detach(struct pcmcia_device *p_dev);
@@ -214,7 +214,7 @@
 static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
 
 typedef struct pcnet_dev_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t		node;
     u_int		flags;
     void		__iomem *base;
@@ -240,10 +240,9 @@
 
 ======================================================================*/
 
-static int pcnet_probe(struct pcmcia_device *p_dev)
+static int pcnet_probe(struct pcmcia_device *link)
 {
     pcnet_dev_t *info;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "pcnet_attach()\n");
@@ -252,7 +251,7 @@
     dev = __alloc_ei_netdev(sizeof(pcnet_dev_t));
     if (!dev) return -ENOMEM;
     info = PRIV(dev);
-    link = &info->link;
+    info->p_dev = link;
     link->priv = dev;
 
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -265,13 +264,7 @@
     dev->stop = &pcnet_close;
     dev->set_config = &set_config;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    pcnet_config(link);
-
-    return 0;
+    return pcnet_config(link);
 } /* pcnet_attach */
 
 /*======================================================================
@@ -283,18 +276,16 @@
 
 ======================================================================*/
 
-static void pcnet_detach(struct pcmcia_device *p_dev)
+static void pcnet_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
 	DEBUG(0, "pcnet_detach(0x%p)\n", link);
 
-	if (link->dev)
+	if (link->dev_node)
 		unregister_netdev(dev);
 
-	if (link->state & DEV_CONFIG)
-		pcnet_release(link);
+	pcnet_release(link);
 
 	free_netdev(dev);
 } /* pcnet_detach */
@@ -306,7 +297,7 @@
 
 ======================================================================*/
 
-static hw_info_t *get_hwinfo(dev_link_t *link)
+static hw_info_t *get_hwinfo(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     win_req_t req;
@@ -318,9 +309,9 @@
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = 0; req.Size = 0;
     req.AccessSpeed = 0;
-    i = pcmcia_request_window(&link->handle, &req, &link->win);
+    i = pcmcia_request_window(&link, &req, &link->win);
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestWindow, i);
+	cs_error(link, RequestWindow, i);
 	return NULL;
     }
 
@@ -343,7 +334,7 @@
     iounmap(virt);
     j = pcmcia_release_window(link->win);
     if (j != CS_SUCCESS)
-	cs_error(link->handle, ReleaseWindow, j);
+	cs_error(link, ReleaseWindow, j);
     return (i < NR_INFO) ? hw_info+i : NULL;
 } /* get_hwinfo */
 
@@ -355,7 +346,7 @@
 
 ======================================================================*/
 
-static hw_info_t *get_prom(dev_link_t *link)
+static hw_info_t *get_prom(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -409,7 +400,7 @@
 
 ======================================================================*/
 
-static hw_info_t *get_dl10019(dev_link_t *link)
+static hw_info_t *get_dl10019(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     int i;
@@ -431,7 +422,7 @@
 
 ======================================================================*/
 
-static hw_info_t *get_ax88190(dev_link_t *link)
+static hw_info_t *get_ax88190(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -464,7 +455,7 @@
 
 ======================================================================*/
 
-static hw_info_t *get_hwired(dev_link_t *link)
+static hw_info_t *get_hwired(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     int i;
@@ -491,7 +482,7 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static int try_io_port(dev_link_t *link)
+static int try_io_port(struct pcmcia_device *link)
 {
     int j, ret;
     if (link->io.NumPorts1 == 32) {
@@ -512,18 +503,17 @@
 	for (j = 0; j < 0x400; j += 0x20) {
 	    link->io.BasePort1 = j ^ 0x300;
 	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
-	    ret = pcmcia_request_io(link->handle, &link->io);
+	    ret = pcmcia_request_io(link, &link->io);
 	    if (ret == CS_SUCCESS) return ret;
 	}
 	return ret;
     } else {
-	return pcmcia_request_io(link->handle, &link->io);
+	return pcmcia_request_io(link, &link->io);
     }
 }
 
-static void pcnet_config(dev_link_t *link)
+static int pcnet_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     pcnet_dev_t *info = PRIV(dev);
     tuple_t tuple;
@@ -531,7 +521,6 @@
     int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
     int manfid = 0, prodid = 0, has_shmem = 0;
     u_short buf[64];
-    config_info_t conf;
     hw_info_t *hw_info;
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -541,36 +530,29 @@
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Look up current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
-
     tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
-    if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
- 	(pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) {
+    if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) &&
+ 	(pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) {
 	manfid = le16_to_cpu(buf[0]);
 	prodid = le16_to_cpu(buf[1]);
     }
     
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
     tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (last_ret == CS_SUCCESS) {
 	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 	cistpl_io_t *io = &(parse.cftable_entry.io);
 	
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-			pcmcia_parse_tuple(handle, &tuple, &parse) != 0 ||
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+			pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
 			cfg->index == 0 || cfg->io.nwin == 0)
 		goto next_entry;
 	
@@ -594,14 +576,14 @@
 	    if (last_ret == CS_SUCCESS) break;
 	}
     next_entry:
-	last_ret = pcmcia_get_next_tuple(handle, &tuple);
+	last_ret = pcmcia_get_next_tuple(link, &tuple);
     }
     if (last_ret != CS_SUCCESS) {
-	cs_error(handle, RequestIO, last_ret);
+	cs_error(link, RequestIO, last_ret);
 	goto failed;
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     
     if (link->io.NumPorts2 == 8) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -611,7 +593,7 @@
 	(prodid == PRODID_IBM_HOME_AND_AWAY))
 	link->conf.ConfigIndex |= 0x10;
     
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
     if (info->flags & HAS_MISC_REG) {
@@ -679,9 +661,8 @@
 	    info->eth_phy = 0;
     }
 
-    link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &info->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
     dev->poll_controller = ei_poll;
@@ -689,7 +670,7 @@
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto failed;
     }
 
@@ -712,14 +693,13 @@
     printk(" hw_addr ");
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     pcnet_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
+    return -ENODEV;
 } /* pcnet_config */
 
 /*======================================================================
@@ -730,21 +710,16 @@
 
 ======================================================================*/
 
-static void pcnet_release(dev_link_t *link)
+static void pcnet_release(struct pcmcia_device *link)
 {
-    pcnet_dev_t *info = PRIV(link->priv);
+	pcnet_dev_t *info = PRIV(link->priv);
 
-    DEBUG(0, "pcnet_release(0x%p)\n", link);
+	DEBUG(0, "pcnet_release(0x%p)\n", link);
 
-    if (info->flags & USE_SHMEM) {
-	iounmap(info->base);
-	pcmcia_release_window(link->win);
-    }
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
+	if (info->flags & USE_SHMEM)
+		iounmap(info->base);
 
-    link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
 /*======================================================================
@@ -756,34 +731,24 @@
 
 ======================================================================*/
 
-static int pcnet_suspend(struct pcmcia_device *p_dev)
+static int pcnet_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int pcnet_resume(struct pcmcia_device *p_dev)
+static int pcnet_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			pcnet_reset_8390(dev);
-			NS8390_init(dev, 1);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		pcnet_reset_8390(dev);
+		NS8390_init(dev, 1);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -1023,11 +988,11 @@
 static int pcnet_open(struct net_device *dev)
 {
     pcnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
-    
+    struct pcmcia_device *link = info->p_dev;
+
     DEBUG(2, "pcnet_open('%s')\n", dev->name);
 
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
     link->open++;
@@ -1051,7 +1016,7 @@
 static int pcnet_close(struct net_device *dev)
 {
     pcnet_dev_t *info = PRIV(dev);
-    dev_link_t *link = &info->link;
+    struct pcmcia_device *link = info->p_dev;
 
     DEBUG(2, "pcnet_close('%s')\n", dev->name);
 
@@ -1429,7 +1394,7 @@
 
 /*====================================================================*/
 
-static int setup_dma_config(dev_link_t *link, int start_pg,
+static int setup_dma_config(struct pcmcia_device *link, int start_pg,
 			    int stop_pg)
 {
     struct net_device *dev = link->priv;
@@ -1532,7 +1497,7 @@
 
 /*====================================================================*/
 
-static int setup_shmem_window(dev_link_t *link, int start_pg,
+static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
 			      int stop_pg, int cm_offset)
 {
     struct net_device *dev = link->priv;
@@ -1554,7 +1519,7 @@
     req.Attributes |= WIN_USE_WAIT;
     req.Base = 0; req.Size = window_size;
     req.AccessSpeed = mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
 
     mem.CardOffset = (start_pg << 8) + cm_offset;
     offset = mem.CardOffset % window_size;
@@ -1595,7 +1560,7 @@
     return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     return 1;
 }
diff -urN oldtree/drivers/net/pcmcia/smc91c92_cs.c newtree/drivers/net/pcmcia/smc91c92_cs.c
--- oldtree/drivers/net/pcmcia/smc91c92_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/smc91c92_cs.c	2006-04-01 05:35:44.263386250 -0500
@@ -49,6 +49,7 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -103,7 +104,7 @@
 #define MEMORY_WAIT_TIME       	8
 
 struct smc_private {
-    dev_link_t			link;
+	struct pcmcia_device	*p_dev;
     spinlock_t			lock;
     u_short			manfid;
     u_short			cardid;
@@ -278,8 +279,8 @@
 /*====================================================================*/
 
 static void smc91c92_detach(struct pcmcia_device *p_dev);
-static void smc91c92_config(dev_link_t *link);
-static void smc91c92_release(dev_link_t *link);
+static int smc91c92_config(struct pcmcia_device *link);
+static void smc91c92_release(struct pcmcia_device *link);
 
 static int smc_open(struct net_device *dev);
 static int smc_close(struct net_device *dev);
@@ -308,10 +309,9 @@
 
 ======================================================================*/
 
-static int smc91c92_attach(struct pcmcia_device *p_dev)
+static int smc91c92_probe(struct pcmcia_device *link)
 {
     struct smc_private *smc;
-    dev_link_t *link;
     struct net_device *dev;
 
     DEBUG(0, "smc91c92_attach()\n");
@@ -321,7 +321,7 @@
     if (!dev)
 	return -ENOMEM;
     smc = netdev_priv(dev);
-    link = &smc->link;
+    smc->p_dev = link;
     link->priv = dev;
 
     spin_lock_init(&smc->lock);
@@ -333,7 +333,6 @@
     link->irq.Handler = &smc_interrupt;
     link->irq.Instance = dev;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The SMC91c92-specific entries in the device structure. */
@@ -357,13 +356,7 @@
     smc->mii_if.phy_id_mask = 0x1f;
     smc->mii_if.reg_num_mask = 0x1f;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    smc91c92_config(link);
-
-    return 0;
+    return smc91c92_config(link);
 } /* smc91c92_attach */
 
 /*======================================================================
@@ -375,18 +368,16 @@
 
 ======================================================================*/
 
-static void smc91c92_detach(struct pcmcia_device *p_dev)
+static void smc91c92_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "smc91c92_detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	smc91c92_release(link);
+    smc91c92_release(link);
 
     free_netdev(dev);
 } /* smc91c92_detach */
@@ -414,7 +405,7 @@
 
 /*====================================================================*/
 
-static int first_tuple(client_handle_t handle, tuple_t *tuple,
+static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		cisparse_t *parse)
 {
 	int i;
@@ -425,7 +416,7 @@
 	return pcmcia_parse_tuple(handle, tuple, parse);
 }
 
-static int next_tuple(client_handle_t handle, tuple_t *tuple,
+static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
 		cisparse_t *parse)
 {
 	int i;
@@ -447,7 +438,7 @@
 
 ======================================================================*/
 
-static int mhz_3288_power(dev_link_t *link)
+static int mhz_3288_power(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
@@ -469,7 +460,7 @@
     return 0;
 }
 
-static int mhz_mfc_config(dev_link_t *link)
+static int mhz_mfc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
@@ -504,7 +495,7 @@
     tuple->TupleDataMax = 255;
     tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
 
-    i = first_tuple(link->handle, tuple, parse);
+    i = first_tuple(link, tuple, parse);
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
     while (i == CS_SUCCESS) {
@@ -513,11 +504,11 @@
 	for (k = 0; k < 0x400; k += 0x10) {
 	    if (k & 0x80) continue;
 	    link->io.BasePort1 = k ^ 0x300;
-	    i = pcmcia_request_io(link->handle, &link->io);
+	    i = pcmcia_request_io(link, &link->io);
 	    if (i == CS_SUCCESS) break;
 	}
 	if (i == CS_SUCCESS) break;
-	i = next_tuple(link->handle, tuple, parse);
+	i = next_tuple(link, tuple, parse);
     }
     if (i != CS_SUCCESS)
 	goto free_cfg_mem;
@@ -527,7 +518,7 @@
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = req.Size = 0;
     req.AccessSpeed = 0;
-    i = pcmcia_request_window(&link->handle, &req, &link->win);
+    i = pcmcia_request_window(&link, &req, &link->win);
     if (i != CS_SUCCESS)
 	goto free_cfg_mem;
     smc->base = ioremap(req.Base, req.Size);
@@ -546,9 +537,8 @@
     return i;
 }
 
-static int mhz_setup(dev_link_t *link)
+static int mhz_setup(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_cfg_mem *cfg_mem;
     tuple_t *tuple;
@@ -571,13 +561,13 @@
     /* Read the station address from the CIS.  It is stored as the last
        (fourth) string in the Version 1 Version/ID tuple. */
     tuple->DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+    if (first_tuple(link, tuple, parse) != CS_SUCCESS) {
 	rc = -1;
 	goto free_cfg_mem;
     }
     /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (next_tuple(handle, tuple, parse) != CS_SUCCESS)
-	first_tuple(handle, tuple, parse);
+    if (next_tuple(link, tuple, parse) != CS_SUCCESS)
+	first_tuple(link, tuple, parse);
     if (parse->version_1.ns > 3) {
 	station_addr = parse->version_1.str + parse->version_1.ofs[3];
 	if (cvt_ascii_address(dev, station_addr) == 0) {
@@ -588,11 +578,11 @@
 
     /* Another possibility: for the EM3288, in a special tuple */
     tuple->DesiredTuple = 0x81;
-    if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_first_tuple(link, tuple) != CS_SUCCESS) {
 	rc = -1;
 	goto free_cfg_mem;
     }
-    if (pcmcia_get_tuple_data(handle, tuple) != CS_SUCCESS) {
+    if (pcmcia_get_tuple_data(link, tuple) != CS_SUCCESS) {
 	rc = -1;
 	goto free_cfg_mem;
     }
@@ -616,7 +606,7 @@
 
 ======================================================================*/
 
-static void mot_config(dev_link_t *link)
+static void mot_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
@@ -637,7 +627,7 @@
     mdelay(100);
 }
 
-static int mot_setup(dev_link_t *link)
+static int mot_setup(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -671,7 +661,7 @@
 
 /*====================================================================*/
 
-static int smc_config(dev_link_t *link)
+static int smc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_cfg_mem *cfg_mem;
@@ -696,16 +686,16 @@
     tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
 
     link->io.NumPorts1 = 16;
-    i = first_tuple(link->handle, tuple, parse);
+    i = first_tuple(link, tuple, parse);
     while (i != CS_NO_MORE_ITEMS) {
 	if (i == CS_SUCCESS) {
 	    link->conf.ConfigIndex = cf->index;
 	    link->io.BasePort1 = cf->io.win[0].base;
 	    link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-	    i = pcmcia_request_io(link->handle, &link->io);
+	    i = pcmcia_request_io(link, &link->io);
 	    if (i == CS_SUCCESS) break;
 	}
-	i = next_tuple(link->handle, tuple, parse);
+	i = next_tuple(link, tuple, parse);
     }
     if (i == CS_SUCCESS)
 	dev->base_addr = link->io.BasePort1;
@@ -714,9 +704,8 @@
     return i;
 }
 
-static int smc_setup(dev_link_t *link)
+static int smc_setup(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_cfg_mem *cfg_mem;
     tuple_t *tuple;
@@ -739,11 +728,11 @@
 
     /* Check for a LAN function extension tuple */
     tuple->DesiredTuple = CISTPL_FUNCE;
-    i = first_tuple(handle, tuple, parse);
+    i = first_tuple(link, tuple, parse);
     while (i == CS_SUCCESS) {
 	if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
 	    break;
-	i = next_tuple(handle, tuple, parse);
+	i = next_tuple(link, tuple, parse);
     }
     if (i == CS_SUCCESS) {
 	node_id = (cistpl_lan_node_id_t *)parse->funce.data;
@@ -756,7 +745,7 @@
     }
     /* Try the third string in the Version 1 Version/ID tuple. */
     tuple->DesiredTuple = CISTPL_VERS_1;
-    if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+    if (first_tuple(link, tuple, parse) != CS_SUCCESS) {
 	rc = -1;
 	goto free_cfg_mem;
     }
@@ -774,7 +763,7 @@
 
 /*====================================================================*/
 
-static int osi_config(dev_link_t *link)
+static int osi_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     static kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
@@ -794,22 +783,21 @@
 
     for (i = j = 0; j < 4; j++) {
 	link->io.BasePort2 = com[j];
-	i = pcmcia_request_io(link->handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
 	if (i == CS_SUCCESS) break;
     }
     if (i != CS_SUCCESS) {
 	/* Fallback: turn off hard decode */
 	link->conf.ConfigIndex = 0x03;
 	link->io.NumPorts2 = 0;
-	i = pcmcia_request_io(link->handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
     }
     dev->base_addr = link->io.BasePort1 + 0x10;
     return i;
 }
 
-static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
+static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_cfg_mem *cfg_mem;
     tuple_t *tuple;
@@ -830,12 +818,12 @@
 
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple->DesiredTuple = 0x90;
-    i = pcmcia_get_first_tuple(handle, tuple);
+    i = pcmcia_get_first_tuple(link, tuple);
     while (i == CS_SUCCESS) {
-	i = pcmcia_get_tuple_data(handle, tuple);
+	i = pcmcia_get_tuple_data(link, tuple);
 	if ((i != CS_SUCCESS) || (buf[0] == 0x04))
 	    break;
-	i = pcmcia_get_next_tuple(handle, tuple);
+	i = pcmcia_get_next_tuple(link, tuple);
     }
     if (i != CS_SUCCESS) {
 	rc = -1;
@@ -868,57 +856,47 @@
    return rc;
 }
 
-static int smc91c92_suspend(struct pcmcia_device *p_dev)
+static int smc91c92_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int smc91c92_resume(struct pcmcia_device *p_dev)
+static int smc91c92_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 	struct smc_private *smc = netdev_priv(dev);
 	int i;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if ((smc->manfid == MANFID_MEGAHERTZ) &&
-		    (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-			mhz_3288_power(link);
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (smc->manfid == MANFID_MOTOROLA)
-			mot_config(link);
-		if ((smc->manfid == MANFID_OSITECH) &&
-		    (smc->cardid != PRODID_OSITECH_SEVEN)) {
-			/* Power up the card and enable interrupts */
-			set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
-			set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
-		}
-		if (((smc->manfid == MANFID_OSITECH) &&
-		     (smc->cardid == PRODID_OSITECH_SEVEN)) ||
-		    ((smc->manfid == MANFID_PSION) &&
-		     (smc->cardid == PRODID_PSION_NET100))) {
-			/* Download the Seven of Diamonds firmware */
-			for (i = 0; i < sizeof(__Xilinx7OD); i++) {
-				outb(__Xilinx7OD[i], link->io.BasePort1+2);
-				udelay(50);
-			}
-		}
-		if (link->open) {
-			smc_reset(dev);
-			netif_device_attach(dev);
+	if ((smc->manfid == MANFID_MEGAHERTZ) &&
+	    (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+		mhz_3288_power(link);
+	if (smc->manfid == MANFID_MOTOROLA)
+		mot_config(link);
+	if ((smc->manfid == MANFID_OSITECH) &&
+	    (smc->cardid != PRODID_OSITECH_SEVEN)) {
+		/* Power up the card and enable interrupts */
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
+	}
+	if (((smc->manfid == MANFID_OSITECH) &&
+	     (smc->cardid == PRODID_OSITECH_SEVEN)) ||
+	    ((smc->manfid == MANFID_PSION) &&
+	     (smc->cardid == PRODID_PSION_NET100))) {
+		/* Download the Seven of Diamonds firmware */
+		for (i = 0; i < sizeof(__Xilinx7OD); i++) {
+			outb(__Xilinx7OD[i], link->io.BasePort1+2);
+			udelay(50);
 		}
 	}
+	if (link->open) {
+		smc_reset(dev);
+		netif_device_attach(dev);
+	}
 
 	return 0;
 }
@@ -931,7 +909,7 @@
 
 ======================================================================*/
 
-static int check_sig(dev_link_t *link)
+static int check_sig(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     kio_addr_t ioaddr = dev->base_addr;
@@ -964,13 +942,15 @@
     }
 
     if (width) {
-	printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
-	smc91c92_suspend(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	pcmcia_request_io(link->handle, &link->io);
-	smc91c92_resume(link->handle);
-	return check_sig(link);
+	    modconf_t mod = {
+		    .Attributes = CONF_IO_CHANGE_WIDTH,
+	    };
+	    printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+
+	    smc91c92_suspend(link);
+	    pcmcia_modify_configuration(link, &mod);
+	    smc91c92_resume(link);
+	    return check_sig(link);
     }
     return -ENODEV;
 }
@@ -984,11 +964,10 @@
 ======================================================================*/
 
 #define CS_EXIT_TEST(ret, svc, label) \
-if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }
+if (ret != CS_SUCCESS) { cs_error(link, svc, ret); goto label; }
 
-static void smc91c92_config(dev_link_t *link)
+static int smc91c92_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
     struct smc_cfg_mem *cfg_mem;
@@ -1015,21 +994,18 @@
     tuple->TupleDataMax = 64;
 
     tuple->DesiredTuple = CISTPL_CONFIG;
-    i = first_tuple(handle, tuple, parse);
+    i = first_tuple(link, tuple, parse);
     CS_EXIT_TEST(i, ParseTuple, config_failed);
     link->conf.ConfigBase = parse->config.base;
     link->conf.Present = parse->config.rmask[0];
 
     tuple->DesiredTuple = CISTPL_MANFID;
     tuple->Attributes = TUPLE_RETURN_COMMON;
-    if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+    if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
 	smc->manfid = parse->manfid.manf;
 	smc->cardid = parse->manfid.card;
     }
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     if ((smc->manfid == MANFID_OSITECH) &&
 	(smc->cardid != PRODID_OSITECH_SEVEN)) {
 	i = osi_config(link);
@@ -1043,9 +1019,9 @@
     }
     CS_EXIT_TEST(i, RequestIO, config_failed);
 
-    i = pcmcia_request_irq(link->handle, &link->irq);
+    i = pcmcia_request_irq(link, &link->irq);
     CS_EXIT_TEST(i, RequestIRQ, config_failed);
-    i = pcmcia_request_configuration(link->handle, &link->conf);
+    i = pcmcia_request_configuration(link, &link->conf);
     CS_EXIT_TEST(i, RequestConfiguration, config_failed);
 
     if (smc->manfid == MANFID_MOTOROLA)
@@ -1124,13 +1100,12 @@
 	SMC_SELECT_BANK(0);
     }
 
-    link->dev = &smc->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &smc->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto config_undo;
     }
 
@@ -1160,15 +1135,14 @@
 	}
     }
     kfree(cfg_mem);
-    return;
+    return 0;
 
 config_undo:
     unregister_netdev(dev);
 config_failed:			/* CS_EXIT_TEST() calls jump to here... */
     smc91c92_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
     kfree(cfg_mem);
-
+    return -ENODEV;
 } /* smc91c92_config */
 
 /*======================================================================
@@ -1179,22 +1153,15 @@
 
 ======================================================================*/
 
-static void smc91c92_release(dev_link_t *link)
+static void smc91c92_release(struct pcmcia_device *link)
 {
-
-    DEBUG(0, "smc91c92_release(0x%p)\n", link);
-
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    if (link->win) {
-	struct net_device *dev = link->priv;
-	struct smc_private *smc = netdev_priv(dev);
-	iounmap(smc->base);
-	pcmcia_release_window(link->win);
-    }
-
-    link->state &= ~DEV_CONFIG;
+	DEBUG(0, "smc91c92_release(0x%p)\n", link);
+	if (link->win) {
+		struct net_device *dev = link->priv;
+		struct smc_private *smc = netdev_priv(dev);
+		iounmap(smc->base);
+	}
+	pcmcia_disable_device(link);
 }
 
 /*======================================================================
@@ -1283,7 +1250,7 @@
 static int smc_open(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    dev_link_t *link = &smc->link;
+    struct pcmcia_device *link = smc->p_dev;
 
 #ifdef PCMCIA_DEBUG
     DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
@@ -1292,7 +1259,7 @@
 #endif
 
     /* Check that the PCMCIA card is still here. */
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
     /* Physical device present signature. */
     if (check_sig(link) < 0) {
@@ -1320,7 +1287,7 @@
 static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    dev_link_t *link = &smc->link;
+    struct pcmcia_device *link = smc->p_dev;
     kio_addr_t ioaddr = dev->base_addr;
 
     DEBUG(0, "%s: smc_close(), status %4.4x.\n",
@@ -2311,7 +2278,7 @@
 	.drv		= {
 		.name	= "smc91c92_cs",
 	},
-	.probe		= smc91c92_attach,
+	.probe		= smc91c92_probe,
 	.remove		= smc91c92_detach,
 	.id_table       = smc91c92_ids,
 	.suspend	= smc91c92_suspend,
diff -urN oldtree/drivers/net/pcmcia/xirc2ps_cs.c newtree/drivers/net/pcmcia/xirc2ps_cs.c
--- oldtree/drivers/net/pcmcia/xirc2ps_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/pcmcia/xirc2ps_cs.c	2006-04-01 05:35:44.267386500 -0500
@@ -289,9 +289,9 @@
  * and ejection events.  They are invoked from the event handler.
  */
 
-static int has_ce2_string(dev_link_t * link);
-static void xirc2ps_config(dev_link_t * link);
-static void xirc2ps_release(dev_link_t * link);
+static int has_ce2_string(struct pcmcia_device * link);
+static int xirc2ps_config(struct pcmcia_device * link);
+static void xirc2ps_release(struct pcmcia_device * link);
 
 /****************
  * The attach() and detach() entry points are used to create and destroy
@@ -313,10 +313,10 @@
 /****************
  * A linked list of "instances" of the device.  Each actual
  * PCMCIA card corresponds to one device instance, and is described
- * by one dev_link_t structure (defined in ds.h).
+ * by one struct pcmcia_device structure (defined in ds.h).
  *
  * You may not want to use a linked list for this -- for example, the
- * memory card driver uses an array of dev_link_t pointers, where minor
+ * memory card driver uses an array of struct pcmcia_device pointers, where minor
  * device numbers are used to derive the corresponding array index.
  */
 
@@ -326,13 +326,13 @@
  * example, ethernet cards, modems).  In other cases, there may be
  * many actual or logical devices (SCSI adapters, memory cards with
  * multiple partitions).  The dev_node_t structures need to be kept
- * in a linked list starting at the 'dev' field of a dev_link_t
+ * in a linked list starting at the 'dev' field of a struct pcmcia_device
  * structure.  We allocate them in the card's private data structure,
  * because they generally can't be allocated dynamically.
  */
 
 typedef struct local_info_t {
-    dev_link_t link;
+	struct pcmcia_device	*p_dev;
     dev_node_t node;
     struct net_device_stats stats;
     int card_type;
@@ -355,7 +355,7 @@
 static struct net_device_stats *do_get_stats(struct net_device *dev);
 static void set_addresses(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
-static int set_card_type(dev_link_t *link, const void *s);
+static int set_card_type(struct pcmcia_device *link, const void *s);
 static int do_config(struct net_device *dev, struct ifmap *map);
 static int do_open(struct net_device *dev);
 static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -368,7 +368,7 @@
 
 /*=============== Helper functions =========================*/
 static int
-first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int err;
 
@@ -379,7 +379,7 @@
 }
 
 static int
-next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 {
 	int err;
 
@@ -553,9 +553,8 @@
  */
 
 static int
-xirc2ps_attach(struct pcmcia_device *p_dev)
+xirc2ps_probe(struct pcmcia_device *link)
 {
-    dev_link_t *link;
     struct net_device *dev;
     local_info_t *local;
 
@@ -566,12 +565,11 @@
     if (!dev)
 	    return -ENOMEM;
     local = netdev_priv(dev);
-    link = &local->link;
+    local->p_dev = link;
     link->priv = dev;
 
     /* General socket configuration */
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
@@ -593,13 +591,7 @@
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    xirc2ps_config(link);
-
-    return 0;
+    return xirc2ps_config(link);
 } /* xirc2ps_attach */
 
 /****************
@@ -610,18 +602,16 @@
  */
 
 static void
-xirc2ps_detach(struct pcmcia_device *p_dev)
+xirc2ps_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
     struct net_device *dev = link->priv;
 
     DEBUG(0, "detach(0x%p)\n", link);
 
-    if (link->dev)
+    if (link->dev_node)
 	unregister_netdev(dev);
 
-    if (link->state & DEV_CONFIG)
-	xirc2ps_release(link);
+    xirc2ps_release(link);
 
     free_netdev(dev);
 } /* xirc2ps_detach */
@@ -645,7 +635,7 @@
  *
  */
 static int
-set_card_type(dev_link_t *link, const void *s)
+set_card_type(struct pcmcia_device *link, const void *s)
 {
     struct net_device *dev = link->priv;
     local_info_t *local = netdev_priv(dev);
@@ -714,9 +704,8 @@
  * Returns: true if this is a CE2
  */
 static int
-has_ce2_string(dev_link_t * link)
+has_ce2_string(struct pcmcia_device * link)
 {
-    client_handle_t handle = link->handle;
     tuple_t tuple;
     cisparse_t parse;
     u_char buf[256];
@@ -726,7 +715,7 @@
     tuple.TupleDataMax = 254;
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_VERS_1;
-    if (!first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 2) {
+    if (!first_tuple(link, &tuple, &parse) && parse.version_1.ns > 2) {
 	if (strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2"))
 	    return 1;
     }
@@ -738,10 +727,9 @@
  * is received, to configure the PCMCIA socket, and to make the
  * ethernet device available to the system.
  */
-static void
-xirc2ps_config(dev_link_t * link)
+static int
+xirc2ps_config(struct pcmcia_device * link)
 {
-    client_handle_t handle = link->handle;
     struct net_device *dev = link->priv;
     local_info_t *local = netdev_priv(dev);
     tuple_t tuple;
@@ -767,7 +755,7 @@
 
     /* Is this a valid	card */
     tuple.DesiredTuple = CISTPL_MANFID;
-    if ((err=first_tuple(handle, &tuple, &parse))) {
+    if ((err=first_tuple(link, &tuple, &parse))) {
 	printk(KNOT_XIRC "manfid not found in CIS\n");
 	goto failure;
     }
@@ -803,15 +791,15 @@
 
     /* get configuration stuff */
     tuple.DesiredTuple = CISTPL_CONFIG;
-    if ((err=first_tuple(handle, &tuple, &parse)))
+    if ((err=first_tuple(link, &tuple, &parse)))
 	goto cis_error;
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present =    parse.config.rmask[0];
 
     /* get the ethernet address from the CIS */
     tuple.DesiredTuple = CISTPL_FUNCE;
-    for (err = first_tuple(handle, &tuple, &parse); !err;
-			     err = next_tuple(handle, &tuple, &parse)) {
+    for (err = first_tuple(link, &tuple, &parse); !err;
+			     err = next_tuple(link, &tuple, &parse)) {
 	/* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries:
 	 * the first one with a length of zero the second correct -
 	 * so I skip all entries with length 0 */
@@ -821,8 +809,8 @@
     }
     if (err) { /* not found: try to get the node-id from tuple 0x89 */
 	tuple.DesiredTuple = 0x89;  /* data layout looks like tuple 0x22 */
-	if ((err = pcmcia_get_first_tuple(handle, &tuple)) == 0 &&
-		(err = pcmcia_get_tuple_data(handle, &tuple)) == 0) {
+	if ((err = pcmcia_get_first_tuple(link, &tuple)) == 0 &&
+		(err = pcmcia_get_tuple_data(link, &tuple)) == 0) {
 	    if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID)
 		memcpy(&parse, buf, 8);
 	    else
@@ -831,8 +819,8 @@
     }
     if (err) { /* another try	(James Lehmer's CE2 version 4.1)*/
 	tuple.DesiredTuple = CISTPL_FUNCE;
-	for (err = first_tuple(handle, &tuple, &parse); !err;
-				 err = next_tuple(handle, &tuple, &parse)) {
+	for (err = first_tuple(link, &tuple, &parse); !err;
+				 err = next_tuple(link, &tuple, &parse)) {
 	    if (parse.funce.type == 0x02 && parse.funce.data[0] == 1
 		&& parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) {
 		buf[1] = 4;
@@ -853,9 +841,6 @@
     for (i=0; i < 6; i++)
 	dev->dev_addr[i] = node_id->id[i];
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     link->io.IOAddrLines =10;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
     link->irq.Attributes = IRQ_HANDLE_PRESENT;
@@ -875,14 +860,14 @@
 	     * Ethernet port */
 	    link->io.NumPorts1 = 16; /* no Mako stuff anymore */
 	    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	    for (err = first_tuple(handle, &tuple, &parse); !err;
-				 err = next_tuple(handle, &tuple, &parse)) {
+	    for (err = first_tuple(link, &tuple, &parse); !err;
+				 err = next_tuple(link, &tuple, &parse)) {
 		if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
 		    for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
 			link->conf.ConfigIndex = cf->index ;
 			link->io.BasePort2 = cf->io.win[0].base;
 			link->io.BasePort1 = ioaddr;
-			if (!(err=pcmcia_request_io(link->handle, &link->io)))
+			if (!(err=pcmcia_request_io(link, &link->io)))
 			    goto port_found;
 		    }
 		}
@@ -896,15 +881,15 @@
 	     */
 	    for (pass=0; pass < 2; pass++) {
 		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-		for (err = first_tuple(handle, &tuple, &parse); !err;
-				     err = next_tuple(handle, &tuple, &parse)){
+		for (err = first_tuple(link, &tuple, &parse); !err;
+				     err = next_tuple(link, &tuple, &parse)){
 		    if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8){
 			link->conf.ConfigIndex = cf->index ;
 			link->io.BasePort2 = cf->io.win[0].base;
 			link->io.BasePort1 = link->io.BasePort2
 				    + (pass ? (cf->index & 0x20 ? -24:8)
 					    : (cf->index & 0x20 ?   8:-24));
-			if (!(err=pcmcia_request_io(link->handle, &link->io)))
+			if (!(err=pcmcia_request_io(link, &link->io)))
 			    goto port_found;
 		    }
 		}
@@ -919,12 +904,12 @@
 	link->io.NumPorts1 = 16;
 	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
 	    link->io.BasePort1 = ioaddr;
-	    if (!(err=pcmcia_request_io(link->handle, &link->io)))
+	    if (!(err=pcmcia_request_io(link, &link->io)))
 		goto port_found;
 	}
 	link->io.BasePort1 = 0; /* let CS decide */
-	if ((err=pcmcia_request_io(link->handle, &link->io))) {
-	    cs_error(link->handle, RequestIO, err);
+	if ((err=pcmcia_request_io(link, &link->io))) {
+	    cs_error(link, RequestIO, err);
 	    goto config_error;
 	}
     }
@@ -936,8 +921,8 @@
      * Now allocate an interrupt line.	Note that this does not
      * actually assign a handler to the interrupt.
      */
-    if ((err=pcmcia_request_irq(link->handle, &link->irq))) {
-	cs_error(link->handle, RequestIRQ, err);
+    if ((err=pcmcia_request_irq(link, &link->irq))) {
+	cs_error(link, RequestIRQ, err);
 	goto config_error;
     }
 
@@ -945,8 +930,8 @@
      * This actually configures the PCMCIA socket -- setting up
      * the I/O windows and the interrupt mapping.
      */
-    if ((err=pcmcia_request_configuration(link->handle, &link->conf))) {
-	cs_error(link->handle, RequestConfiguration, err);
+    if ((err=pcmcia_request_configuration(link, &link->conf))) {
+	cs_error(link, RequestConfiguration, err);
 	goto config_error;
     }
 
@@ -963,15 +948,15 @@
 	reg.Action = CS_WRITE;
 	reg.Offset = CISREG_IOBASE_0;
 	reg.Value = link->io.BasePort2 & 0xff;
-	if ((err = pcmcia_access_configuration_register(link->handle, &reg))) {
-	    cs_error(link->handle, AccessConfigurationRegister, err);
+	if ((err = pcmcia_access_configuration_register(link, &reg))) {
+	    cs_error(link, AccessConfigurationRegister, err);
 	    goto config_error;
 	}
 	reg.Action = CS_WRITE;
 	reg.Offset = CISREG_IOBASE_1;
 	reg.Value = (link->io.BasePort2 >> 8) & 0xff;
-	if ((err = pcmcia_access_configuration_register(link->handle, &reg))) {
-	    cs_error(link->handle, AccessConfigurationRegister, err);
+	if ((err = pcmcia_access_configuration_register(link, &reg))) {
+	    cs_error(link, AccessConfigurationRegister, err);
 	    goto config_error;
 	}
 
@@ -982,15 +967,15 @@
 	req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
 	req.Base = req.Size = 0;
 	req.AccessSpeed = 0;
-	if ((err = pcmcia_request_window(&link->handle, &req, &link->win))) {
-	    cs_error(link->handle, RequestWindow, err);
+	if ((err = pcmcia_request_window(&link, &req, &link->win))) {
+	    cs_error(link, RequestWindow, err);
 	    goto config_error;
 	}
 	local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800;
 	mem.CardOffset = 0x0;
 	mem.Page = 0;
 	if ((err = pcmcia_map_mem_page(link->win, &mem))) {
-	    cs_error(link->handle, MapMemPage, err);
+	    cs_error(link, MapMemPage, err);
 	    goto config_error;
 	}
 
@@ -1050,13 +1035,12 @@
     if (local->dingo)
 	do_reset(dev, 1); /* a kludge to make the cem56 work */
 
-    link->dev = &local->node;
-    link->state &= ~DEV_CONFIG_PENDING;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    link->dev_node = &local->node;
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if ((err=register_netdev(dev))) {
 	printk(KNOT_XIRC "register_netdev() failed\n");
-	link->dev = NULL;
+	link->dev_node = NULL;
 	goto config_error;
     }
 
@@ -1069,17 +1053,16 @@
 	printk("%c%02X", i?':':' ', dev->dev_addr[i]);
     printk("\n");
 
-    return;
+    return 0;
 
   config_error:
-    link->state &= ~DEV_CONFIG_PENDING;
     xirc2ps_release(link);
-    return;
+    return -ENODEV;
 
   cis_error:
     printk(KNOT_XIRC "unable to parse CIS\n");
   failure:
-    link->state &= ~DEV_CONFIG_PENDING;
+    return -ENODEV;
 } /* xirc2ps_config */
 
 /****************
@@ -1088,57 +1071,41 @@
  * still open, this will be postponed until it is closed.
  */
 static void
-xirc2ps_release(dev_link_t *link)
+xirc2ps_release(struct pcmcia_device *link)
 {
+	DEBUG(0, "release(0x%p)\n", link);
 
-    DEBUG(0, "release(0x%p)\n", link);
-
-    if (link->win) {
-	struct net_device *dev = link->priv;
-	local_info_t *local = netdev_priv(dev);
-	if (local->dingo)
-	    iounmap(local->dingo_ccr - 0x0800);
-	pcmcia_release_window(link->win);
-    }
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    link->state &= ~DEV_CONFIG;
-
+	if (link->win) {
+		struct net_device *dev = link->priv;
+		local_info_t *local = netdev_priv(dev);
+		if (local->dingo)
+			iounmap(local->dingo_ccr - 0x0800);
+	}
+	pcmcia_disable_device(link);
 } /* xirc2ps_release */
 
 /*====================================================================*/
 
 
-static int xirc2ps_suspend(struct pcmcia_device *p_dev)
+static int xirc2ps_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open) {
-			netif_device_detach(dev);
-			do_powerdown(dev);
-		}
-		pcmcia_release_configuration(link->handle);
+	if (link->open) {
+		netif_device_detach(dev);
+		do_powerdown(dev);
 	}
 
 	return 0;
 }
 
-static int xirc2ps_resume(struct pcmcia_device *p_dev)
+static int xirc2ps_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			do_reset(dev,1);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		do_reset(dev,1);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -1552,13 +1519,13 @@
 do_open(struct net_device *dev)
 {
     local_info_t *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
 
     DEBUG(0, "do_open(%p)\n", dev);
 
     /* Check that the PCMCIA card is still here. */
     /* Physical device present signature. */
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
     /* okay */
@@ -1882,7 +1849,7 @@
 {
     kio_addr_t ioaddr = dev->base_addr;
     local_info_t *lp = netdev_priv(dev);
-    dev_link_t *link = &lp->link;
+    struct pcmcia_device *link = lp->p_dev;
 
     DEBUG(0, "do_stop(%p)\n", dev);
 
@@ -1935,7 +1902,7 @@
 	.drv		= {
 		.name	= "xirc2ps_cs",
 	},
-	.probe		= xirc2ps_attach,
+	.probe		= xirc2ps_probe,
 	.remove		= xirc2ps_detach,
 	.id_table       = xirc2ps_ids,
 	.suspend	= xirc2ps_suspend,
diff -urN oldtree/drivers/net/tokenring/Kconfig newtree/drivers/net/tokenring/Kconfig
--- oldtree/drivers/net/tokenring/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/tokenring/Kconfig	2006-04-01 05:36:15.329327750 -0500
@@ -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/tulip/media.c newtree/drivers/net/tulip/media.c
--- oldtree/drivers/net/tulip/media.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/tulip/media.c	2006-04-01 05:35:41.723227500 -0500
@@ -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)
 {
@@ -272,13 +274,29 @@
 				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/tulip.h newtree/drivers/net/tulip/tulip.h
--- oldtree/drivers/net/tulip/tulip.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/tulip/tulip.h	2006-04-01 05:35:41.723227500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/tulip/tulip_core.c	2006-04-01 05:35:41.723227500 -0500
@@ -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/wireless/Kconfig newtree/drivers/net/wireless/Kconfig
--- oldtree/drivers/net/wireless/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/Kconfig	2006-04-01 05:35:49.667724000 -0500
@@ -473,6 +473,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/Makefile	2006-04-01 05:35:49.667724000 -0500
@@ -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_cs.c newtree/drivers/net/wireless/airo_cs.c
--- oldtree/drivers/net/wireless/airo_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/airo_cs.c	2006-04-01 05:35:44.267386500 -0500
@@ -80,8 +80,8 @@
    event handler. 
 */
 
-static void airo_config(dev_link_t *link);
-static void airo_release(dev_link_t *link);
+static int airo_config(struct pcmcia_device *link);
+static void airo_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -101,10 +101,10 @@
 /*
    A linked list of "instances" of the  aironet device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
+   by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
+   memory card driver uses an array of struct pcmcia_device pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -114,7 +114,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
 
@@ -141,24 +141,16 @@
   
   ======================================================================*/
 
-static int airo_attach(struct pcmcia_device *p_dev)
+static int airo_probe(struct pcmcia_device *p_dev)
 {
-	dev_link_t *link;
 	local_info_t *local;
 
 	DEBUG(0, "airo_attach()\n");
 
-	/* Initialize the dev_link_t structure */
-	link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-	if (!link) {
-		printk(KERN_ERR "airo_cs: no memory for new device\n");
-		return -ENOMEM;
-	}
-	
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-	link->irq.Handler = NULL;
+	p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	p_dev->irq.Handler = NULL;
 	
 	/*
 	  General socket configuration defaults can go here.  In this
@@ -167,26 +159,18 @@
 	  and attributes of IO windows) are fixed by the nature of the
 	  device, and can be hard-wired here.
 	*/
-	link->conf.Attributes = 0;
-	link->conf.Vcc = 50;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	p_dev->conf.Attributes = 0;
+	p_dev->conf.IntType = INT_MEMORY_AND_IO;
 	
 	/* Allocate space for private device-specific data */
 	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local) {
 		printk(KERN_ERR "airo_cs: no memory for new device\n");
-		kfree (link);
 		return -ENOMEM;
 	}
-	link->priv = local;
+	p_dev->priv = local;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	airo_config(link);
-
-	return 0;
+	return airo_config(p_dev);
 } /* airo_attach */
 
 /*======================================================================
@@ -198,14 +182,11 @@
   
   ======================================================================*/
 
-static void airo_detach(struct pcmcia_device *p_dev)
+static void airo_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "airo_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		airo_release(link);
+	airo_release(link);
 
 	if ( ((local_info_t*)link->priv)->eth_dev ) {
 		stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 );
@@ -213,7 +194,6 @@
 	((local_info_t*)link->priv)->eth_dev = NULL;
 
 	kfree(link->priv);
-	kfree(link);
 } /* airo_detach */
 
 /*======================================================================
@@ -227,9 +207,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void airo_config(dev_link_t *link)
+static int airo_config(struct pcmcia_device *link)
 {
-	client_handle_t handle;
 	tuple_t tuple;
 	cisparse_t parse;
 	local_info_t *dev;
@@ -237,8 +216,7 @@
 	u_char buf[64];
 	win_req_t req;
 	memreq_t map;
-	
-	handle = link->handle;
+
 	dev = link->priv;
 
 	DEBUG(0, "airo_config(0x%p)\n", link);
@@ -252,15 +230,12 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
-	
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	
+
 	/*
 	  In this loop, we scan the CIS for configuration table entries,
 	  each of which describes a valid card configuration, including
@@ -274,12 +249,12 @@
 	  will only use the CIS to fill in implementation-defined details.
 	*/
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t dflt = { 0 };
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 		
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
@@ -294,16 +269,11 @@
 		
 		/* Use power settings for Vcc and Vpp if present */
 		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
-		else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
-		
 		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
 		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
 		
 		/* Do we need to allocate an interrupt? */
@@ -329,12 +299,12 @@
 		}
 		
 		/* This reserves IO space but doesn't actually enable it */
-		if (pcmcia_request_io(link->handle, &link->io) != 0)
+		if (pcmcia_request_io(link, &link->io) != 0)
 			goto next_entry;
 		
 		/*
 		  Now set up a common memory window, if needed.  There is room
-		  in the dev_link_t structure for one memory window handle,
+		  in the struct pcmcia_device structure for one memory window handle,
 		  but if the base addresses need to be saved, or if multiple
 		  windows are needed, the info should go in the private data
 		  structure for this device.
@@ -350,7 +320,7 @@
 			req.Base = mem->win[0].host_addr;
 			req.Size = mem->win[0].len;
 			req.AccessSpeed = 0;
-			if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
+			if (pcmcia_request_window(&link, &req, &link->win) != 0)
 				goto next_entry;
 			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
 			if (pcmcia_map_mem_page(link->win, &map) != 0)
@@ -360,7 +330,7 @@
 		break;
 		
 	next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 	
     /*
@@ -369,33 +339,32 @@
       irq structure is initialized.
     */
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 	
 	/*
 	  This actually configures the PCMCIA socket -- setting up
 	  the I/O windows and the interrupt mapping, and putting the
 	  card and host interface into "Memory and IO" mode.
 	*/
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 	((local_info_t*)link->priv)->eth_dev = 
 		init_airo_card( link->irq.AssignedIRQ,
-				link->io.BasePort1, 1, &handle_to_dev(handle) );
+				link->io.BasePort1, 1, &handle_to_dev(link) );
 	if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed;
 	
 	/*
 	  At this point, the dev_node_t structure(s) need to be
-	  initialized and arranged in a linked list at link->dev.
+	  initialized and arranged in a linked list at link->dev_node.
 	*/
 	strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
 	dev->node.major = dev->node.minor = 0;
-	link->dev = &dev->node;
+	link->dev_node = &dev->node;
 	
 	/* Finally, report what we've done */
-	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-	       dev->node.dev_name, link->conf.ConfigIndex,
-	       link->conf.Vcc/10, link->conf.Vcc%10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	printk(KERN_INFO "%s: index 0x%02x: ",
+	       dev->node.dev_name, link->conf.ConfigIndex);
+	if (link->conf.Vpp)
+		printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		printk(", irq %d", link->irq.AssignedIRQ);
 	if (link->io.NumPorts1)
@@ -408,14 +377,12 @@
 		printk(", mem 0x%06lx-0x%06lx", req.Base,
 		       req.Base+req.Size-1);
 	printk("\n");
-	
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
-	
+	return 0;
+
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	airo_release(link);
-	
+	return -ENODEV;
 } /* airo_config */
 
 /*======================================================================
@@ -426,51 +393,26 @@
   
   ======================================================================*/
 
-static void airo_release(dev_link_t *link)
+static void airo_release(struct pcmcia_device *link)
 {
 	DEBUG(0, "airo_release(0x%p)\n", link);
-	
-	/* Unlink the device chain */
-	link->dev = NULL;
-	
-	/*
-	  In a normal driver, additional code may be needed to release
-	  other kernel data structures associated with this device. 
-	*/
-	
-	/* Don't bother checking to see if these succeed or not */
-	if (link->win)
-		pcmcia_release_window(link->win);
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int airo_suspend(struct pcmcia_device *p_dev)
+static int airo_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *local = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		netif_device_detach(local->eth_dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	netif_device_detach(local->eth_dev);
 
 	return 0;
 }
 
-static int airo_resume(struct pcmcia_device *p_dev)
+static int airo_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	local_info_t *local = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
+	if (link->open) {
 		reset_airo_card(local->eth_dev);
 		netif_device_attach(local->eth_dev);
 	}
@@ -492,7 +434,7 @@
 	.drv		= {
 		.name	= "airo_cs",
 	},
-	.probe		= airo_attach,
+	.probe		= airo_probe,
 	.remove		= airo_detach,
 	.id_table       = airo_ids,
 	.suspend	= airo_suspend,
diff -urN oldtree/drivers/net/wireless/atmel_cs.c newtree/drivers/net/wireless/atmel_cs.c
--- oldtree/drivers/net/wireless/atmel_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/atmel_cs.c	2006-04-01 05:35:44.267386500 -0500
@@ -91,8 +91,8 @@
    event handler. 
 */
 
-static void atmel_config(dev_link_t *link);
-static void atmel_release(dev_link_t *link);
+static int atmel_config(struct pcmcia_device *link);
+static void atmel_release(struct pcmcia_device *link);
 
 /*
    The attach() and detach() entry points are used to create and destroy
@@ -112,10 +112,10 @@
 /*
    A linked list of "instances" of the  atmelnet device.  Each actual
    PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
+   by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
+   memory card driver uses an array of struct pcmcia_device pointers, where minor
    device numbers are used to derive the corresponding array index.
 */
 
@@ -125,7 +125,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally shouldn't be allocated dynamically.
 
@@ -152,24 +152,16 @@
   
   ======================================================================*/
 
-static int atmel_attach(struct pcmcia_device *p_dev)
+static int atmel_probe(struct pcmcia_device *p_dev)
 {
-	dev_link_t *link;
 	local_info_t *local;
 
 	DEBUG(0, "atmel_attach()\n");
 
-	/* Initialize the dev_link_t structure */
-	link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-	if (!link) {
-		printk(KERN_ERR "atmel_cs: no memory for new device\n");
-		return -ENOMEM;
-	}
-
 	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-	link->irq.Handler = NULL;
+	p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	p_dev->irq.Handler = NULL;
 
 	/*
 	  General socket configuration defaults can go here.  In this
@@ -178,26 +170,18 @@
 	  and attributes of IO windows) are fixed by the nature of the
 	  device, and can be hard-wired here.
 	*/
-	link->conf.Attributes = 0;
-	link->conf.Vcc = 50;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	p_dev->conf.Attributes = 0;
+	p_dev->conf.IntType = INT_MEMORY_AND_IO;
 
 	/* Allocate space for private device-specific data */
 	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local) {
 		printk(KERN_ERR "atmel_cs: no memory for new device\n");
-		kfree (link);
 		return -ENOMEM;
 	}
-	link->priv = local;
+	p_dev->priv = local;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	atmel_config(link);
-
-	return 0;
+	return atmel_config(p_dev);
 } /* atmel_attach */
 
 /*======================================================================
@@ -209,17 +193,13 @@
   
   ======================================================================*/
 
-static void atmel_detach(struct pcmcia_device *p_dev)
+static void atmel_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "atmel_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		atmel_release(link);
+	atmel_release(link);
 
 	kfree(link->priv);
-	kfree(link);
 }
 
 /*======================================================================
@@ -236,19 +216,17 @@
 /* Call-back function to interrogate PCMCIA-specific information
    about the current existance of the card */
 static int card_present(void *arg)
-{ 
-	dev_link_t *link = (dev_link_t *)arg;
-	if (link->state & DEV_SUSPEND)
-		return 0;
-	else if (link->state & DEV_PRESENT)
+{
+	struct pcmcia_device *link = (struct pcmcia_device *)arg;
+
+	if (pcmcia_dev_present(link))
 		return 1;
-	
+
 	return 0;
 }
 
-static void atmel_config(dev_link_t *link)
+static int atmel_config(struct pcmcia_device *link)
 {
-	client_handle_t handle;
 	tuple_t tuple;
 	cisparse_t parse;
 	local_info_t *dev;
@@ -256,9 +234,8 @@
 	u_char buf[64];
 	struct pcmcia_device_id *did;
 
-	handle = link->handle;
 	dev = link->priv;
-	did = handle_to_dev(handle).driver_data;
+	did = handle_to_dev(link).driver_data;
 
 	DEBUG(0, "atmel_config(0x%p)\n", link);
 	
@@ -272,15 +249,12 @@
 	  registers.
 	*/
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
-	
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-	
+
 	/*
 	  In this loop, we scan the CIS for configuration table entries,
 	  each of which describes a valid card configuration, including
@@ -294,12 +268,12 @@
 	  will only use the CIS to fill in implementation-defined details.
 	*/
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t dflt = { 0 };
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 		
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
@@ -314,16 +288,11 @@
 		
 		/* Use power settings for Vcc and Vpp if present */
 		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
-		else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
-		
 		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
 		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
 		
 		/* Do we need to allocate an interrupt? */
@@ -349,14 +318,14 @@
 		}
 		
 		/* This reserves IO space but doesn't actually enable it */
-		if (pcmcia_request_io(link->handle, &link->io) != 0)
+		if (pcmcia_request_io(link, &link->io) != 0)
 			goto next_entry;
 
 		/* If we got this far, we're cool! */
 		break;
 		
 	next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 	
 	/*
@@ -365,14 +334,14 @@
 	  irq structure is initialized.
 	*/
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 	
 	/*
 	  This actually configures the PCMCIA socket -- setting up
 	  the I/O windows and the interrupt mapping, and putting the
 	  card and host interface into "Memory and IO" mode.
 	*/
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 	
 	if (link->irq.AssignedIRQ == 0) {
 		printk(KERN_ALERT 
@@ -384,7 +353,7 @@
 		init_atmel_card(link->irq.AssignedIRQ,
 				link->io.BasePort1,
 				did ? did->driver_info : ATMEL_FW_TYPE_NONE,
-				&handle_to_dev(handle),
+				&handle_to_dev(link),
 				card_present, 
 				link);
 	if (!((local_info_t*)link->priv)->eth_dev) 
@@ -393,18 +362,18 @@
 	
 	/*
 	  At this point, the dev_node_t structure(s) need to be
-	  initialized and arranged in a linked list at link->dev.
+	  initialized and arranged in a linked list at link->dev_node.
 	*/
 	strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
 	dev->node.major = dev->node.minor = 0;
-	link->dev = &dev->node;
-			
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
-	
+	link->dev_node = &dev->node;
+
+	return 0;
+
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	atmel_release(link);
+	return -ENODEV;
 }
 
 /*======================================================================
@@ -415,53 +384,34 @@
   
   ======================================================================*/
 
-static void atmel_release(dev_link_t *link)
+static void atmel_release(struct pcmcia_device *link)
 {
 	struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
-		
+
 	DEBUG(0, "atmel_release(0x%p)\n", link);
-	
-	/* Unlink the device chain */
-	link->dev = NULL;
-	
-	if (dev) 
+
+	if (dev)
 		stop_atmel_card(dev);
-	((local_info_t*)link->priv)->eth_dev = NULL; 
-	
-	/* Don't bother checking to see if these succeed or not */
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	((local_info_t*)link->priv)->eth_dev = NULL;
+
+	pcmcia_disable_device(link);
 }
 
-static int atmel_suspend(struct pcmcia_device *dev)
+static int atmel_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	local_info_t *local = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		netif_device_detach(local->eth_dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	netif_device_detach(local->eth_dev);
 
 	return 0;
 }
 
-static int atmel_resume(struct pcmcia_device *dev)
+static int atmel_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	local_info_t *local = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		atmel_open(local->eth_dev);
-		netif_device_attach(local->eth_dev);
-	}
+	atmel_open(local->eth_dev);
+	netif_device_attach(local->eth_dev);
 
 	return 0;
 }
@@ -515,7 +465,7 @@
 	.drv		= {
 		.name	= "atmel_cs",
         },
-	.probe          = atmel_attach,
+	.probe          = atmel_probe,
 	.remove		= atmel_detach,
 	.id_table	= atmel_ids,
 	.suspend	= atmel_suspend,
diff -urN oldtree/drivers/net/wireless/hostap/hostap_cs.c newtree/drivers/net/wireless/hostap/hostap_cs.c
--- oldtree/drivers/net/wireless/hostap/hostap_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/hostap/hostap_cs.c	2006-04-01 05:35:44.267386500 -0500
@@ -42,7 +42,7 @@
 /* struct local_info::hw_priv */
 struct hostap_cs_priv {
 	dev_node_t node;
-	dev_link_t *link;
+	struct pcmcia_device *link;
 	int sandisk_connectplus;
 };
 
@@ -204,15 +204,13 @@
 
 static void prism2_detach(struct pcmcia_device *p_dev);
 static void prism2_release(u_long arg);
-static int prism2_config(dev_link_t *link);
+static int prism2_config(struct pcmcia_device *link);
 
 
 static int prism2_pccard_card_present(local_info_t *local)
 {
 	struct hostap_cs_priv *hw_priv = local->hw_priv;
-	if (hw_priv != NULL && hw_priv->link != NULL &&
-	    ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) ==
-	     (DEV_PRESENT | DEV_CONFIG)))
+	if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
 		return 1;
 	return 0;
 }
@@ -237,7 +235,7 @@
 	reg.Action = CS_WRITE;
 	reg.Offset = 0x10; /* 0x3f0 IO base 1 */
 	reg.Value = hw_priv->link->io.BasePort1 & 0x00ff;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
@@ -249,7 +247,7 @@
 	reg.Action = CS_WRITE;
 	reg.Offset = 0x12; /* 0x3f2 IO base 2 */
 	reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
@@ -301,9 +299,9 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
-	    pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
-	    pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+	if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
+	    pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
+	    pcmcia_parse_tuple(hw_priv->link, &tuple, parse) ||
 	    parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) {
 		/* No SanDisk manfid found */
 		ret = -ENODEV;
@@ -311,9 +309,9 @@
 	}
 
 	tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
-	if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) ||
-	    pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) ||
-	    pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) ||
+	if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
+	    pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
+	    pcmcia_parse_tuple(hw_priv->link, &tuple, parse) ||
 		parse->longlink_mfc.nfn < 2) {
 		/* No multi-function links found */
 		ret = -ENODEV;
@@ -328,7 +326,7 @@
 	reg.Action = CS_WRITE;
 	reg.Offset = CISREG_COR;
 	reg.Value = COR_SOFT_RESET;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
@@ -345,7 +343,7 @@
 	 * will be enabled during the first cor_sreset call.
 	 */
 	reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
@@ -380,7 +378,7 @@
 	reg.Action = CS_READ;
 	reg.Offset = CISREG_COR;
 	reg.Value = 0;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
@@ -392,7 +390,7 @@
 
 	reg.Action = CS_WRITE;
 	reg.Value |= COR_SOFT_RESET;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
@@ -405,7 +403,7 @@
 	reg.Value &= ~COR_SOFT_RESET;
 	if (hw_priv->sandisk_connectplus)
 		reg.Value |= COR_IREQ_ENA;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
@@ -439,7 +437,7 @@
 	reg.Action = CS_READ;
 	reg.Offset = CISREG_COR;
 	reg.Value = 0;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
@@ -452,7 +450,7 @@
 
 	reg.Action = CS_WRITE;
 	reg.Value |= COR_SOFT_RESET;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
@@ -466,7 +464,7 @@
 	reg.Action = CS_WRITE;
 	reg.Value = hcr;
 	reg.Offset = CISREG_CCSR;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
@@ -478,7 +476,7 @@
 	reg.Action = CS_WRITE;
 	reg.Offset = CISREG_COR;
 	reg.Value = old_cor & ~COR_SOFT_RESET;
-	res = pcmcia_access_configuration_register(hw_priv->link->handle,
+	res = pcmcia_access_configuration_register(hw_priv->link,
 						   &reg);
 	if (res != CS_SUCCESS) {
 		printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
@@ -501,40 +499,27 @@
 
 /* allocate local data and register with CardServices
  * initialize dev_link structure, but do not configure the card yet */
-static int prism2_attach(struct pcmcia_device *p_dev)
+static int hostap_cs_probe(struct pcmcia_device *p_dev)
 {
-	dev_link_t *link;
-
-	link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
-	if (link == NULL)
-		return -ENOMEM;
-
-	memset(link, 0, sizeof(dev_link_t));
+	int ret;
 
 	PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
-	link->conf.Vcc = 33;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-
-	link->handle = p_dev;
-	p_dev->instance = link;
+	p_dev->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	if (prism2_config(link))
+	ret = prism2_config(p_dev);
+	if (ret) {
 		PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
+	}
 
-	return 0;
+	return ret;
 }
 
 
-static void prism2_detach(struct pcmcia_device *p_dev)
+static void prism2_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	PDEBUG(DEBUG_FLOW, "prism2_detach\n");
 
-	if (link->state & DEV_CONFIG) {
-		prism2_release((u_long)link);
-	}
+	prism2_release((u_long)link);
 
 	/* release net devices */
 	if (link->priv) {
@@ -547,7 +532,6 @@
 		prism2_free_local_data(dev);
 		kfree(hw_priv);
 	}
-	kfree(link);
 }
 
 
@@ -558,7 +542,7 @@
 do { int ret = (retf); \
 if (ret != 0) { \
 	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
-	cs_error(link->handle, fn, ret); \
+	cs_error(link, fn, ret); \
 	goto next_entry; \
 } \
 } while (0)
@@ -566,7 +550,7 @@
 
 /* run after a CARD_INSERTION event is received to configure the PCMCIA
  * socket and make the device available to the system */
-static int prism2_config(dev_link_t *link)
+static int prism2_config(struct pcmcia_device *link)
 {
 	struct net_device *dev;
 	struct hostap_interface *iface;
@@ -597,27 +581,24 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse));
 	link->conf.ConfigBase = parse->config.base;
 	link->conf.Present = parse->config.rmask[0];
 
 	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(link->handle, &conf));
-	PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info,
-	       ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc);
-	link->conf.Vcc = conf.Vcc;
+		 pcmcia_get_configuration_info(link, &conf));
 
 	/* Look for an appropriate configuration table entry in the CIS */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	for (;;) {
 		cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
 		CFG_CHECK2(GetTupleData,
-			   pcmcia_get_tuple_data(link->handle, &tuple));
+			   pcmcia_get_tuple_data(link, &tuple));
 		CFG_CHECK2(ParseTuple,
-			   pcmcia_parse_tuple(link->handle, &tuple, parse));
+			   pcmcia_parse_tuple(link, &tuple, parse));
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 			dflt = *cfg;
@@ -652,10 +633,10 @@
 		}
 
 		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 
 		/* Do we need to allocate an interrupt? */
@@ -697,19 +678,19 @@
 
 		/* This reserves IO space but doesn't actually enable it */
 		CFG_CHECK2(RequestIO,
-			   pcmcia_request_io(link->handle, &link->io));
+			   pcmcia_request_io(link, &link->io));
 
 		/* This configuration table entry is OK */
 		break;
 
 	next_entry:
 		CS_CHECK(GetNextTuple,
-			 pcmcia_get_next_tuple(link->handle, &tuple));
+			 pcmcia_get_next_tuple(link, &tuple));
 	}
 
 	/* Need to allocate net_device before requesting IRQ handler */
 	dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
-				     &handle_to_dev(link->handle));
+				     &handle_to_dev(link));
 	if (dev == NULL)
 		goto failed;
 	link->priv = dev;
@@ -719,7 +700,7 @@
 	local->hw_priv = hw_priv;
 	hw_priv->link = link;
 	strcpy(hw_priv->node.dev_name, dev->name);
-	link->dev = &hw_priv->node;
+	link->dev_node = &hw_priv->node;
 
 	/*
 	 * Allocate an interrupt line.  Note that this does not assign a
@@ -732,7 +713,7 @@
 		link->irq.Handler = prism2_interrupt;
 		link->irq.Instance = dev;
 		CS_CHECK(RequestIRQ,
-			 pcmcia_request_irq(link->handle, &link->irq));
+			 pcmcia_request_irq(link, &link->irq));
 	}
 
 	/*
@@ -741,18 +722,17 @@
 	 * card and host interface into "Memory and IO" mode.
 	 */
 	CS_CHECK(RequestConfiguration,
-		 pcmcia_request_configuration(link->handle, &link->conf));
+		 pcmcia_request_configuration(link, &link->conf));
 
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
 
 	/* Finally, report what we've done */
-	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-	       dev_info, link->conf.ConfigIndex,
-	       link->conf.Vcc / 10, link->conf.Vcc % 10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
-		       link->conf.Vpp1 % 10);
+	printk(KERN_INFO "%s: index 0x%02x: ",
+	       dev_info, link->conf.ConfigIndex);
+	if (link->conf.Vpp)
+		printk(", Vpp %d.%d", link->conf.Vpp / 10,
+		       link->conf.Vpp % 10);
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		printk(", irq %d", link->irq.AssignedIRQ);
 	if (link->io.NumPorts1)
@@ -763,9 +743,6 @@
 		       link->io.BasePort2+link->io.NumPorts2-1);
 	printk("\n");
 
-	link->state |= DEV_CONFIG;
-	link->state &= ~DEV_CONFIG_PENDING;
-
 	local->shutdown = 0;
 
 	sandisk_enable_wireless(dev);
@@ -780,7 +757,7 @@
 	return ret;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
  failed:
 	kfree(parse);
@@ -792,7 +769,7 @@
 
 static void prism2_release(u_long arg)
 {
-	dev_link_t *link = (dev_link_t *)arg;
+	struct pcmcia_device *link = (struct pcmcia_device *)arg;
 
 	PDEBUG(DEBUG_FLOW, "prism2_release\n");
 
@@ -801,71 +778,54 @@
 		struct hostap_interface *iface;
 
 		iface = netdev_priv(dev);
-		if (link->state & DEV_CONFIG)
-			prism2_hw_shutdown(dev, 0);
+		prism2_hw_shutdown(dev, 0);
 		iface->local->shutdown = 1;
 	}
 
-	if (link->win)
-		pcmcia_release_window(link->win);
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
-
+	pcmcia_disable_device(link);
 	PDEBUG(DEBUG_FLOW, "release - done\n");
 }
 
-static int hostap_cs_suspend(struct pcmcia_device *p_dev)
+static int hostap_cs_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = (struct net_device *) link->priv;
 	int dev_open = 0;
+	struct hostap_interface *iface = NULL;
 
-	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
-
-	link->state |= DEV_SUSPEND;
+	if (dev)
+		iface = netdev_priv(dev);
 
-	if (link->state & DEV_CONFIG) {
-		struct hostap_interface *iface = netdev_priv(dev);
-		if (iface && iface->local)
-			dev_open = iface->local->num_dev_open > 0;
-		if (dev_open) {
-			netif_stop_queue(dev);
-			netif_device_detach(dev);
-		}
-		prism2_suspend(dev);
-		pcmcia_release_configuration(link->handle);
+	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
+	if (iface && iface->local)
+		dev_open = iface->local->num_dev_open > 0;
+	if (dev_open) {
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
 	}
+	prism2_suspend(dev);
 
 	return 0;
 }
 
-static int hostap_cs_resume(struct pcmcia_device *p_dev)
+static int hostap_cs_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = (struct net_device *) link->priv;
 	int dev_open = 0;
+	struct hostap_interface *iface = NULL;
+
+	if (dev)
+		iface = netdev_priv(dev);
 
 	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		struct hostap_interface *iface = netdev_priv(dev);
-		if (iface && iface->local)
-			dev_open = iface->local->num_dev_open > 0;
-
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-		prism2_hw_shutdown(dev, 1);
-		prism2_hw_config(dev, dev_open ? 0 : 1);
-		if (dev_open) {
-			netif_device_attach(dev);
-			netif_start_queue(dev);
-		}
+	if (iface && iface->local)
+		dev_open = iface->local->num_dev_open > 0;
+
+	prism2_hw_shutdown(dev, 1);
+	prism2_hw_config(dev, dev_open ? 0 : 1);
+	if (dev_open) {
+		netif_device_attach(dev);
+		netif_start_queue(dev);
 	}
 
 	return 0;
@@ -932,7 +892,7 @@
 	.drv		= {
 		.name	= "hostap_cs",
 	},
-	.probe		= prism2_attach,
+	.probe		= hostap_cs_probe,
 	.remove		= prism2_detach,
 	.owner		= THIS_MODULE,
 	.id_table	= hostap_cs_ids,
diff -urN oldtree/drivers/net/wireless/netwave_cs.c newtree/drivers/net/wireless/netwave_cs.c
--- oldtree/drivers/net/wireless/netwave_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/netwave_cs.c	2006-04-01 05:35:44.271386750 -0500
@@ -192,8 +192,8 @@
 /*====================================================================*/
 
 /* PCMCIA (Card Services) related functions */
-static void netwave_release(dev_link_t *link);     /* Card removal */
-static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card 
+static void netwave_release(struct pcmcia_device *link);     /* Card removal */
+static int netwave_pcmcia_config(struct pcmcia_device *arg); /* Runs after card
 													   insertion */
 static void netwave_detach(struct pcmcia_device *p_dev);    /* Destroy instance */
 
@@ -223,10 +223,10 @@
 static void set_multicast_list(struct net_device *dev);
 
 /*
-   A dev_link_t structure has fields for most things that are needed
+   A struct pcmcia_device structure has fields for most things that are needed
    to keep track of a socket, but there will usually be some device
    specific information that also needs to be kept track of.  The
-   'priv' pointer in a dev_link_t structure can be used to point to
+   'priv' pointer in a struct pcmcia_device structure can be used to point to
    a device-specific private data structure, like this.
 
    A driver needs to provide a dev_node_t structure for each device
@@ -234,7 +234,7 @@
    example, ethernet cards, modems).  In other cases, there may be
    many actual or logical devices (SCSI adapters, memory cards with
    multiple partitions).  The dev_node_t structures need to be kept
-   in a linked list starting at the 'dev' field of a dev_link_t
+   in a linked list starting at the 'dev' field of a struct pcmcia_device
    structure.  We allocate them in the card's private data structure,
    because they generally can't be allocated dynamically.
 */
@@ -270,7 +270,7 @@
 };	
    
 typedef struct netwave_private {
-    dev_link_t link;
+	struct pcmcia_device	*p_dev;
     spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
     dev_node_t node;
     u_char     __iomem *ramBase;
@@ -378,20 +378,19 @@
  *     configure the card at this point -- we wait until we receive a
  *     card insertion event.
  */
-static int netwave_attach(struct pcmcia_device *p_dev)
+static int netwave_probe(struct pcmcia_device *link)
 {
-    dev_link_t *link;
     struct net_device *dev;
     netwave_private *priv;
 
     DEBUG(0, "netwave_attach()\n");
 
-    /* Initialize the dev_link_t structure */
+    /* Initialize the struct pcmcia_device structure */
     dev = alloc_etherdev(sizeof(netwave_private));
     if (!dev)
 	return -ENOMEM;
     priv = netdev_priv(dev);
-    link = &priv->link;
+    priv->p_dev = link;
     link->priv = dev;
 
     /* The io structure describes IO port mapping */
@@ -408,7 +407,6 @@
     
     /* General socket configuration */
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
@@ -432,13 +430,7 @@
     dev->stop = &netwave_close;
     link->irq.Instance = dev;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    netwave_pcmcia_config( link);
-
-    return 0;
+    return netwave_pcmcia_config( link);
 } /* netwave_attach */
 
 /*
@@ -449,17 +441,15 @@
  *    structures are freed.  Otherwise, the structures will be freed
  *    when the device is released.
  */
-static void netwave_detach(struct pcmcia_device *p_dev)
+static void netwave_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
 	DEBUG(0, "netwave_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		netwave_release(link);
+	netwave_release(link);
 
-	if (link->dev)
+	if (link->dev_node)
 		unregister_netdev(dev);
 
 	free_netdev(dev);
@@ -745,8 +735,7 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void netwave_pcmcia_config(dev_link_t *link) {
-    client_handle_t handle = link->handle;
+static int netwave_pcmcia_config(struct pcmcia_device *link) {
     struct net_device *dev = link->priv;
     netwave_private *priv = netdev_priv(dev);
     tuple_t tuple;
@@ -768,15 +757,12 @@
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     /*
      *  Try allocating IO ports.  This tries a few fixed addresses.
      *  If you want, you can also read the card's config table to
@@ -784,11 +770,11 @@
      */
     for (i = j = 0x0; j < 0x400; j += 0x20) {
 	link->io.BasePort1 = j ^ 0x300;
-	i = pcmcia_request_io(link->handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
 	if (i == CS_SUCCESS) break;
     }
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
+	cs_error(link, RequestIO, i);
 	goto failed;
     }
 
@@ -796,16 +782,16 @@
      *  Now allocate an interrupt line.  Note that this does not
      *  actually assign a handler to the interrupt.
      */
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
     /*
      *  This actually configures the PCMCIA socket -- setting up
      *  the I/O windows and the interrupt mapping.
      */
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     /*
-     *  Allocate a 32K memory window.  Note that the dev_link_t
+     *  Allocate a 32K memory window.  Note that the struct pcmcia_device
      *  structure provides space for one window handle -- if your
      *  device needs several windows, you'll need to keep track of
      *  the handles in your private data structure, dev->priv.
@@ -815,7 +801,7 @@
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
     req.Base = 0; req.Size = 0x8000;
     req.AccessSpeed = mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
     mem.CardOffset = 0x20000; mem.Page = 0; 
     CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
 
@@ -825,7 +811,7 @@
 
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
     if (register_netdev(dev) != 0) {
 	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
@@ -833,8 +819,7 @@
     }
 
     strcpy(priv->node.dev_name, dev->name);
-    link->dev = &priv->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev_node = &priv->node;
 
     /* Reset card before reading physical address */
     netwave_doreset(dev->base_addr, ramBase);
@@ -854,12 +839,13 @@
     printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
 	   get_uint16(ramBase + NETWAVE_EREG_ARW),
 	   get_uint16(ramBase + NETWAVE_EREG_ARW+2));
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     netwave_release(link);
+    return -ENODEV;
 } /* netwave_pcmcia_config */
 
 /*
@@ -869,52 +855,35 @@
  *    device, and release the PCMCIA configuration.  If the device is
  *    still open, this will be postponed until it is closed.
  */
-static void netwave_release(dev_link_t *link)
+static void netwave_release(struct pcmcia_device *link)
 {
-    struct net_device *dev = link->priv;
-    netwave_private *priv = netdev_priv(dev);
-
-    DEBUG(0, "netwave_release(0x%p)\n", link);
+	struct net_device *dev = link->priv;
+	netwave_private *priv = netdev_priv(dev);
 
-    /* Don't bother checking to see if these succeed or not */
-    if (link->win) {
-	iounmap(priv->ramBase);
-	pcmcia_release_window(link->win);
-    }
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
+	DEBUG(0, "netwave_release(0x%p)\n", link);
 
-    link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
+	if (link->win)
+		iounmap(priv->ramBase);
 }
 
-static int netwave_suspend(struct pcmcia_device *p_dev)
+static int netwave_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int netwave_resume(struct pcmcia_device *p_dev)
+static int netwave_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			netwave_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		netwave_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -1121,7 +1090,7 @@
     u_char __iomem *ramBase;
     struct net_device *dev = (struct net_device *)dev_id;
     struct netwave_private *priv = netdev_priv(dev);
-    dev_link_t *link = &priv->link;
+    struct pcmcia_device *link = priv->p_dev;
     int i;
     
     if (!netif_device_present(dev))
@@ -1140,7 +1109,7 @@
 	
         status = inb(iobase + NETWAVE_REG_ASR);
 		
-	if (!DEV_OK(link)) {
+	if (!pcmcia_dev_present(link)) {
 	    DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x "
 		  "from removed or suspended card!\n", status);
 	    break;
@@ -1375,11 +1344,11 @@
 
 static int netwave_open(struct net_device *dev) {
     netwave_private *priv = netdev_priv(dev);
-    dev_link_t *link = &priv->link;
+    struct pcmcia_device *link = priv->p_dev;
 
     DEBUG(1, "netwave_open: starting.\n");
     
-    if (!DEV_OK(link))
+    if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
     link->open++;
@@ -1392,7 +1361,7 @@
 
 static int netwave_close(struct net_device *dev) {
     netwave_private *priv = netdev_priv(dev);
-    dev_link_t *link = &priv->link;
+    struct pcmcia_device *link = priv->p_dev;
 
     DEBUG(1, "netwave_close: finishing.\n");
 
@@ -1413,7 +1382,7 @@
 	.drv		= {
 		.name	= "netwave_cs",
 	},
-	.probe		= netwave_attach,
+	.probe		= netwave_probe,
 	.remove		= netwave_detach,
 	.id_table       = netwave_ids,
 	.suspend	= netwave_suspend,
diff -urN oldtree/drivers/net/wireless/orinoco_cs.c newtree/drivers/net/wireless/orinoco_cs.c
--- oldtree/drivers/net/wireless/orinoco_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/orinoco_cs.c	2006-04-01 05:35:44.271386750 -0500
@@ -49,7 +49,7 @@
 /* PCMCIA specific device information (goes in the card field of
  * struct orinoco_private */
 struct orinoco_pccard {
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 
 	/* Used to handle hard reset */
@@ -63,8 +63,8 @@
 /* Function prototypes						    */
 /********************************************************************/
 
-static void orinoco_cs_config(dev_link_t *link);
-static void orinoco_cs_release(dev_link_t *link);
+static int orinoco_cs_config(struct pcmcia_device *link);
+static void orinoco_cs_release(struct pcmcia_device *link);
 static void orinoco_cs_detach(struct pcmcia_device *p_dev);
 
 /********************************************************************/
@@ -75,13 +75,13 @@
 orinoco_cs_hard_reset(struct orinoco_private *priv)
 {
 	struct orinoco_pccard *card = priv->card;
-	dev_link_t *link = &card->link;
+	struct pcmcia_device *link = card->p_dev;
 	int err;
 
 	/* We need atomic ops here, because we're not holding the lock */
 	set_bit(0, &card->hard_reset_in_progress);
 
-	err = pcmcia_reset_card(link->handle, NULL);
+	err = pcmcia_reset_card(link, NULL);
 	if (err)
 		return err;
 
@@ -104,12 +104,11 @@
  * configure the card at this point -- we wait until we receive a card
  * insertion event.  */
 static int
-orinoco_cs_attach(struct pcmcia_device *p_dev)
+orinoco_cs_probe(struct pcmcia_device *link)
 {
 	struct net_device *dev;
 	struct orinoco_private *priv;
 	struct orinoco_pccard *card;
-	dev_link_t *link;
 
 	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
 	if (! dev)
@@ -118,7 +117,7 @@
 	card = priv->card;
 
 	/* Link both structures together */
-	link = &card->link;
+	card->p_dev = link;
 	link->priv = dev;
 
 	/* Interrupt setup */
@@ -135,16 +134,7 @@
 	link->conf.Attributes = 0;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	/* Register with Card Services */
-	link->next = NULL;
-
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	orinoco_cs_config(link);
-
-	return 0;
+	return orinoco_cs_config(link);
 }				/* orinoco_cs_attach */
 
 /*
@@ -153,16 +143,14 @@
  * are freed.  Otherwise, the structures will be freed when the device
  * is released.
  */
-static void orinoco_cs_detach(struct pcmcia_device *p_dev)
+static void orinoco_cs_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		orinoco_cs_release(link);
+	orinoco_cs_release(link);
 
-	DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev);
-	if (link->dev) {
+	DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
+	if (link->dev_node) {
 		DEBUG(0, PFX "About to unregister net device %p\n",
 		      dev);
 		unregister_netdev(dev);
@@ -180,11 +168,10 @@
 		last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
 	} while (0)
 
-static void
-orinoco_cs_config(dev_link_t *link)
+static int
+orinoco_cs_config(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
-	client_handle_t handle = link->handle;
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pccard *card = priv->card;
 	hermes_t *hw = &priv->hw;
@@ -196,7 +183,7 @@
 	cisparse_t parse;
 	void __iomem *mem;
 
-	CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
+	CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
 
 	/*
 	 * This reads the card's CONFIG tuple to find its
@@ -207,19 +194,15 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	/* Look up the current Vcc */
 	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(handle, &conf));
-	link->conf.Vcc = conf.Vcc;
+		 pcmcia_get_configuration_info(link, &conf));
 
 	/*
 	 * In this loop, we scan the CIS for configuration table
@@ -236,13 +219,13 @@
 	 * implementation-defined details.
 	 */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 		cistpl_cftable_entry_t dflt = { .index = 0 };
 
-		if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
-		    || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
+		if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
+		    || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
 			goto next_entry;
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
@@ -274,10 +257,10 @@
 		}
 
 		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
 		/* Do we need to allocate an interrupt? */
@@ -307,7 +290,7 @@
 			}
 
 			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
+			if (pcmcia_request_io(link, &link->io) != 0)
 				goto next_entry;
 		}
 
@@ -317,9 +300,8 @@
 		break;
 		
 	next_entry:
-		if (link->io.NumPorts1)
-			pcmcia_release_io(link->handle, &link->io);
-		last_ret = pcmcia_get_next_tuple(handle, &tuple);
+		pcmcia_disable_device(link);
+		last_ret = pcmcia_get_next_tuple(link, &tuple);
 		if (last_ret  == CS_NO_MORE_ITEMS) {
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
 			       "CIS configuration.  Maybe you need the "
@@ -333,7 +315,7 @@
 	 * a handler to the interrupt, unless the 'Handler' member of
 	 * the irq structure is initialized.
 	 */
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
 	/* We initialize the hermes structure before completing PCMCIA
 	 * configuration just in case the interrupt handler gets
@@ -350,7 +332,7 @@
 	 * card and host interface into "Memory and IO" mode.
 	 */
 	CS_CHECK(RequestConfiguration,
-		 pcmcia_request_configuration(link->handle, &link->conf));
+		 pcmcia_request_configuration(link, &link->conf));
 
 	/* Ok, we have the configuration, prepare to register the netdev */
 	dev->base_addr = link->io.BasePort1;
@@ -358,7 +340,7 @@
 	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
-	SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+	SET_NETDEV_DEV(dev, &handle_to_dev(link));
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR PFX "register_netdev() failed\n");
@@ -366,20 +348,18 @@
 	}
 
 	/* At this point, the dev_node_t structure(s) needs to be
-	 * initialized and arranged in a linked list at link->dev. */
+	 * initialized and arranged in a linked list at link->dev_node. */
 	strcpy(card->node.dev_name, dev->name);
-	link->dev = &card->node; /* link->dev being non-NULL is also
+	link->dev_node = &card->node; /* link->dev_node being non-NULL is also
                                     used to indicate that the
                                     net_device has been registered */
-	link->state &= ~DEV_CONFIG_PENDING;
 
 	/* Finally, report what we've done */
-	printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
-	       dev->name, link->conf.ConfigIndex,
-	       link->conf.Vcc / 10, link->conf.Vcc % 10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
-		       link->conf.Vpp1 % 10);
+	printk(KERN_DEBUG "%s: index 0x%02x: ",
+	       dev->name, link->conf.ConfigIndex);
+	if (link->conf.Vpp)
+		printk(", Vpp %d.%d", link->conf.Vpp / 10,
+		       link->conf.Vpp % 10);
 	printk(", irq %d", link->irq.AssignedIRQ);
 	if (link->io.NumPorts1)
 		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
@@ -389,13 +369,14 @@
 		       link->io.BasePort2 + link->io.NumPorts2 - 1);
 	printk("\n");
 
-	return;
+	return 0;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
  failed:
 	orinoco_cs_release(link);
+	return -ENODEV;
 }				/* orinoco_cs_config */
 
 /*
@@ -404,7 +385,7 @@
  * still open, this will be postponed until it is closed.
  */
 static void
-orinoco_cs_release(dev_link_t *link)
+orinoco_cs_release(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -416,88 +397,68 @@
 	priv->hw_unavailable++;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Don't bother checking to see if these succeed or not */
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 	if (priv->hw.iobase)
 		ioport_unmap(priv->hw.iobase);
 }				/* orinoco_cs_release */
 
-static int orinoco_cs_suspend(struct pcmcia_device *p_dev)
+static int orinoco_cs_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pccard *card = priv->card;
 	int err = 0;
 	unsigned long flags;
 
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		/* This is probably racy, but I can't think of
-		   a better way, short of rewriting the PCMCIA
-		   layer to not suck :-( */
-		if (! test_bit(0, &card->hard_reset_in_progress)) {
-			spin_lock_irqsave(&priv->lock, flags);
+	/* This is probably racy, but I can't think of
+	   a better way, short of rewriting the PCMCIA
+	   layer to not suck :-( */
+	if (! test_bit(0, &card->hard_reset_in_progress)) {
+		spin_lock_irqsave(&priv->lock, flags);
+
+		err = __orinoco_down(dev);
+		if (err)
+			printk(KERN_WARNING "%s: Error %d downing interface\n",
+			       dev->name, err);
 
-			err = __orinoco_down(dev);
-			if (err)
-				printk(KERN_WARNING "%s: Error %d downing interface\n",
-				       dev->name, err);
+		netif_device_detach(dev);
+		priv->hw_unavailable++;
 
-			netif_device_detach(dev);
-			priv->hw_unavailable++;
-
-			spin_unlock_irqrestore(&priv->lock, flags);
-		}
-
-		pcmcia_release_configuration(link->handle);
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
 	return 0;
 }
 
-static int orinoco_cs_resume(struct pcmcia_device *p_dev)
+static int orinoco_cs_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pccard *card = priv->card;
 	int err = 0;
 	unsigned long flags;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		/* FIXME: should we double check that this is
-		 * the same card as we had before */
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-		if (! test_bit(0, &card->hard_reset_in_progress)) {
-			err = orinoco_reinit_firmware(dev);
-			if (err) {
-				printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
-				       dev->name, err);
-				return -EIO;
-			}
-
-			spin_lock_irqsave(&priv->lock, flags);
+	if (! test_bit(0, &card->hard_reset_in_progress)) {
+		err = orinoco_reinit_firmware(dev);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+			       dev->name, err);
+			return -EIO;
+		}
 
-			netif_device_attach(dev);
-			priv->hw_unavailable--;
+		spin_lock_irqsave(&priv->lock, flags);
 
-			if (priv->open && ! priv->hw_unavailable) {
-				err = __orinoco_up(dev);
-				if (err)
-					printk(KERN_ERR "%s: Error %d restarting card\n",
-					       dev->name, err);
-			}
+		netif_device_attach(dev);
+		priv->hw_unavailable--;
 
-			spin_unlock_irqrestore(&priv->lock, flags);
+		if (priv->open && ! priv->hw_unavailable) {
+			err = __orinoco_up(dev);
+			if (err)
+				printk(KERN_ERR "%s: Error %d restarting card\n",
+				       dev->name, err);
 		}
+
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
 	return 0;
@@ -604,7 +565,7 @@
 	.drv		= {
 		.name	= DRIVER_NAME,
 	},
-	.probe		= orinoco_cs_attach,
+	.probe		= orinoco_cs_probe,
 	.remove		= orinoco_cs_detach,
 	.id_table       = orinoco_cs_ids,
 	.suspend	= orinoco_cs_suspend,
diff -urN oldtree/drivers/net/wireless/ray_cs.c newtree/drivers/net/wireless/ray_cs.c
--- oldtree/drivers/net/wireless/ray_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/ray_cs.c	2006-04-01 05:35:44.275387000 -0500
@@ -90,8 +90,8 @@
 #define DEBUG(n, args...)
 #endif
 /** Prototypes based on PCMCIA skeleton driver *******************************/
-static void ray_config(dev_link_t *link);
-static void ray_release(dev_link_t *link);
+static int ray_config(struct pcmcia_device *link);
+static void ray_release(struct pcmcia_device *link);
 static void ray_detach(struct pcmcia_device *p_dev);
 
 /***** Prototypes indicated by device structure ******************************/
@@ -190,20 +190,17 @@
 static char *phy_addr = NULL;
 
 
-/* A linked list of "instances" of the ray device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
-*/
-static dev_link_t *dev_list = NULL;
-
-/* A dev_link_t structure has fields for most things that are needed
+/* A struct pcmcia_device structure has fields for most things that are needed
    to keep track of a socket, but there will usually be some device
    specific information that also needs to be kept track of.  The
-   'priv' pointer in a dev_link_t structure can be used to point to
+   'priv' pointer in a struct pcmcia_device structure can be used to point to
    a device-specific private data structure, like this.
 */
 static unsigned int ray_mem_speed = 500;
 
+/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */
+static struct pcmcia_device *this_device = NULL;
+
 MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
 MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
 MODULE_LICENSE("GPL");
@@ -306,56 +303,46 @@
     configure the card at this point -- we wait until we receive a
     card insertion event.
 =============================================================================*/
-static int ray_attach(struct pcmcia_device *p_dev)
+static int ray_probe(struct pcmcia_device *p_dev)
 {
-    dev_link_t *link;
     ray_dev_t *local;
     struct net_device *dev;
-    
-    DEBUG(1, "ray_attach()\n");
 
-    /* Initialize the dev_link_t structure */
-    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-
-    if (!link)
-	    return -ENOMEM;
+    DEBUG(1, "ray_attach()\n");
 
     /* Allocate space for private device-specific data */
     dev = alloc_etherdev(sizeof(ray_dev_t));
-
     if (!dev)
 	    goto fail_alloc_dev;
 
     local = dev->priv;
-
-    memset(link, 0, sizeof(struct dev_link_t));
+    local->finder = p_dev;
 
     /* The io structure describes IO port mapping. None used here */
-    link->io.NumPorts1 = 0;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.IOAddrLines = 5;
+    p_dev->io.NumPorts1 = 0;
+    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    p_dev->io.IOAddrLines = 5;
 
     /* Interrupt setup. For PCMCIA, driver takes what's given */
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-    link->irq.Handler = &ray_interrupt;
+    p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    p_dev->irq.Handler = &ray_interrupt;
 
     /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
+    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+    p_dev->conf.IntType = INT_MEMORY_AND_IO;
+    p_dev->conf.ConfigIndex = 1;
+    p_dev->conf.Present = PRESENT_OPTION;
 
-    link->priv = dev;
-    link->irq.Instance = dev;
+    p_dev->priv = dev;
+    p_dev->irq.Instance = dev;
     
-    local->finder = link;
+    local->finder = p_dev;
     local->card_status = CARD_INSERTED;
     local->authentication_state = UNAUTHENTICATED;
     local->num_multi = 0;
-    DEBUG(2,"ray_attach link = %p,  dev = %p,  local = %p, intr = %p\n",
-          link,dev,local,&ray_interrupt);
+    DEBUG(2,"ray_attach p_dev = %p,  dev = %p,  local = %p, intr = %p\n",
+          p_dev,dev,local,&ray_interrupt);
 
     /* Raylink entries in the device structure */
     dev->hard_start_xmit = &ray_dev_start_xmit;
@@ -379,16 +366,10 @@
 
     init_timer(&local->timer);
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    ray_config(link);
-
-    return 0;
+    this_device = p_dev;
+    return ray_config(p_dev);
 
 fail_alloc_dev:
-    kfree(link);
     return -ENOMEM;
 } /* ray_attach */
 /*=============================================================================
@@ -397,37 +378,25 @@
     structures are freed.  Otherwise, the structures will be freed
     when the device is released.
 =============================================================================*/
-static void ray_detach(struct pcmcia_device *p_dev)
+static void ray_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-    dev_link_t **linkp;
     struct net_device *dev;
     ray_dev_t *local;
 
     DEBUG(1, "ray_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-        if (*linkp == link) break;
-    if (*linkp == NULL)
-        return;
 
+    this_device = NULL;
     dev = link->priv;
 
-    if (link->state & DEV_CONFIG) {
-	    ray_release(link);
+    ray_release(link);
 
-	    local = (ray_dev_t *)dev->priv;
-            del_timer(&local->timer);
-    }
+    local = (ray_dev_t *)dev->priv;
+    del_timer(&local->timer);
 
-    /* Unlink device structure, free pieces */
-    *linkp = link->next;
     if (link->priv) {
-	if (link->dev) unregister_netdev(dev);
+	if (link->dev_node) unregister_netdev(dev);
         free_netdev(dev);
     }
-    kfree(link);
     DEBUG(2,"ray_cs ray_detach ending\n");
 } /* ray_detach */
 /*=============================================================================
@@ -438,9 +407,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 #define MAX_TUPLE_SIZE 128
-static void ray_config(dev_link_t *link)
+static int ray_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     tuple_t tuple;
     cisparse_t parse;
     int last_fn = 0, last_ret = 0;
@@ -455,48 +423,45 @@
 
     /* This reads the card's CONFIG tuple to find its configuration regs */
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     tuple.TupleData = buf;
     tuple.TupleDataMax = MAX_TUPLE_SIZE;
     tuple.TupleOffset = 0;
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
 
     /* Determine card type and firmware version */
     buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0;
     tuple.DesiredTuple = CISTPL_VERS_1;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     tuple.TupleData = buf;
     tuple.TupleDataMax = MAX_TUPLE_SIZE;
     tuple.TupleOffset = 2;
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 
     for (i=0; i<tuple.TupleDataLen - 4; i++) 
         if (buf[i] == 0) buf[i] = ' ';
     printk(KERN_INFO "ray_cs Detected: %s\n",buf);
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     /* Now allocate an interrupt line.  Note that this does not
        actually assign a handler to the interrupt.
     */
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
     dev->irq = link->irq.AssignedIRQ;
     
     /* This actually configures the PCMCIA socket -- setting up
        the I/O windows and the interrupt mapping.
     */
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 /*** Set up 32k window for shared memory (transmit and control) ************/
     req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
     req.Base = 0;
     req.Size = 0x8000;
     req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
     mem.CardOffset = 0x0000; mem.Page = 0;
     CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
     local->sram = ioremap(req.Base,req.Size);
@@ -506,7 +471,7 @@
     req.Base = 0;
     req.Size = 0x4000;
     req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->rmem_handle));
     mem.CardOffset = 0x8000; mem.Page = 0;
     CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem));
     local->rmem = ioremap(req.Base,req.Size);
@@ -516,7 +481,7 @@
     req.Base = 0;
     req.Size = 0x1000;
     req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle));
+    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->amem_handle));
     mem.CardOffset = 0x0000; mem.Page = 0;
     CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem));
     local->amem = ioremap(req.Base,req.Size);
@@ -526,32 +491,32 @@
     DEBUG(3,"ray_config amem=%p\n",local->amem);
     if (ray_init(dev) < 0) {
         ray_release(link);
-        return;
+        return -ENODEV;
     }
 
-    SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+    SET_NETDEV_DEV(dev, &handle_to_dev(link));
     i = register_netdev(dev);
     if (i != 0) {
         printk("ray_config register_netdev() failed\n");
         ray_release(link);
-        return;
+        return i;
     }
 
     strcpy(local->node.dev_name, dev->name);
-    link->dev = &local->node;
+    link->dev_node = &local->node;
 
-    link->state &= ~DEV_CONFIG_PENDING;
     printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
        dev->name, dev->irq);
     for (i = 0; i < 6; i++)
     printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 
     ray_release(link);
+    return -ENODEV;
 } /* ray_config */
 
 static inline struct ccs __iomem *ccs_base(ray_dev_t *dev)
@@ -578,9 +543,9 @@
     UCHAR *p;
     struct ccs __iomem *pccs;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     DEBUG(1, "ray_init(0x%p)\n", dev);
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(0,"ray_init - device not present\n");
         return -1;
     }
@@ -640,10 +605,10 @@
     int ccsindex;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
     struct ccs __iomem *pccs;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
     DEBUG(1,"dl_startup_params entered\n");
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs dl_startup_params - device not present\n");
         return -1;
     }
@@ -747,9 +712,9 @@
     ray_dev_t *local = (ray_dev_t *)data;
     struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
     UCHAR status;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs verify_dl_startup - device not present\n");
         return;
     }
@@ -787,8 +752,8 @@
     ray_dev_t *local = (ray_dev_t *)data;
     struct ccs __iomem *pccs;
     int ccsindex;
-    dev_link_t *link = local->finder;
-    if (!(link->state & DEV_PRESENT)) {
+    struct pcmcia_device *link = local->finder;
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs start_net - device not present\n");
         return;
     }
@@ -814,9 +779,9 @@
 
     struct ccs __iomem *pccs;
     int ccsindex;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs join_net - device not present\n");
         return;
     }
@@ -840,7 +805,7 @@
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
 =============================================================================*/
-static void ray_release(dev_link_t *link)
+static void ray_release(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv; 
     ray_dev_t *local = dev->priv;
@@ -849,56 +814,38 @@
     DEBUG(1, "ray_release(0x%p)\n", link);
 
     del_timer(&local->timer);
-    link->state &= ~DEV_CONFIG;
 
     iounmap(local->sram);
     iounmap(local->rmem);
     iounmap(local->amem);
     /* Do bother checking to see if these succeed or not */
-    i = pcmcia_release_window(link->win);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i);
     i = pcmcia_release_window(local->amem_handle);
     if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
     i = pcmcia_release_window(local->rmem_handle);
     if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
-    i = pcmcia_release_configuration(link->handle);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i);
-    i = pcmcia_release_irq(link->handle, &link->irq);
-    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i);
+    pcmcia_disable_device(link);
 
     DEBUG(2,"ray_release ending\n");
 }
 
-static int ray_suspend(struct pcmcia_device *p_dev)
+static int ray_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-
-		pcmcia_release_configuration(link->handle);
-        }
-
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int ray_resume(struct pcmcia_device *p_dev)
+static int ray_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-        if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			ray_reset(dev);
-			netif_device_attach(dev);
-		}
-        }
+	if (link->open) {
+		ray_reset(dev);
+		netif_device_attach(dev);
+	}
 
 	return 0;
 }
@@ -910,10 +857,10 @@
     int i;
 #endif	/* RAY_IMMEDIATE_INIT */
     ray_dev_t *local = dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
     DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_dev_init - device not present\n");
         return -1;
     }
@@ -944,10 +891,10 @@
 static int ray_dev_config(struct net_device *dev, struct ifmap *map)
 {
     ray_dev_t *local = dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     /* Dummy routine to satisfy device structure */
     DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_dev_config - device not present\n");
         return -1;
     }
@@ -958,10 +905,10 @@
 static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     ray_dev_t *local = dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     short length = skb->len;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_dev_start_xmit - device not present\n");
         return -1;
     }
@@ -1570,7 +1517,7 @@
 static iw_stats * ray_get_wireless_stats(struct net_device *	dev)
 {
   ray_dev_t *	local = (ray_dev_t *) dev->priv;
-  dev_link_t *link = local->finder;
+  struct pcmcia_device *link = local->finder;
   struct status __iomem *p = local->sram + STATUS_BASE;
 
   if(local == (ray_dev_t *) NULL)
@@ -1588,7 +1535,7 @@
     }
 #endif /* WIRELESS_SPY */
 
-  if((link->state & DEV_PRESENT)) {
+  if(pcmcia_dev_present(link)) {
     local->wstats.qual.noise = readb(&p->rxnoise);
     local->wstats.qual.updated |= 4;
   }
@@ -1657,18 +1604,14 @@
 /*===========================================================================*/
 static int ray_open(struct net_device *dev)
 {
-    dev_link_t *link;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct pcmcia_device *link;
+    link = local->finder;
     
     DEBUG(1, "ray_open('%s')\n", dev->name);
 
-    for (link = dev_list; link; link = link->next)
-        if (link->priv == dev) break;
-    if (!DEV_OK(link)) {
-        return -ENODEV;
-    }
-
-    if (link->open == 0) local->num_multi = 0;
+    if (link->open == 0)
+	    local->num_multi = 0;
     link->open++;
 
     /* If the card is not started, time to start it ! - Jean II */
@@ -1695,15 +1638,12 @@
 /*===========================================================================*/
 static int ray_dev_close(struct net_device *dev)
 {
-    dev_link_t *link;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct pcmcia_device *link;
+    link = local->finder;
 
     DEBUG(1, "ray_dev_close('%s')\n", dev->name);
 
-    for (link = dev_list; link; link = link->next)
-        if (link->priv == dev) break;
-    if (link == NULL)
-        return -ENODEV;
-
     link->open--;
     netif_stop_queue(dev);
 
@@ -1725,9 +1665,9 @@
 static int interrupt_ecf(ray_dev_t *local, int ccs)
 {
     int i = 50;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs interrupt_ecf - device not present\n");
         return -1;
     }
@@ -1752,9 +1692,9 @@
 {
     int i;
     struct ccs __iomem *pccs = ccs_base(local);
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n");
         return ECARDGONE;
     }
@@ -1783,9 +1723,9 @@
 {
     int i;
     struct ccs __iomem *pccs = ccs_base(local);
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs get_free_ccs - device not present\n");
         return ECARDGONE;
     }
@@ -1858,9 +1798,9 @@
 static struct net_device_stats *ray_get_stats(struct net_device *dev)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     struct status __iomem *p = local->sram + STATUS_BASE;
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs net_device_stats - device not present\n");
         return &local->stats;
     }
@@ -1888,12 +1828,12 @@
 static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
 {
     ray_dev_t *local = (ray_dev_t *)dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     int ccsindex;
     int i;
     struct ccs __iomem *pccs;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_update_parm - device not present\n");
         return;
     }
@@ -1925,10 +1865,10 @@
     struct ccs __iomem *pccs;
     int i = 0;
     ray_dev_t *local = (ray_dev_t *)dev->priv;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     void __iomem *p = local->sram + HOST_TO_ECF_BASE;
 
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_update_multi_list - device not present\n");
         return;
     }
@@ -2005,7 +1945,7 @@
 static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
     struct net_device *dev = (struct net_device *)dev_id;
-    dev_link_t *link;
+    struct pcmcia_device *link;
     ray_dev_t *local;
     struct ccs __iomem *pccs;
     struct rcs __iomem *prcs;
@@ -2020,8 +1960,8 @@
     DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
 
     local = (ray_dev_t *)dev->priv;
-    link = (dev_link_t *)local->finder;
-    if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) {
+    link = (struct pcmcia_device *)local->finder;
+    if (!pcmcia_dev_present(link)) {
         DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
         return IRQ_NONE;
     }
@@ -2540,9 +2480,9 @@
 /*===========================================================================*/
 static void authenticate(ray_dev_t *local)
 {
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     DEBUG(0,"ray_cs Starting authentication.\n");
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs authenticate - device not present\n");
         return;
     }
@@ -2606,10 +2546,10 @@
 static void associate(ray_dev_t *local)
 {
     struct ccs __iomem *pccs;
-    dev_link_t *link = local->finder;
+    struct pcmcia_device *link = local->finder;
     struct net_device *dev = link->priv;
     int ccsindex;
-    if (!(link->state & DEV_PRESENT)) {
+    if (!(pcmcia_dev_present(link))) {
         DEBUG(2,"ray_cs associate - device not present\n");
         return;
     }
@@ -2689,14 +2629,14 @@
  * eg ifconfig 
  */
     int i;
-    dev_link_t *link;
+    struct pcmcia_device *link;
     struct net_device *dev;
     ray_dev_t *local;
     UCHAR *p;
     struct freq_hop_element *pfh;
     UCHAR c[33];
 
-    link = dev_list;
+    link = this_device;
     if (!link)
     	return 0;
     dev = (struct net_device *)link->priv;
@@ -2898,7 +2838,7 @@
 	.drv		= {
 		.name	= "ray_cs",
 	},
-	.probe		= ray_attach,
+	.probe		= ray_probe,
 	.remove		= ray_detach,
 	.id_table       = ray_ids,
 	.suspend	= ray_suspend,
@@ -2940,7 +2880,6 @@
 #endif
 
     pcmcia_unregister_driver(&ray_driver);
-    BUG_ON(dev_list != NULL);
 } /* exit_ray_cs */
 
 module_init(init_ray_cs);
diff -urN oldtree/drivers/net/wireless/ray_cs.h newtree/drivers/net/wireless/ray_cs.h
--- oldtree/drivers/net/wireless/ray_cs.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/ray_cs.h	2006-04-01 05:35:44.275387000 -0500
@@ -31,7 +31,7 @@
     void __iomem *sram;            /* pointer to beginning of shared RAM     */
     void __iomem *amem;            /* pointer to attribute mem window        */
     void __iomem *rmem;            /* pointer to receive buffer window       */
-    dev_link_t *finder;            /* pointer back to dev_link_t for card    */
+    struct pcmcia_device *finder;            /* pointer back to struct pcmcia_device for card    */
     struct timer_list timer;
     long tx_ccs_lock;
     long ccs_lock;
diff -urN oldtree/drivers/net/wireless/spectrum_cs.c newtree/drivers/net/wireless/spectrum_cs.c
--- oldtree/drivers/net/wireless/spectrum_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/spectrum_cs.c	2006-04-01 05:35:44.275387000 -0500
@@ -63,7 +63,7 @@
 /* PCMCIA specific device information (goes in the card field of
  * struct orinoco_private */
 struct orinoco_pccard {
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 };
 
@@ -71,8 +71,8 @@
 /* Function prototypes						    */
 /********************************************************************/
 
-static void spectrum_cs_config(dev_link_t *link);
-static void spectrum_cs_release(dev_link_t *link);
+static int spectrum_cs_config(struct pcmcia_device *link);
+static void spectrum_cs_release(struct pcmcia_device *link);
 
 /********************************************************************/
 /* Firmware downloader						    */
@@ -238,14 +238,14 @@
  * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
  */
 static int
-spectrum_reset(dev_link_t *link, int idle)
+spectrum_reset(struct pcmcia_device *link, int idle)
 {
 	int last_ret, last_fn;
 	conf_reg_t reg;
 	u_int save_cor;
 
 	/* Doing it if hardware is gone is guaranteed crash */
-	if (!(link->state & DEV_CONFIG))
+	if (pcmcia_dev_present(link))
 		return -ENODEV;
 
 	/* Save original COR value */
@@ -253,7 +253,7 @@
 	reg.Action = CS_READ;
 	reg.Offset = CISREG_COR;
 	CS_CHECK(AccessConfigurationRegister,
-		 pcmcia_access_configuration_register(link->handle, &reg));
+		 pcmcia_access_configuration_register(link, &reg));
 	save_cor = reg.Value;
 
 	/* Soft-Reset card */
@@ -261,14 +261,14 @@
 	reg.Offset = CISREG_COR;
 	reg.Value = (save_cor | COR_SOFT_RESET);
 	CS_CHECK(AccessConfigurationRegister,
-		 pcmcia_access_configuration_register(link->handle, &reg));
+		 pcmcia_access_configuration_register(link, &reg));
 	udelay(1000);
 
 	/* Read CCSR */
 	reg.Action = CS_READ;
 	reg.Offset = CISREG_CCSR;
 	CS_CHECK(AccessConfigurationRegister,
-		 pcmcia_access_configuration_register(link->handle, &reg));
+		 pcmcia_access_configuration_register(link, &reg));
 
 	/*
 	 * Start or stop the firmware.  Memory width bit should be
@@ -278,7 +278,7 @@
 	reg.Offset = CISREG_CCSR;
 	reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
 	CS_CHECK(AccessConfigurationRegister,
-		 pcmcia_access_configuration_register(link->handle, &reg));
+		 pcmcia_access_configuration_register(link, &reg));
 	udelay(1000);
 
 	/* Restore original COR configuration index */
@@ -286,12 +286,12 @@
 	reg.Offset = CISREG_COR;
 	reg.Value = (save_cor & ~COR_SOFT_RESET);
 	CS_CHECK(AccessConfigurationRegister,
-		 pcmcia_access_configuration_register(link->handle, &reg));
+		 pcmcia_access_configuration_register(link, &reg));
 	udelay(1000);
 	return 0;
 
       cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	return -ENODEV;
 }
 
@@ -441,7 +441,7 @@
  * care of the PDA - read it and then write it on top of the firmware.
  */
 static int
-spectrum_dl_image(hermes_t *hw, dev_link_t *link,
+spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
 		  const unsigned char *image)
 {
 	int ret;
@@ -505,14 +505,13 @@
  * reset on the card, to make sure it's in a sane state.
  */
 static int
-spectrum_dl_firmware(hermes_t *hw, dev_link_t *link)
+spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
 {
 	int ret;
-	client_handle_t handle = link->handle;
 	const struct firmware *fw_entry;
 
 	if (request_firmware(&fw_entry, primary_fw_name,
-			     &handle_to_dev(handle)) == 0) {
+			     &handle_to_dev(link)) == 0) {
 		primsym = fw_entry->data;
 	} else {
 		printk(KERN_ERR PFX "Cannot find firmware: %s\n",
@@ -521,7 +520,7 @@
 	}
 
 	if (request_firmware(&fw_entry, secondary_fw_name,
-			     &handle_to_dev(handle)) == 0) {
+			     &handle_to_dev(link)) == 0) {
 		secsym = fw_entry->data;
 	} else {
 		printk(KERN_ERR PFX "Cannot find firmware: %s\n",
@@ -554,12 +553,12 @@
 spectrum_cs_hard_reset(struct orinoco_private *priv)
 {
 	struct orinoco_pccard *card = priv->card;
-	dev_link_t *link = &card->link;
+	struct pcmcia_device *link = card->p_dev;
 	int err;
 
 	if (!hermes_present(&priv->hw)) {
 		/* The firmware needs to be reloaded */
-		if (spectrum_dl_firmware(&priv->hw, &card->link) != 0) {
+		if (spectrum_dl_firmware(&priv->hw, link) != 0) {
 			printk(KERN_ERR PFX "Firmware download failed\n");
 			err = -ENODEV;
 		}
@@ -584,12 +583,11 @@
  * configure the card at this point -- we wait until we receive a card
  * insertion event.  */
 static int
-spectrum_cs_attach(struct pcmcia_device *p_dev)
+spectrum_cs_probe(struct pcmcia_device *link)
 {
 	struct net_device *dev;
 	struct orinoco_private *priv;
 	struct orinoco_pccard *card;
-	dev_link_t *link;
 
 	dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
 	if (! dev)
@@ -598,7 +596,7 @@
 	card = priv->card;
 
 	/* Link both structures together */
-	link = &card->link;
+	card->p_dev = link;
 	link->priv = dev;
 
 	/* Interrupt setup */
@@ -615,13 +613,7 @@
 	link->conf.Attributes = 0;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	spectrum_cs_config(link);
-
-	return 0;
+	return spectrum_cs_config(link);
 }				/* spectrum_cs_attach */
 
 /*
@@ -630,16 +622,14 @@
  * are freed.  Otherwise, the structures will be freed when the device
  * is released.
  */
-static void spectrum_cs_detach(struct pcmcia_device *p_dev)
+static void spectrum_cs_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	if (link->state & DEV_CONFIG)
-		spectrum_cs_release(link);
+	spectrum_cs_release(link);
 
-	DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev);
-	if (link->dev) {
+	DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
+	if (link->dev_node) {
 		DEBUG(0, PFX "About to unregister net device %p\n",
 		      dev);
 		unregister_netdev(dev);
@@ -653,11 +643,10 @@
  * device available to the system.
  */
 
-static void
-spectrum_cs_config(dev_link_t *link)
+static int
+spectrum_cs_config(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
-	client_handle_t handle = link->handle;
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pccard *card = priv->card;
 	hermes_t *hw = &priv->hw;
@@ -669,7 +658,7 @@
 	cisparse_t parse;
 	void __iomem *mem;
 
-	CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info));
+	CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
 
 	/*
 	 * This reads the card's CONFIG tuple to find its
@@ -680,19 +669,15 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	/* Look up the current Vcc */
 	CS_CHECK(GetConfigurationInfo,
-		 pcmcia_get_configuration_info(handle, &conf));
-	link->conf.Vcc = conf.Vcc;
+		 pcmcia_get_configuration_info(link, &conf));
 
 	/*
 	 * In this loop, we scan the CIS for configuration table
@@ -709,13 +694,13 @@
 	 * implementation-defined details.
 	 */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 		cistpl_cftable_entry_t dflt = { .index = 0 };
 
-		if ( (pcmcia_get_tuple_data(handle, &tuple) != 0)
-		    || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0))
+		if ( (pcmcia_get_tuple_data(link, &tuple) != 0)
+		    || (pcmcia_parse_tuple(link, &tuple, &parse) != 0))
 			goto next_entry;
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
@@ -747,10 +732,10 @@
 		}
 
 		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
 		/* Do we need to allocate an interrupt? */
@@ -780,7 +765,7 @@
 			}
 
 			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
+			if (pcmcia_request_io(link, &link->io) != 0)
 				goto next_entry;
 		}
 
@@ -790,9 +775,8 @@
 		break;
 		
 	next_entry:
-		if (link->io.NumPorts1)
-			pcmcia_release_io(link->handle, &link->io);
-		last_ret = pcmcia_get_next_tuple(handle, &tuple);
+		pcmcia_disable_device(link);
+		last_ret = pcmcia_get_next_tuple(link, &tuple);
 		if (last_ret  == CS_NO_MORE_ITEMS) {
 			printk(KERN_ERR PFX "GetNextTuple(): No matching "
 			       "CIS configuration.  Maybe you need the "
@@ -806,7 +790,7 @@
 	 * a handler to the interrupt, unless the 'Handler' member of
 	 * the irq structure is initialized.
 	 */
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
 	/* We initialize the hermes structure before completing PCMCIA
 	 * configuration just in case the interrupt handler gets
@@ -823,7 +807,7 @@
 	 * card and host interface into "Memory and IO" mode.
 	 */
 	CS_CHECK(RequestConfiguration,
-		 pcmcia_request_configuration(link->handle, &link->conf));
+		 pcmcia_request_configuration(link, &link->conf));
 
 	/* Ok, we have the configuration, prepare to register the netdev */
 	dev->base_addr = link->io.BasePort1;
@@ -836,7 +820,7 @@
 		goto failed;
 	}
 
-	SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+	SET_NETDEV_DEV(dev, &handle_to_dev(link));
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR PFX "register_netdev() failed\n");
@@ -844,20 +828,18 @@
 	}
 
 	/* At this point, the dev_node_t structure(s) needs to be
-	 * initialized and arranged in a linked list at link->dev. */
+	 * initialized and arranged in a linked list at link->dev_node. */
 	strcpy(card->node.dev_name, dev->name);
-	link->dev = &card->node; /* link->dev being non-NULL is also
+	link->dev_node = &card->node; /* link->dev_node being non-NULL is also
                                     used to indicate that the
                                     net_device has been registered */
-	link->state &= ~DEV_CONFIG_PENDING;
 
 	/* Finally, report what we've done */
-	printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
-	       dev->name, link->conf.ConfigIndex,
-	       link->conf.Vcc / 10, link->conf.Vcc % 10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
-		       link->conf.Vpp1 % 10);
+	printk(KERN_DEBUG "%s: index 0x%02x: ",
+	       dev->name, link->conf.ConfigIndex);
+	if (link->conf.Vpp)
+		printk(", Vpp %d.%d", link->conf.Vpp / 10,
+		       link->conf.Vpp % 10);
 	printk(", irq %d", link->irq.AssignedIRQ);
 	if (link->io.NumPorts1)
 		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
@@ -867,13 +849,14 @@
 		       link->io.BasePort2 + link->io.NumPorts2 - 1);
 	printk("\n");
 
-	return;
+	return 0;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 
  failed:
 	spectrum_cs_release(link);
+	return -ENODEV;
 }				/* spectrum_cs_config */
 
 /*
@@ -882,7 +865,7 @@
  * still open, this will be postponed until it is closed.
  */
 static void
-spectrum_cs_release(dev_link_t *link)
+spectrum_cs_release(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -894,64 +877,46 @@
 	priv->hw_unavailable++;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Don't bother checking to see if these succeed or not */
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 	if (priv->hw.iobase)
 		ioport_unmap(priv->hw.iobase);
 }				/* spectrum_cs_release */
 
 
 static int
-spectrum_cs_suspend(struct pcmcia_device *p_dev)
+spectrum_cs_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
 	unsigned long flags;
 	int err = 0;
 
-	link->state |= DEV_SUSPEND;
 	/* Mark the device as stopped, to block IO until later */
-	if (link->state & DEV_CONFIG) {
-		spin_lock_irqsave(&priv->lock, flags);
-
-		err = __orinoco_down(dev);
-		if (err)
-			printk(KERN_WARNING "%s: Error %d downing interface\n",
-			       dev->name, err);
+	spin_lock_irqsave(&priv->lock, flags);
 
-		netif_device_detach(dev);
-		priv->hw_unavailable++;
+	err = __orinoco_down(dev);
+	if (err)
+		printk(KERN_WARNING "%s: Error %d downing interface\n",
+		       dev->name, err);
 
-		spin_unlock_irqrestore(&priv->lock, flags);
+	netif_device_detach(dev);
+	priv->hw_unavailable++;
 
-		pcmcia_release_configuration(link->handle);
-	}
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
 static int
-spectrum_cs_resume(struct pcmcia_device *p_dev)
+spectrum_cs_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		/* FIXME: should we double check that this is
-		 * the same card as we had before */
-		pcmcia_request_configuration(link->handle, &link->conf);
-		netif_device_attach(dev);
-		priv->hw_unavailable--;
-		schedule_work(&priv->reset_work);
-	}
+	netif_device_attach(dev);
+	priv->hw_unavailable--;
+	schedule_work(&priv->reset_work);
+
 	return 0;
 }
 
@@ -979,7 +944,7 @@
 	.drv		= {
 		.name	= DRIVER_NAME,
 	},
-	.probe		= spectrum_cs_attach,
+	.probe		= spectrum_cs_probe,
 	.remove		= spectrum_cs_detach,
 	.suspend	= spectrum_cs_suspend,
 	.resume		= spectrum_cs_resume,
diff -urN oldtree/drivers/net/wireless/tiacx/Changelog newtree/drivers/net/wireless/tiacx/Changelog
--- oldtree/drivers/net/wireless/tiacx/Changelog	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/Changelog	2006-04-01 05:35:49.671724250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/Kconfig	2006-04-01 05:35:49.679724750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/Makefile	2006-04-01 05:35:49.679724750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/README	2006-04-01 05:35:49.695725750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/acx.h	2006-04-01 05:35:49.671724250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/acx_config.h	2006-04-01 05:35:49.667724000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/acx_func.h	2006-04-01 05:35:49.667724000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/acx_struct.h	2006-04-01 05:35:49.671724250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/common.c	2006-04-01 05:35:49.695725750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/conv.c	2006-04-01 05:35:49.675724500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/ioctl.c	2006-04-01 05:35:49.675724500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/pci.c	2006-04-01 05:35:49.683725000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/setrate.c	2006-04-01 05:35:49.683725000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/usb.c	2006-04-01 05:35:49.683725000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/wlan.c	2006-04-01 05:35:49.687725250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/wlan_compat.h	2006-04-01 05:35:49.687725250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/wlan_hdr.h	2006-04-01 05:35:49.687725250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/net/wireless/tiacx/wlan_mgmt.h	2006-04-01 05:35:49.687725250 -0500
@@ -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_cs.c newtree/drivers/net/wireless/wavelan_cs.c
--- oldtree/drivers/net/wireless/wavelan_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/wavelan_cs.c	2006-04-01 05:35:44.279387250 -0500
@@ -1005,7 +1005,7 @@
 wv_82593_reconfig(struct net_device *	dev)
 {
   net_local *		lp = netdev_priv(dev);
-  dev_link_t *		link = lp->link;
+  struct pcmcia_device *		link = lp->link;
   unsigned long		flags;
 
   /* Arm the flag, will be cleard in wv_82593_config() */
@@ -3744,16 +3744,16 @@
 {
   int		i;
   conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
-  dev_link_t *	link = ((net_local *)netdev_priv(dev))->link;
+  struct pcmcia_device *	link = ((net_local *)netdev_priv(dev))->link;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
 #endif
 
-  i = pcmcia_access_configuration_register(link->handle, &reg);
+  i = pcmcia_access_configuration_register(link, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link->handle, AccessConfigurationRegister, i);
+      cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
     }
       
@@ -3764,19 +3764,19 @@
 
   reg.Action = CS_WRITE;
   reg.Value = reg.Value | COR_SW_RESET;
-  i = pcmcia_access_configuration_register(link->handle, &reg);
+  i = pcmcia_access_configuration_register(link, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link->handle, AccessConfigurationRegister, i);
+      cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
     }
       
   reg.Action = CS_WRITE;
   reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
-  i = pcmcia_access_configuration_register(link->handle, &reg);
+  i = pcmcia_access_configuration_register(link, &reg);
   if(i != CS_SUCCESS)
     {
-      cs_error(link->handle, AccessConfigurationRegister, i);
+      cs_error(link, AccessConfigurationRegister, i);
       return FALSE;
     }
 
@@ -3940,9 +3940,8 @@
  * (called by wavelan_event())
  */
 static inline int
-wv_pcmcia_config(dev_link_t *	link)
+wv_pcmcia_config(struct pcmcia_device *	link)
 {
-  client_handle_t	handle = link->handle;
   tuple_t		tuple;
   cisparse_t		parse;
   struct net_device *	dev = (struct net_device *) link->priv;
@@ -3965,16 +3964,16 @@
     {
       tuple.Attributes = 0;
       tuple.DesiredTuple = CISTPL_CONFIG;
-      i = pcmcia_get_first_tuple(handle, &tuple);
+      i = pcmcia_get_first_tuple(link, &tuple);
       if(i != CS_SUCCESS)
 	break;
       tuple.TupleData = (cisdata_t *)buf;
       tuple.TupleDataMax = 64;
       tuple.TupleOffset = 0;
-      i = pcmcia_get_tuple_data(handle, &tuple);
+      i = pcmcia_get_tuple_data(link, &tuple);
       if(i != CS_SUCCESS)
 	break;
-      i = pcmcia_parse_tuple(handle, &tuple, &parse);
+      i = pcmcia_parse_tuple(link, &tuple, &parse);
       if(i != CS_SUCCESS)
 	break;
       link->conf.ConfigBase = parse.config.base;
@@ -3983,19 +3982,16 @@
   while(0);
   if(i != CS_SUCCESS)
     {
-      cs_error(link->handle, ParseTuple, i);
-      link->state &= ~DEV_CONFIG_PENDING;
+      cs_error(link, ParseTuple, i);
       return FALSE;
     }
-    
-  /* Configure card */
-  link->state |= DEV_CONFIG;
+
   do
     {
-      i = pcmcia_request_io(link->handle, &link->io);
+      i = pcmcia_request_io(link, &link->io);
       if(i != CS_SUCCESS)
 	{
-	  cs_error(link->handle, RequestIO, i);
+	  cs_error(link, RequestIO, i);
 	  break;
 	}
 
@@ -4003,10 +3999,10 @@
        * Now allocate an interrupt line.  Note that this does not
        * actually assign a handler to the interrupt.
        */
-      i = pcmcia_request_irq(link->handle, &link->irq);
+      i = pcmcia_request_irq(link, &link->irq);
       if(i != CS_SUCCESS)
 	{
-	  cs_error(link->handle, RequestIRQ, i);
+	  cs_error(link, RequestIRQ, i);
 	  break;
 	}
 
@@ -4015,15 +4011,15 @@
        * the I/O windows and the interrupt mapping.
        */
       link->conf.ConfigIndex = 1;
-      i = pcmcia_request_configuration(link->handle, &link->conf);
+      i = pcmcia_request_configuration(link, &link->conf);
       if(i != CS_SUCCESS)
 	{
-	  cs_error(link->handle, RequestConfiguration, i);
+	  cs_error(link, RequestConfiguration, i);
 	  break;
 	}
 
       /*
-       * Allocate a small memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the struct pcmcia_device
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
@@ -4031,10 +4027,10 @@
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
       req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
-      i = pcmcia_request_window(&link->handle, &req, &link->win);
+      i = pcmcia_request_window(&link, &req, &link->win);
       if(i != CS_SUCCESS)
 	{
-	  cs_error(link->handle, RequestWindow, i);
+	  cs_error(link, RequestWindow, i);
 	  break;
 	}
 
@@ -4046,7 +4042,7 @@
       i = pcmcia_map_mem_page(link->win, &mem);
       if(i != CS_SUCCESS)
 	{
-	  cs_error(link->handle, MapMemPage, i);
+	  cs_error(link, MapMemPage, i);
 	  break;
 	}
 
@@ -4060,7 +4056,7 @@
 	     lp->mem, dev->irq, (u_int) dev->base_addr);
 #endif
 
-      SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+      SET_NETDEV_DEV(dev, &handle_to_dev(link));
       i = register_netdev(dev);
       if(i != 0)
 	{
@@ -4072,7 +4068,6 @@
     }
   while(0);		/* Humm... Disguised goto !!! */
 
-  link->state &= ~DEV_CONFIG_PENDING;
   /* If any step failed, release any partially configured state */
   if(i != 0)
     {
@@ -4081,7 +4076,7 @@
     }
 
   strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name);
-  link->dev = &((net_local *) netdev_priv(dev))->node;
+  link->dev_node = &((net_local *) netdev_priv(dev))->node;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
@@ -4096,26 +4091,20 @@
  * still open, this will be postponed until it is closed.
  */
 static void
-wv_pcmcia_release(dev_link_t *link)
+wv_pcmcia_release(struct pcmcia_device *link)
 {
-  struct net_device *	dev = (struct net_device *) link->priv;
-  net_local *		lp = netdev_priv(dev);
+	struct net_device *	dev = (struct net_device *) link->priv;
+	net_local *		lp = netdev_priv(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
+	printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
 #endif
 
-  /* Don't bother checking to see if these succeed or not */
-  iounmap(lp->mem);
-  pcmcia_release_window(link->win);
-  pcmcia_release_configuration(link->handle);
-  pcmcia_release_io(link->handle, &link->io);
-  pcmcia_release_irq(link->handle, &link->irq);
-
-  link->state &= ~DEV_CONFIG;
+	iounmap(lp->mem);
+	pcmcia_disable_device(link);
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
+	printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
 #endif
 }
 
@@ -4479,7 +4468,7 @@
 wavelan_open(struct net_device *	dev)
 {
   net_local *	lp = netdev_priv(dev);
-  dev_link_t *	link = lp->link;
+  struct pcmcia_device *	link = lp->link;
   kio_addr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4533,7 +4522,7 @@
 static int
 wavelan_close(struct net_device *	dev)
 {
-  dev_link_t *	link = ((net_local *)netdev_priv(dev))->link;
+  struct pcmcia_device *	link = ((net_local *)netdev_priv(dev))->link;
   kio_addr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4587,45 +4576,36 @@
  * card insertion event.
  */
 static int
-wavelan_attach(struct pcmcia_device *p_dev)
+wavelan_probe(struct pcmcia_device *p_dev)
 {
-  dev_link_t *	link;		/* Info for cardmgr */
   struct net_device *	dev;		/* Interface generic data */
   net_local *	lp;		/* Interface specific data */
+  int ret;
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "-> wavelan_attach()\n");
 #endif
 
-  /* Initialize the dev_link_t structure */
-  link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link) return -ENOMEM;
-
   /* The io structure describes IO port mapping */
-  link->io.NumPorts1 = 8;
-  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-  link->io.IOAddrLines = 3;
+  p_dev->io.NumPorts1 = 8;
+  p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  p_dev->io.IOAddrLines = 3;
 
   /* Interrupt setup */
-  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-  link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-  link->irq.Handler = wavelan_interrupt;
+  p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+  p_dev->irq.Handler = wavelan_interrupt;
 
   /* General socket configuration */
-  link->conf.Attributes = CONF_ENABLE_IRQ;
-  link->conf.Vcc = 50;
-  link->conf.IntType = INT_MEMORY_AND_IO;
-
-  /* Chain drivers */
-  link->next = NULL;
+  p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+  p_dev->conf.IntType = INT_MEMORY_AND_IO;
 
   /* Allocate the generic data structure */
   dev = alloc_etherdev(sizeof(net_local));
-  if (!dev) {
-      kfree(link);
+  if (!dev)
       return -ENOMEM;
-  }
-  link->priv = link->irq.Instance = dev;
+
+  p_dev->priv = p_dev->irq.Instance = dev;
 
   lp = netdev_priv(dev);
 
@@ -4642,7 +4622,6 @@
   spin_lock_init(&lp->spinlock);
 
   /* back links */
-  lp->link = link;
   lp->dev = dev;
 
   /* wavelan NET3 callbacks */
@@ -4668,15 +4647,18 @@
   /* Other specific data */
   dev->mtu = WAVELAN_MTU;
 
-  link->handle = p_dev;
-  p_dev->instance = link;
+  ret = wv_pcmcia_config(p_dev);
+  if (ret)
+	  return ret;
 
-  link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-  if(wv_pcmcia_config(link) &&
-     wv_hw_config(dev))
-	  wv_init_info(dev);
-  else
+  ret = wv_hw_config(dev);
+  if (ret) {
 	  dev->irq = 0;
+	  pcmcia_disable_device(p_dev);
+	  return ret;
+  }
+
+  wv_init_info(dev);
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "<- wavelan_attach()\n");
@@ -4693,25 +4675,14 @@
  * is released.
  */
 static void
-wavelan_detach(struct pcmcia_device *p_dev)
+wavelan_detach(struct pcmcia_device *link)
 {
-   dev_link_t *link = dev_to_instance(p_dev);
-
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
 #endif
 
-  /*
-   * If the device is currently configured and active, we won't
-   * actually delete it yet.  Instead, it is marked so that when the
-   * release() function is called, that will trigger a proper
-   * detach().
-   */
-  if(link->state & DEV_CONFIG)
-    {
-      /* Some others haven't done their job : give them another chance */
-      wv_pcmcia_release(link);
-    }
+  /* Some others haven't done their job : give them another chance */
+  wv_pcmcia_release(link);
 
   /* Free pieces */
   if(link->priv)
@@ -4720,23 +4691,21 @@
 
       /* Remove ourselves from the kernel list of ethernet devices */
       /* Warning : can't be called from interrupt, timer or wavelan_close() */
-      if (link->dev)
+      if (link->dev_node)
 	unregister_netdev(dev);
-      link->dev = NULL;
+      link->dev_node = NULL;
       ((net_local *)netdev_priv(dev))->link = NULL;
       ((net_local *)netdev_priv(dev))->dev = NULL;
       free_netdev(dev);
     }
-  kfree(link);
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "<- wavelan_detach()\n");
 #endif
 }
 
-static int wavelan_suspend(struct pcmcia_device *p_dev)
+static int wavelan_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *	dev = (struct net_device *) link->priv;
 
 	/* NB: wavelan_close will be called, but too late, so we are
@@ -4748,36 +4717,22 @@
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
 
+	if (link->open)
+		netif_device_detach(dev);
+
 	/* Power down the module */
 	hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
 
-	/* The card is now suspended */
-	link->state |= DEV_SUSPEND;
-
-    	if(link->state & DEV_CONFIG)
-	{
-		if(link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
-
 	return 0;
 }
 
-static int wavelan_resume(struct pcmcia_device *p_dev)
+static int wavelan_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *	dev = (struct net_device *) link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if(link->state & DEV_CONFIG)
-	{
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if(link->open)	/* If RESET -> True, If RESUME -> False ? */
-		{
-			wv_hw_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		wv_hw_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -4798,7 +4753,7 @@
 	.drv		= {
 		.name	= "wavelan_cs",
 	},
-	.probe		= wavelan_attach,
+	.probe		= wavelan_probe,
 	.remove		= wavelan_detach,
 	.id_table       = wavelan_ids,
 	.suspend	= wavelan_suspend,
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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/wavelan_cs.p.h	2006-04-01 05:35:44.279387250 -0500
@@ -609,7 +609,7 @@
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   struct net_device *	dev;		/* Reverse link... */
   spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
-  dev_link_t *	link;		/* pcmcia structure */
+  struct pcmcia_device *	link;		/* pcmcia structure */
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
   u_char	configured;	/* If it is configured */
@@ -740,9 +740,9 @@
 static inline void
 	wv_hw_reset(struct net_device *);	/* Same, + start receiver unit */
 static inline int
-	wv_pcmcia_config(dev_link_t *);	/* Configure the pcmcia interface */
+	wv_pcmcia_config(struct pcmcia_device *);	/* Configure the pcmcia interface */
 static void
-	wv_pcmcia_release(dev_link_t *);/* Remove a device */
+	wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static irqreturn_t
 	wavelan_interrupt(int,	/* Interrupt handler */
diff -urN oldtree/drivers/net/wireless/wl3501.h newtree/drivers/net/wireless/wl3501.h
--- oldtree/drivers/net/wireless/wl3501.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/wl3501.h	2006-04-01 05:35:44.279387250 -0500
@@ -611,5 +611,6 @@
 	struct iw_spy_data		spy_data;
 	struct iw_public_data		wireless_data;
 	struct dev_node_t		node;
+	struct pcmcia_device		*p_dev;
 };
 #endif
diff -urN oldtree/drivers/net/wireless/wl3501_cs.c newtree/drivers/net/wireless/wl3501_cs.c
--- oldtree/drivers/net/wireless/wl3501_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/net/wireless/wl3501_cs.c	2006-04-01 05:35:44.279387250 -0500
@@ -103,8 +103,8 @@
  * release a socket, in response to card insertion and ejection events.  They
  * are invoked from the wl24 event handler.
  */
-static void wl3501_config(dev_link_t *link);
-static void wl3501_release(dev_link_t *link);
+static int wl3501_config(struct pcmcia_device *link);
+static void wl3501_release(struct pcmcia_device *link);
 
 /*
  * The dev_info variable is the "key" that is used to match up this
@@ -226,17 +226,6 @@
 	iw_set_mgmt_info_element(from->id, to, from->data, from->len);
 }
 
-/*
- * A linked list of "instances" of the wl24 device.  Each actual PCMCIA card
- * corresponds to one device instance, and is described by one dev_link_t
- * structure (defined in ds.h).
- *
- * You may not want to use a linked list for this -- for example, the memory
- * card driver uses an array of dev_link_t pointers, where minor device numbers
- * are used to derive the corresponding array index.
- */
-static dev_link_t *wl3501_dev_list;
-
 static inline void wl3501_switch_page(struct wl3501_card *this, u8 page)
 {
 	wl3501_outb(page, this->base_addr + WL3501_NIC_BSS);
@@ -1281,15 +1270,10 @@
 	struct wl3501_card *this = dev->priv;
 	int rc = -ENODEV;
 	unsigned long flags;
-	dev_link_t *link;
+	struct pcmcia_device *link;
+	link = this->p_dev;
 
 	spin_lock_irqsave(&this->lock, flags);
-	/* Check if the device is in wl3501_dev_list */
-	for (link = wl3501_dev_list; link; link = link->next)
-		if (link->priv == dev)
-			break;
-	if (!link)
-		goto out;
 	link->open--;
 
 	/* Stop wl3501_hard_start_xmit() from now on */
@@ -1301,7 +1285,6 @@
 
 	rc = 0;
 	printk(KERN_INFO "%s: WL3501 closed\n", dev->name);
-out:
 	spin_unlock_irqrestore(&this->lock, flags);
 	return rc;
 }
@@ -1400,14 +1383,11 @@
 	int rc = -ENODEV;
 	struct wl3501_card *this = dev->priv;
 	unsigned long flags;
-	dev_link_t *link;
+	struct pcmcia_device *link;
+	link = this->p_dev;
 
 	spin_lock_irqsave(&this->lock, flags);
-	/* Check if the device is in wl3501_dev_list */
-	for (link = wl3501_dev_list; link; link = link->next)
-		if (link->priv == dev)
-			break;
-	if (!DEV_OK(link))
+	if (!pcmcia_dev_present(link))
 		goto out;
 	netif_device_attach(dev);
 	link->open++;
@@ -1497,38 +1477,23 @@
  * Services. If it has been released, all local data structures are freed.
  * Otherwise, the structures will be freed when the device is released.
  */
-static void wl3501_detach(struct pcmcia_device *p_dev)
+static void wl3501_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-	dev_link_t **linkp;
 	struct net_device *dev = link->priv;
 
-	/* Locate device structure */
-	for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next)
-		if (*linkp == link)
-			break;
-	if (!*linkp)
-		goto out;
-
 	/* If the device is currently configured and active, we won't actually
 	 * delete it yet.  Instead, it is marked so that when the release()
 	 * function is called, that will trigger a proper detach(). */
 
-	if (link->state & DEV_CONFIG) {
-		while (link->open > 0)
-			wl3501_close(dev);
-
-		netif_device_detach(dev);
-		wl3501_release(link);
-	}
+	while (link->open > 0)
+		wl3501_close(dev);
 
-	/* Unlink device structure, free pieces */
-	*linkp = link->next;
+	netif_device_detach(dev);
+	wl3501_release(link);
 
 	if (link->priv)
 		free_netdev(link->priv);
-	kfree(link);
-out:
+
 	return;
 }
 
@@ -1953,33 +1918,26 @@
  * The dev_link structure is initialized, but we don't actually configure the
  * card at this point -- we wait until we receive a card insertion event.
  */
-static int wl3501_attach(struct pcmcia_device *p_dev)
+static int wl3501_probe(struct pcmcia_device *p_dev)
 {
-	dev_link_t *link;
 	struct net_device *dev;
 	struct wl3501_card *this;
 
-	/* Initialize the dev_link_t structure */
-	link = kzalloc(sizeof(*link), GFP_KERNEL);
-	if (!link)
-		return -ENOMEM;
-
 	/* The io structure describes IO port mapping */
-	link->io.NumPorts1	= 16;
-	link->io.Attributes1	= IO_DATA_PATH_WIDTH_8;
-	link->io.IOAddrLines	= 5;
+	p_dev->io.NumPorts1	= 16;
+	p_dev->io.Attributes1	= IO_DATA_PATH_WIDTH_8;
+	p_dev->io.IOAddrLines	= 5;
 
 	/* Interrupt setup */
-	link->irq.Attributes	= IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-	link->irq.IRQInfo1	= IRQ_LEVEL_ID;
-	link->irq.Handler = wl3501_interrupt;
+	p_dev->irq.Attributes	= IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	p_dev->irq.IRQInfo1	= IRQ_LEVEL_ID;
+	p_dev->irq.Handler = wl3501_interrupt;
 
 	/* General socket configuration */
-	link->conf.Attributes	= CONF_ENABLE_IRQ;
-	link->conf.Vcc		= 50;
-	link->conf.IntType	= INT_MEMORY_AND_IO;
-	link->conf.ConfigIndex	= 1;
-	link->conf.Present	= PRESENT_OPTION;
+	p_dev->conf.Attributes	= CONF_ENABLE_IRQ;
+	p_dev->conf.IntType	= INT_MEMORY_AND_IO;
+	p_dev->conf.ConfigIndex	= 1;
+	p_dev->conf.Present	= PRESENT_OPTION;
 
 	dev = alloc_etherdev(sizeof(struct wl3501_card));
 	if (!dev)
@@ -1992,22 +1950,15 @@
 	dev->get_stats		= wl3501_get_stats;
 	this = dev->priv;
 	this->wireless_data.spy_data = &this->spy_data;
+	this->p_dev = p_dev;
 	dev->wireless_data	= &this->wireless_data;
 	dev->wireless_handlers	= (struct iw_handler_def *)&wl3501_handler_def;
 	SET_ETHTOOL_OPS(dev, &ops);
 	netif_stop_queue(dev);
-	link->priv = link->irq.Instance = dev;
-
-	link->handle = p_dev;
-	p_dev->instance = link;
+	p_dev->priv = p_dev->irq.Instance = dev;
 
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	wl3501_config(link);
-
-	return 0;
+	return wl3501_config(p_dev);
 out_link:
-	kfree(link);
-	link = NULL;
 	return -ENOMEM;
 }
 
@@ -2022,11 +1973,10 @@
  * received, to configure the PCMCIA socket, and to make the ethernet device
  * available to the system.
  */
-static void wl3501_config(dev_link_t *link)
+static int wl3501_config(struct pcmcia_device *link)
 {
 	tuple_t tuple;
 	cisparse_t parse;
-	client_handle_t handle = link->handle;
 	struct net_device *dev = link->priv;
 	int i = 0, j, last_fn, last_ret;
 	unsigned char bf[64];
@@ -2035,18 +1985,15 @@
 	/* This reads the card's CONFIG tuple to find its config registers. */
 	tuple.Attributes	= 0;
 	tuple.DesiredTuple	= CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	tuple.TupleData		= bf;
 	tuple.TupleDataMax	= sizeof(bf);
 	tuple.TupleOffset	= 0;
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase	= parse.config.base;
 	link->conf.Present	= parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	/* Try allocating IO ports.  This tries a few fixed addresses.  If you
 	 * want, you can also read the card's config table to pick addresses --
 	 * see the serial driver for an example. */
@@ -2056,28 +2003,28 @@
 		 * 0x200-0x2ff, and so on, because this seems safer */
 		link->io.BasePort1 = j;
 		link->io.BasePort2 = link->io.BasePort1 + 0x10;
-		i = pcmcia_request_io(link->handle, &link->io);
+		i = pcmcia_request_io(link, &link->io);
 		if (i == CS_SUCCESS)
 			break;
 	}
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		goto failed;
 	}
 
 	/* Now allocate an interrupt line. Note that this does not actually
 	 * assign a handler to the interrupt. */
 
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
 	/* This actually configures the PCMCIA socket -- setting up the I/O
 	 * windows and the interrupt mapping.  */
 
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
-	SET_NETDEV_DEV(dev, &handle_to_dev(handle));
+	SET_NETDEV_DEV(dev, &handle_to_dev(link));
 	if (register_netdev(dev)) {
 		printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");
 		goto failed;
@@ -2088,10 +2035,9 @@
 	this = dev->priv;
 	/*
 	 * At this point, the dev_node_t structure(s) should be initialized and
-	 * arranged in a linked list at link->dev.
+	 * arranged in a linked list at link->dev_node.
 	 */
-	link->dev = &this->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &this->node;
 
 	this->base_addr = dev->base_addr;
 
@@ -2127,13 +2073,13 @@
 	spin_lock_init(&this->lock);
 	init_waitqueue_head(&this->wait);
 	netif_start_queue(dev);
-	goto out;
+	return 0;
+
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 failed:
 	wl3501_release(link);
-out:
-	return;
+	return -ENODEV;
 }
 
 /**
@@ -2144,52 +2090,36 @@
  * and release the PCMCIA configuration.  If the device is still open, this
  * will be postponed until it is closed.
  */
-static void wl3501_release(dev_link_t *link)
+static void wl3501_release(struct pcmcia_device *link)
 {
 	struct net_device *dev = link->priv;
 
 	/* Unlink the device chain */
-	if (link->dev) {
+	if (link->dev_node)
 		unregister_netdev(dev);
-		link->dev = NULL;
-	}
 
-	/* Don't bother checking to see if these succeed or not */
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int wl3501_suspend(struct pcmcia_device *p_dev)
+static int wl3501_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
-	link->state |= DEV_SUSPEND;
-
 	wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
-	if (link->state & DEV_CONFIG) {
-		if (link->open)
-			netif_device_detach(dev);
-		pcmcia_release_configuration(link->handle);
-	}
+	if (link->open)
+		netif_device_detach(dev);
 
 	return 0;
 }
 
-static int wl3501_resume(struct pcmcia_device *p_dev)
+static int wl3501_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct net_device *dev = link->priv;
 
 	wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if (link->open) {
-			wl3501_reset(dev);
-			netif_device_attach(dev);
-		}
+	if (link->open) {
+		wl3501_reset(dev);
+		netif_device_attach(dev);
 	}
 
 	return 0;
@@ -2207,7 +2137,7 @@
 	.drv		= {
 		.name	= "wl3501_cs",
 	},
-	.probe		= wl3501_attach,
+	.probe		= wl3501_probe,
 	.remove		= wl3501_detach,
 	.id_table	= wl3501_ids,
 	.suspend	= wl3501_suspend,
@@ -2221,9 +2151,7 @@
 
 static void __exit wl3501_exit_module(void)
 {
-	dprintk(0, ": unloading");
 	pcmcia_unregister_driver(&wl3501_driver);
-	BUG_ON(wl3501_dev_list != NULL);
 }
 
 module_init(wl3501_init_module);
diff -urN oldtree/drivers/parport/parport_cs.c newtree/drivers/parport/parport_cs.c
--- oldtree/drivers/parport/parport_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/parport/parport_cs.c	2006-04-01 05:35:44.279387250 -0500
@@ -81,15 +81,15 @@
 #define FORCE_EPP_MODE	0x08
 
 typedef struct parport_info_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     int			ndev;
     dev_node_t		node;
     struct parport	*port;
 } parport_info_t;
 
 static void parport_detach(struct pcmcia_device *p_dev);
-static void parport_config(dev_link_t *link);
-static void parport_cs_release(dev_link_t *);
+static int parport_config(struct pcmcia_device *link);
+static void parport_cs_release(struct pcmcia_device *);
 
 /*======================================================================
 
@@ -99,10 +99,9 @@
 
 ======================================================================*/
 
-static int parport_attach(struct pcmcia_device *p_dev)
+static int parport_probe(struct pcmcia_device *link)
 {
     parport_info_t *info;
-    dev_link_t *link;
 
     DEBUG(0, "parport_attach()\n");
 
@@ -110,23 +109,17 @@
     info = kmalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
     memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
+    link->priv = info;
+    info->p_dev = link;
 
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    parport_config(link);
-
-    return 0;
+    return parport_config(link);
 } /* parport_attach */
 
 /*======================================================================
@@ -138,14 +131,11 @@
 
 ======================================================================*/
 
-static void parport_detach(struct pcmcia_device *p_dev)
+static void parport_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-
     DEBUG(0, "parport_detach(0x%p)\n", link);
 
-    if (link->state & DEV_CONFIG)
-	parport_cs_release(link);
+    parport_cs_release(link);
 
     kfree(link->priv);
 } /* parport_detach */
@@ -161,14 +151,12 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-void parport_config(dev_link_t *link)
+static int parport_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     parport_info_t *info = link->priv;
     tuple_t tuple;
     u_short buf[128];
     cisparse_t parse;
-    config_info_t conf;
     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
     cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
@@ -180,24 +168,18 @@
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
     tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
 
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
     tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (1) {
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 	    goto next_entry;
 
 	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
@@ -212,7 +194,7 @@
 		link->io.BasePort2 = io->win[1].base;
 		link->io.NumPorts2 = io->win[1].len;
 	    }
-	    if (pcmcia_request_io(link->handle, &link->io) != 0)
+	    if (pcmcia_request_io(link, &link->io) != 0)
 		goto next_entry;
 	    /* If we've got this far, we're done */
 	    break;
@@ -220,15 +202,12 @@
 	
     next_entry:
 	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
     }
     
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
-    release_region(link->io.BasePort1, link->io.NumPorts1);
-    if (link->io.NumPorts2)
-	release_region(link->io.BasePort2, link->io.NumPorts2);
     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
 			      NULL);
@@ -247,17 +226,15 @@
     info->node.minor = p->number;
     info->port = p;
     strcpy(info->node.dev_name, p->name);
-    link->dev = &info->node;
+    link->dev_node = &info->node;
+
+    return 0;
 
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
 failed:
     parport_cs_release(link);
-    link->state &= ~DEV_CONFIG_PENDING;
-
+    return -ENODEV;
 } /* parport_config */
 
 /*======================================================================
@@ -268,53 +245,21 @@
     
 ======================================================================*/
 
-void parport_cs_release(dev_link_t *link)
+void parport_cs_release(struct pcmcia_device *link)
 {
-    parport_info_t *info = link->priv;
-    
-    DEBUG(0, "parport_release(0x%p)\n", link);
+	parport_info_t *info = link->priv;
 
-    if (info->ndev) {
-	struct parport *p = info->port;
-	parport_pc_unregister_port(p);
-	request_region(link->io.BasePort1, link->io.NumPorts1,
-		       info->node.dev_name);
-	if (link->io.NumPorts2)
-	    request_region(link->io.BasePort2, link->io.NumPorts2,
-			   info->node.dev_name);
-    }
-    info->ndev = 0;
-    link->dev = NULL;
-    
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
-
-} /* parport_cs_release */
-
-static int parport_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
+	DEBUG(0, "parport_release(0x%p)\n", link);
 
-	return 0;
-}
-
-static int parport_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
+	if (info->ndev) {
+		struct parport *p = info->port;
+		parport_pc_unregister_port(p);
+	}
+	info->ndev = 0;
 
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
+	pcmcia_disable_device(link);
+} /* parport_cs_release */
 
-	return 0;
-}
 
 static struct pcmcia_device_id parport_ids[] = {
 	PCMCIA_DEVICE_FUNC_ID(3),
@@ -328,11 +273,9 @@
 	.drv		= {
 		.name	= "parport_cs",
 	},
-	.probe		= parport_attach,
+	.probe		= parport_probe,
 	.remove		= parport_detach,
 	.id_table	= parport_ids,
-	.suspend	= parport_suspend,
-	.resume		= parport_resume,
 };
 
 static int __init init_parport_cs(void)
diff -urN oldtree/drivers/pcmcia/Kconfig newtree/drivers/pcmcia/Kconfig
--- oldtree/drivers/pcmcia/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/Kconfig	2006-04-01 05:35:44.287387750 -0500
@@ -263,6 +263,13 @@
 	  Say Y here to support the CompactFlash controller on OMAP.
 	  Note that this doesn't support "True IDE" mode.
 
+config AT91_CF
+	tristate "AT91 CompactFlash Controller"
+	depends on PCMCIA && ARCH_AT91RM9200
+	help
+	  Say Y here to support the CompactFlash controller on AT91 chips.
+	  Or choose M to compile the driver as a module named "at91_cf".
+
 config PCCARD_NONSTATIC
 	tristate
 
diff -urN oldtree/drivers/pcmcia/Makefile newtree/drivers/pcmcia/Makefile
--- oldtree/drivers/pcmcia/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/Makefile	2006-04-01 05:35:44.287387750 -0500
@@ -10,7 +10,7 @@
 pcmcia_core-$(CONFIG_CARDBUS)			+= cardbus.o
 obj-$(CONFIG_PCCARD)				+= pcmcia_core.o
 
-pcmcia-y					+= ds.o pcmcia_compat.o pcmcia_resource.o
+pcmcia-y					+= ds.o pcmcia_resource.o
 pcmcia-$(CONFIG_PCMCIA_IOCTL)			+= pcmcia_ioctl.o
 obj-$(CONFIG_PCMCIA)				+= pcmcia.o
 
@@ -36,6 +36,7 @@
 obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc4171_card.o
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
+obj-$(CONFIG_AT91_CF)				+= at91_cf.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
diff -urN oldtree/drivers/pcmcia/at91_cf.c newtree/drivers/pcmcia/at91_cf.c
--- oldtree/drivers/pcmcia/at91_cf.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/pcmcia/at91_cf.c	2006-04-01 05:35:44.283387500 -0500
@@ -0,0 +1,365 @@
+/*
+ * at91_cf.c -- AT91 CompactFlash controller driver
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/at91rm9200.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+
+#define	CF_SIZE		0x30000000	/* CS5+CS6: unavailable */
+
+/*
+ * A0..A10 work in each range; A23 indicates I/O space;  A25 is CFRNW;
+ * some other bit in {A24,A22..A11} is nREG to flag memory access
+ * (vs attributes).  So more than 2KB/region would just be waste.
+ */
+#define	CF_ATTR_PHYS	(AT91_CF_BASE)
+#define	CF_IO_PHYS	(AT91_CF_BASE  + (1 << 23))
+#define	CF_MEM_PHYS	(AT91_CF_BASE  + 0x017ff800)
+
+/*--------------------------------------------------------------------------*/
+
+static const char driver_name[] = "at91_cf";
+
+struct at91_cf_socket {
+	struct pcmcia_socket	socket;
+
+	unsigned		present:1;
+
+	struct platform_device	*pdev;
+	struct at91_cf_data	*board;
+};
+
+#define	SZ_2K			(2 * SZ_1K)
+
+static inline int at91_cf_present(struct at91_cf_socket *cf)
+{
+	return !at91_get_gpio_value(cf->board->det_pin);
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int at91_cf_ss_init(struct pcmcia_socket *s)
+{
+	return 0;
+}
+
+static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r)
+{
+	struct at91_cf_socket	*cf = (struct at91_cf_socket *) _cf;
+
+	if (irq == cf->board->det_pin) {
+		unsigned present = at91_cf_present(cf);
+
+		/* kick pccard as needed */
+		if (present != cf->present) {
+			cf->present = present;
+			pr_debug("%s: card %s\n", driver_name, present ? "present" : "gone");
+			pcmcia_parse_events(&cf->socket, SS_DETECT);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+	struct at91_cf_socket	*cf;
+
+	if (!sp)
+		return -EINVAL;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+
+	/* NOTE: we assume 3VCARD, not XVCARD...  */
+	if (at91_cf_present(cf)) {
+		int rdy	= cf->board->irq_pin;	/* RDY/nIRQ */
+		int vcc	= cf->board->vcc_pin;
+
+		*sp = SS_DETECT | SS_3VCARD;
+		if (!rdy || at91_get_gpio_value(rdy))
+			*sp |= SS_READY;
+		if (!vcc || at91_get_gpio_value(vcc))
+			*sp |= SS_POWERON;
+	} else
+		*sp = 0;
+
+	return 0;
+}
+
+static int at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+	struct at91_cf_socket	*cf;
+
+	cf = container_of(sock, struct at91_cf_socket, socket);
+
+	/* switch Vcc if needed and possible */
+	if (cf->board->vcc_pin) {
+		switch (s->Vcc) {
+			case 0:
+				at91_set_gpio_value(cf->board->vcc_pin, 0);
+				break;
+			case 33:
+				at91_set_gpio_value(cf->board->vcc_pin, 1);
+				break;
+			default:
+				return -EINVAL;
+		}
+	}
+
+	/* toggle reset if needed */
+	at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET);
+
+	pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
+		driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+	return 0;
+}
+
+static int at91_cf_ss_suspend(struct pcmcia_socket *s)
+{
+	return at91_cf_set_socket(s, &dead_socket);
+}
+
+/* we already mapped the I/O region */
+static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+	struct at91_cf_socket	*cf;
+	u32			csr;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+	io->flags &= (MAP_ACTIVE | MAP_16BIT | MAP_AUTOSZ);
+
+	/*
+	 * Use 16 bit accesses unless/until we need 8-bit i/o space.
+	 * Always set CSR4 ... PCMCIA won't always unmap things.
+	 */
+	csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW;
+
+	/*
+	 * NOTE: this CF controller ignores IOIS16, so we can't really do
+	 * MAP_AUTOSZ.  The 16bit mode allows single byte access on either
+	 * D0-D7 (even addr) or D8-D15 (odd), so it's close enough for many
+	 * purposes (and handles ide-cs).
+	 *
+	 * The 8bit mode is needed for odd byte access on D0-D7.  It seems
+	 * some cards only like that way to get at the odd byte, despite
+	 * CF 3.0 spec table 35 also giving the D8-D15 option.
+	 */
+	if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) {
+		csr |= AT91_SMC_DBW_8;
+		pr_debug("%s: 8bit i/o bus\n", driver_name);
+	} else {
+		csr |= AT91_SMC_DBW_16;
+		pr_debug("%s: 16bit i/o bus\n", driver_name);
+	}
+	at91_sys_write(AT91_SMC_CSR(4), csr);
+
+	io->start = cf->socket.io_offset;
+	io->stop = io->start + SZ_2K - 1;
+
+	return 0;
+}
+
+/* pcmcia layer maps/unmaps mem regions */
+static int at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+	struct at91_cf_socket	*cf;
+
+	if (map->card_start)
+		return -EINVAL;
+
+	cf = container_of(s, struct at91_cf_socket, socket);
+
+	map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = CF_ATTR_PHYS;
+	else
+		map->static_start = CF_MEM_PHYS;
+
+	return 0;
+}
+
+static struct pccard_operations at91_cf_ops = {
+	.init			= at91_cf_ss_init,
+	.suspend		= at91_cf_ss_suspend,
+	.get_status		= at91_cf_get_status,
+	.set_socket		= at91_cf_set_socket,
+	.set_io_map		= at91_cf_set_io_map,
+	.set_mem_map		= at91_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init at91_cf_probe(struct device *dev)
+{
+	struct at91_cf_socket	*cf;
+	struct at91_cf_data	*board = dev->platform_data;
+	struct platform_device	*pdev = to_platform_device(dev);
+	unsigned int		csa;
+	int			status;
+
+	if (!board || !board->det_pin || !board->rst_pin)
+		return -ENODEV;
+
+	cf = kcalloc(1, sizeof *cf, GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+
+	cf->board = board;
+	cf->pdev = pdev;
+	dev_set_drvdata(dev, cf);
+
+	/* CF takes over CS4, CS5, CS6 */
+	csa = at91_sys_read(AT91_EBI_CSA);
+	at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
+
+	/* force poweron defaults for these pins ... */
+	(void) at91_set_A_periph(AT91_PIN_PC9, 0);	/* A25/CFRNW */
+	(void) at91_set_A_periph(AT91_PIN_PC10, 0);	/* NCS4/CFCS */
+	(void) at91_set_A_periph(AT91_PIN_PC11, 0);	/* NCS5/CFCE1 */
+	(void) at91_set_A_periph(AT91_PIN_PC12, 0);	/* NCS6/CFCE2 */
+
+	/* nWAIT is _not_ a default setting */
+	(void) at91_set_A_periph(AT91_PIN_PC6, 1);	/*  nWAIT */
+
+	/*
+	 * Static memory controller timing adjustments.
+	 * REVISIT:  these timings are in terms of MCK cycles, so
+	 * when MCK changes (cpufreq etc) so must these values...
+	 */
+	at91_sys_write(AT91_SMC_CSR(4), AT91_SMC_ACSS_STD | AT91_SMC_DBW_16 | AT91_SMC_BAT | AT91_SMC_WSEN
+				| AT91_SMC_NWS_(32)		/* wait states */
+				| AT91_SMC_RWSETUP_(6)		/* setup time */
+				| AT91_SMC_RWHOLD_(4)		/* hold time */
+	);
+
+	/* must be a GPIO; ergo must trigger on both edges */
+	status = request_irq(board->det_pin, at91_cf_irq,
+			SA_SAMPLE_RANDOM, driver_name, cf);
+	if (status < 0)
+		goto fail0;
+
+	/*
+	 * The card driver will request this irq later as needed.
+	 * but it causes lots of "irqNN: nobody cared" messages
+	 * unless we report that we handle everything (sigh).
+	 * (Note:  DK board doesn't wire the IRQ pin...)
+	 */
+	if (board->irq_pin) {
+		status = request_irq(board->irq_pin, at91_cf_irq,
+				SA_SHIRQ, driver_name, cf);
+		if (status < 0)
+			goto fail0a;
+		cf->socket.pci_irq = board->irq_pin;
+	}
+	else
+		cf->socket.pci_irq = NR_IRQS + 1;
+
+	/* pcmcia layer only remaps "real" memory not iospace */
+	cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K);
+	if (!cf->socket.io_offset)
+		goto fail1;
+
+	/* reserve CS4, CS5, and CS6 regions; but use just CS4 */
+	if (!request_mem_region(AT91_CF_BASE, CF_SIZE, driver_name))
+		goto fail1;
+
+	pr_info("%s: irqs det #%d, io #%d\n", driver_name,
+		board->det_pin, board->irq_pin);
+
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.dev.dev = dev;
+	cf->socket.ops = &at91_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+				| SS_CAP_MEM_ALIGN;
+	cf->socket.map_size = SZ_2K;
+	cf->socket.io[0].NumPorts = SZ_2K;
+
+	status = pcmcia_register_socket(&cf->socket);
+	if (status < 0)
+		goto fail2;
+
+	return 0;
+
+fail2:
+	iounmap((void __iomem *) cf->socket.io_offset);
+	release_mem_region(AT91_CF_BASE, CF_SIZE);
+fail1:
+	if (board->irq_pin)
+		free_irq(board->irq_pin, cf);
+fail0a:
+	free_irq(board->det_pin, cf);
+fail0:
+	at91_sys_write(AT91_EBI_CSA, csa);
+	kfree(cf);
+	return status;
+}
+
+static int __exit at91_cf_remove(struct device *dev)
+{
+	struct at91_cf_socket *cf = dev_get_drvdata(dev);
+	unsigned int csa;
+
+	pcmcia_unregister_socket(&cf->socket);
+	free_irq(cf->board->irq_pin, cf);
+	free_irq(cf->board->det_pin, cf);
+	iounmap((void __iomem *) cf->socket.io_offset);
+	release_mem_region(AT91_CF_BASE, CF_SIZE);
+
+	csa = at91_sys_read(AT91_EBI_CSA);
+	at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A);
+
+	kfree(cf);
+	return 0;
+}
+
+static struct device_driver at91_cf_driver = {
+	.name		= (char *) driver_name,
+	.bus		= &platform_bus_type,
+	.probe		= at91_cf_probe,
+	.remove		= __exit_p(at91_cf_remove),
+	.suspend 	= pcmcia_socket_dev_suspend,
+	.resume 	= pcmcia_socket_dev_resume,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init at91_cf_init(void)
+{
+	return driver_register(&at91_cf_driver);
+}
+module_init(at91_cf_init);
+
+static void __exit at91_cf_exit(void)
+{
+	driver_unregister(&at91_cf_driver);
+}
+module_exit(at91_cf_exit);
+
+MODULE_DESCRIPTION("AT91 Compact Flash Driver");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/pcmcia/cistpl.c newtree/drivers/pcmcia/cistpl.c
--- oldtree/drivers/pcmcia/cistpl.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/cistpl.c	2006-04-01 05:35:44.283387500 -0500
@@ -12,7 +12,6 @@
  * (C) 1999		David A. Hinds
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
diff -urN oldtree/drivers/pcmcia/cs.c newtree/drivers/pcmcia/cs.c
--- oldtree/drivers/pcmcia/cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/cs.c	2006-04-01 05:35:44.283387500 -0500
@@ -16,7 +16,6 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/major.h>
 #include <linux/errno.h>
@@ -111,9 +110,9 @@
 	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
 		if (socket->dev.dev != dev)
 			continue;
-		down(&socket->skt_sem);
+		mutex_lock(&socket->skt_mutex);
 		socket_suspend(socket);
-		up(&socket->skt_sem);
+		mutex_unlock(&socket->skt_mutex);
 	}
 	up_read(&pcmcia_socket_list_rwsem);
 
@@ -129,9 +128,9 @@
 	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
 		if (socket->dev.dev != dev)
 			continue;
-		down(&socket->skt_sem);
+		mutex_lock(&socket->skt_mutex);
 		socket_resume(socket);
-		up(&socket->skt_sem);
+		mutex_unlock(&socket->skt_mutex);
 	}
 	up_read(&pcmcia_socket_list_rwsem);
 
@@ -237,7 +236,7 @@
 	init_completion(&socket->socket_released);
 	init_completion(&socket->thread_done);
 	init_waitqueue_head(&socket->thread_wait);
-	init_MUTEX(&socket->skt_sem);
+	mutex_init(&socket->skt_mutex);
 	spin_lock_init(&socket->thread_lock);
 
 	ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
@@ -406,8 +405,6 @@
 	cb_free(s);
 #endif
 	s->functions = 0;
-	kfree(s->config);
-	s->config = NULL;
 
 	s->ops->get_status(s, &status);
 	if (status & SS_POWERON) {
@@ -664,7 +661,7 @@
 		spin_unlock_irqrestore(&skt->thread_lock, flags);
 
 		if (events) {
-			down(&skt->skt_sem);
+			mutex_lock(&skt->skt_mutex);
 			if (events & SS_DETECT)
 				socket_detect_change(skt);
 			if (events & SS_BATDEAD)
@@ -673,7 +670,7 @@
 				send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
 			if (events & SS_READY)
 				send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
-			up(&skt->skt_sem);
+			mutex_unlock(&skt->skt_mutex);
 			continue;
 		}
 
@@ -717,8 +714,8 @@
 {
         int ret = 0;
 
-	/* s->skt_sem also protects s->callback */
-	down(&s->skt_sem);
+	/* s->skt_mutex also protects s->callback */
+	mutex_lock(&s->skt_mutex);
 
 	if (c) {
 		/* registration */
@@ -734,7 +731,7 @@
 	} else
 		s->callback = NULL;
  err:
-	up(&s->skt_sem);
+	mutex_unlock(&s->skt_mutex);
 
 	return ret;
 }
@@ -752,7 +749,7 @@
 
 	cs_dbg(skt, 1, "resetting socket\n");
 
-	down(&skt->skt_sem);
+	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
 			ret = CS_NO_CARD;
@@ -781,7 +778,7 @@
 
 		ret = CS_SUCCESS;
 	} while (0);
-	up(&skt->skt_sem);
+	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* reset_card */
@@ -797,7 +794,7 @@
 
 	cs_dbg(skt, 1, "suspending socket\n");
 
-	down(&skt->skt_sem);
+	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
 			ret = CS_NO_CARD;
@@ -814,7 +811,7 @@
 		}
 		ret = socket_suspend(skt);
 	} while (0);
-	up(&skt->skt_sem);
+	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* suspend_card */
@@ -827,7 +824,7 @@
     
 	cs_dbg(skt, 1, "waking up socket\n");
 
-	down(&skt->skt_sem);
+	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
 			ret = CS_NO_CARD;
@@ -841,7 +838,7 @@
 		if (!ret && skt->callback)
 			skt->callback->resume(skt);
 	} while (0);
-	up(&skt->skt_sem);
+	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* resume_card */
@@ -855,7 +852,7 @@
     
 	cs_dbg(skt, 1, "user eject request\n");
 
-	down(&skt->skt_sem);
+	mutex_lock(&skt->skt_mutex);
 	do {
 		if (!(skt->state & SOCKET_PRESENT)) {
 			ret = -ENODEV;
@@ -871,7 +868,7 @@
 		socket_remove(skt);
 		ret = 0;
 	} while (0);
-	up(&skt->skt_sem);
+	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* eject_card */
@@ -884,7 +881,7 @@
 
 	cs_dbg(skt, 1, "user insert request\n");
 
-	down(&skt->skt_sem);
+	mutex_lock(&skt->skt_mutex);
 	do {
 		if (skt->state & SOCKET_PRESENT) {
 			ret = -EBUSY;
@@ -896,7 +893,7 @@
 		}
 		ret = 0;
 	} while (0);
-	up(&skt->skt_sem);
+	mutex_unlock(&skt->skt_mutex);
 
 	return ret;
 } /* insert_card */
diff -urN oldtree/drivers/pcmcia/cs_internal.h newtree/drivers/pcmcia/cs_internal.h
--- oldtree/drivers/pcmcia/cs_internal.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/cs_internal.h	2006-04-01 05:35:44.283387500 -0500
@@ -15,7 +15,7 @@
 #ifndef _LINUX_CS_INTERNAL_H
 #define _LINUX_CS_INTERNAL_H
 
-#include <linux/config.h>
+#include <linux/kref.h>
 
 /* Flags in client state */
 #define CLIENT_CONFIG_LOCKED	0x0001
@@ -23,7 +23,7 @@
 #define CLIENT_IO_REQ		0x0004
 #define CLIENT_UNBOUND		0x0008
 #define CLIENT_STALE		0x0010
-#define CLIENT_WIN_REQ(i)	(0x20<<(i))
+#define CLIENT_WIN_REQ(i)	(0x1<<(i))
 #define CLIENT_CARDBUS		0x8000
 
 #define REGION_MAGIC	0xE3C9
@@ -31,7 +31,7 @@
     u_short		region_magic;
     u_short		state;
     dev_info_t		dev_info;
-    client_handle_t	mtd;
+    struct pcmcia_device	*mtd;
     u_int		MediaID;
     region_info_t	info;
 } region_t;
@@ -40,12 +40,12 @@
 
 /* Each card function gets one of these guys */
 typedef struct config_t {
+	struct kref	ref;
     u_int		state;
     u_int		Attributes;
     u_int		IntType;
     u_int		ConfigBase;
     u_char		Status, Pin, Copy, Option, ExtStatus;
-    u_int		Present;
     u_int		CardValues;
     io_req_t		io;
     struct {
@@ -95,12 +95,6 @@
 	}
 }
 
-#define CHECK_SOCKET(s) \
-    (((s) >= sockets) || (socket_table[s]->ops == NULL))
-
-#define SOCKET(h) (h->socket)
-#define CONFIG(h) (&SOCKET(h)->config[(h)->func])
-
 /* In cardbus.c */
 int cb_alloc(struct pcmcia_socket *s);
 void cb_free(struct pcmcia_socket *s);
@@ -133,10 +127,9 @@
 extern struct rw_semaphore pcmcia_socket_list_rwsem;
 extern struct list_head pcmcia_socket_list;
 int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req);
-int pccard_get_configuration_info(struct pcmcia_socket *s, unsigned int function, config_info_t *config);
+int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config);
 int pccard_reset_card(struct pcmcia_socket *skt);
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status);
-int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg);
+int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status);
 
 
 struct pcmcia_callback{
diff -urN oldtree/drivers/pcmcia/ds.c newtree/drivers/pcmcia/ds.c
--- oldtree/drivers/pcmcia/ds.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/ds.c	2006-04-01 05:35:44.287387750 -0500
@@ -10,10 +10,9 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * (C) 1999		David A. Hinds
- * (C) 2003 - 2005	Dominik Brodowski
+ * (C) 2003 - 2006	Dominik Brodowski
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -23,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
 #include <linux/firmware.h>
+#include <linux/kref.h>
 
 #define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
@@ -343,12 +343,19 @@
 		put_device(&p_dev->dev);
 }
 
+static void pcmcia_release_function(struct kref *ref)
+{
+	struct config_t *c = container_of(ref, struct config_t, ref);
+	kfree(c);
+}
+
 static void pcmcia_release_dev(struct device *dev)
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 	ds_dbg(1, "releasing dev %p\n", p_dev);
 	pcmcia_put_socket(p_dev->socket);
 	kfree(p_dev->devname);
+	kref_put(&p_dev->function_config->ref, pcmcia_release_function);
 	kfree(p_dev);
 }
 
@@ -377,29 +384,12 @@
 	p_drv = to_pcmcia_drv(dev->driver);
 	s = p_dev->socket;
 
-	if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) {
+	if ((!p_drv->probe) || (!p_dev->function_config) ||
+	    (!try_module_get(p_drv->owner))) {
 		ret = -EINVAL;
 		goto put_dev;
 	}
 
-	p_dev->state &= ~CLIENT_UNBOUND;
-
-	/* set up the device configuration, if it hasn't been done before */
-	if (!s->functions) {
-		cistpl_longlink_mfc_t mfc;
-		if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC,
-				      &mfc) == CS_SUCCESS)
-			s->functions = mfc.nfn;
-		else
-			s->functions = 1;
-		s->config = kzalloc(sizeof(config_t) * s->functions,
-				    GFP_KERNEL);
-		if (!s->config) {
-			ret = -ENOMEM;
-			goto put_module;
-		}
-	}
-
 	ret = p_drv->probe(p_dev);
 	if (ret)
 		goto put_module;
@@ -425,15 +415,61 @@
 }
 
 
+/*
+ * Removes a PCMCIA card from the device tree and socket list.
+ */
+static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
+{
+	struct pcmcia_device	*p_dev;
+	struct pcmcia_device	*tmp;
+	unsigned long		flags;
+
+	ds_dbg(2, "unbind_request(%d)\n", s->sock);
+
+
+	if (!leftover)
+		s->device_count = 0;
+	else
+		s->device_count = 1;
+
+	/* unregister all pcmcia_devices registered with this socket, except leftover */
+	list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
+		if (p_dev == leftover)
+			continue;
+
+		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+		list_del(&p_dev->socket_device_list);
+		p_dev->_removed=1;
+		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+		device_unregister(&p_dev->dev);
+	}
+
+	return;
+}
+
+
 static int pcmcia_device_remove(struct device * dev)
 {
 	struct pcmcia_device *p_dev;
 	struct pcmcia_driver *p_drv;
+	struct pcmcia_device_id *did;
 	int i;
 
-	/* detach the "instance" */
 	p_dev = to_pcmcia_dev(dev);
 	p_drv = to_pcmcia_drv(dev->driver);
+
+	/* If we're removing the primary module driving a
+	 * pseudo multi-function card, we need to unbind
+	 * all devices
+	 */
+	did = (struct pcmcia_device_id *) p_dev->dev.driver_data;
+	if ((did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
+	    (p_dev->socket->device_count != 0) &&
+	    (p_dev->device_no == 0))
+		pcmcia_card_remove(p_dev->socket, p_dev);
+
+	/* detach the "instance" */
 	if (!p_drv)
 		return 0;
 
@@ -441,17 +477,16 @@
 	       	p_drv->remove(p_dev);
 
 	/* check for proper unloading */
-	if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+	if (p_dev->_irq || p_dev->_io || p_dev->_locked)
 		printk(KERN_INFO "pcmcia: driver %s did not release config properly\n",
 		       p_drv->drv.name);
 
 	for (i = 0; i < MAX_WIN; i++)
-		if (p_dev->state & CLIENT_WIN_REQ(i))
+		if (p_dev->_win & CLIENT_WIN_REQ(i))
 			printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n",
 			       p_drv->drv.name);
 
 	/* references from pcmcia_probe_device */
-	p_dev->state = CLIENT_UNBOUND;
 	pcmcia_put_dev(p_dev);
 	module_put(p_drv->owner);
 
@@ -460,37 +495,6 @@
 
 
 /*
- * Removes a PCMCIA card from the device tree and socket list.
- */
-static void pcmcia_card_remove(struct pcmcia_socket *s)
-{
-	struct pcmcia_device	*p_dev;
-	unsigned long		flags;
-
-	ds_dbg(2, "unbind_request(%d)\n", s->sock);
-
-	s->device_count = 0;
-
-	for (;;) {
-		/* unregister all pcmcia_devices registered with this socket*/
-		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-		if (list_empty(&s->devices_list)) {
-			spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- 			return;
-		}
-		p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
-		list_del(&p_dev->socket_device_list);
-		p_dev->state |= CLIENT_STALE;
-		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-		device_unregister(&p_dev->dev);
-	}
-
-	return;
-} /* unbind_request */
-
-
-/*
  * pcmcia_device_query -- determine information about a pcmcia device
  */
 static int pcmcia_device_query(struct pcmcia_device *p_dev)
@@ -571,11 +575,11 @@
  * won't work, this doesn't matter much at the moment: the driver core doesn't
  * support it either.
  */
-static DECLARE_MUTEX(device_add_lock);
+static DEFINE_MUTEX(device_add_lock);
 
 struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
 {
-	struct pcmcia_device *p_dev;
+	struct pcmcia_device *p_dev, *tmp_dev;
 	unsigned long flags;
 	int bus_id_len;
 
@@ -583,7 +587,7 @@
 	if (!s)
 		return NULL;
 
-	down(&device_add_lock);
+	mutex_lock(&device_add_lock);
 
 	/* max of 2 devices per card */
 	if (s->device_count == 2)
@@ -596,6 +600,8 @@
 	p_dev->socket = s;
 	p_dev->device_no = (s->device_count++);
 	p_dev->func   = function;
+	if (s->functions <= function)
+		s->functions = function + 1;
 
 	p_dev->dev.bus = &pcmcia_bus_type;
 	p_dev->dev.parent = s->dev.dev;
@@ -608,36 +614,55 @@
 	sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id);
 
 	/* compat */
-	p_dev->state = CLIENT_UNBOUND;
+	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+
+	/*
+	 * p_dev->function_config must be the same for all card functions.
+	 * Note that this is serialized by the device_add_lock, so that
+	 * only one such struct will be created.
+	 */
+        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
+                if (p_dev->func == tmp_dev->func) {
+			p_dev->function_config = tmp_dev->function_config;
+			kref_get(&p_dev->function_config->ref);
+		}
 
 	/* Add to the list in pcmcia_bus_socket */
-	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 	list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
+	if (!p_dev->function_config) {
+		p_dev->function_config = kzalloc(sizeof(struct config_t),
+						 GFP_KERNEL);
+		if (!p_dev->function_config)
+			goto err_unreg;
+		kref_init(&p_dev->function_config->ref);
+	}
+
 	printk(KERN_NOTICE "pcmcia: registering new device %s\n",
 	       p_dev->devname);
 
 	pcmcia_device_query(p_dev);
 
-	if (device_register(&p_dev->dev)) {
-		spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
-		list_del(&p_dev->socket_device_list);
-		spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
-		goto err_free;
-       }
+	if (device_register(&p_dev->dev))
+		goto err_unreg;
 
-	up(&device_add_lock);
+	mutex_unlock(&device_add_lock);
 
 	return p_dev;
 
+ err_unreg:
+	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+	list_del(&p_dev->socket_device_list);
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
  err_free:
 	kfree(p_dev->devname);
 	kfree(p_dev);
 	s->device_count--;
  err_put:
-	up(&device_add_lock);
+	mutex_unlock(&device_add_lock);
 	pcmcia_put_socket(s);
 
 	return NULL;
@@ -696,7 +721,7 @@
 	int no_devices=0;
 	unsigned long flags;
 
-	/* must be called with skt_sem held */
+	/* must be called with skt_mutex held */
 	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
 	if (list_empty(&skt->devices_list))
 		no_devices=1;
@@ -819,9 +844,11 @@
 	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
 	struct pcmcia_device_id *did = p_drv->id_table;
 
+#ifdef CONFIG_PCMCIA_IOCTL
 	/* matching by cardmgr */
 	if (p_dev->cardmgr == p_drv)
 		return 1;
+#endif
 
 	while (did && did->match_flags) {
 		if (pcmcia_devmatch(p_dev, did))
@@ -927,7 +954,7 @@
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 
-	if (p_dev->dev.power.power_state.event != PM_EVENT_ON)
+	if (p_dev->suspended)
 		return sprintf(buf, "off\n");
 	else
 		return sprintf(buf, "on\n");
@@ -942,11 +969,9 @@
         if (!count)
                 return -EINVAL;
 
-	if ((p_dev->dev.power.power_state.event == PM_EVENT_ON) &&
-	    (!strncmp(buf, "off", 3)))
+	if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
 		ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
-	else if ((p_dev->dev.power.power_state.event != PM_EVENT_ON) &&
-		 (!strncmp(buf, "on", 2)))
+	else if (p_dev->suspended && !strncmp(buf, "on", 2))
 		dpm_runtime_resume(dev);
 
 	return ret ? ret : count;
@@ -982,9 +1007,9 @@
 	if (!count)
 		return -EINVAL;
 
-	down(&p_dev->socket->skt_sem);
+	mutex_lock(&p_dev->socket->skt_mutex);
 	p_dev->allow_func_id_match = 1;
-	up(&p_dev->socket->skt_sem);
+	mutex_unlock(&p_dev->socket->skt_mutex);
 
 	bus_rescan_devices(&pcmcia_bus_type);
 
@@ -1012,14 +1037,27 @@
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 	struct pcmcia_driver *p_drv = NULL;
+	int ret = 0;
 
 	if (dev->driver)
 		p_drv = to_pcmcia_drv(dev->driver);
 
-	if (p_drv && p_drv->suspend)
-		return p_drv->suspend(p_dev);
+	if (!p_drv)
+		goto out;
 
-	return 0;
+	if (p_drv->suspend) {
+		ret = p_drv->suspend(p_dev);
+		if (ret)
+			goto out;
+	}
+
+	if (p_dev->device_no == p_dev->func)
+		pcmcia_release_configuration(p_dev);
+
+ out:
+	if (!ret)
+		p_dev->suspended = 1;
+	return ret;
 }
 
 
@@ -1027,14 +1065,27 @@
 {
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
         struct pcmcia_driver *p_drv = NULL;
+	int ret = 0;
 
 	if (dev->driver)
 		p_drv = to_pcmcia_drv(dev->driver);
 
-	if (p_drv && p_drv->resume)
-		return p_drv->resume(p_dev);
+	if (!p_drv)
+		goto out;
 
-	return 0;
+	if (p_dev->device_no == p_dev->func) {
+		ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+		if (ret)
+			goto out;
+	}
+
+	if (p_drv->resume)
+		ret = p_drv->resume(p_dev);
+
+ out:
+	if (!ret)
+		p_dev->suspended = 0;
+	return ret;
 }
 
 
@@ -1100,7 +1151,7 @@
 	switch (event) {
 	case CS_EVENT_CARD_REMOVAL:
 		s->pcmcia_state.present = 0;
-		pcmcia_card_remove(skt);
+		pcmcia_card_remove(skt, NULL);
 		handle_event(skt, event);
 		break;
 
@@ -1128,6 +1179,32 @@
 } /* ds_event */
 
 
+struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev)
+{
+	struct pcmcia_device *p_dev;
+	struct pcmcia_device *ret = NULL;
+
+	p_dev = pcmcia_get_dev(_p_dev);
+	if (!p_dev)
+		return NULL;
+
+	if (!p_dev->socket->pcmcia_state.present)
+		goto out;
+
+	if (p_dev->_removed)
+		goto out;
+
+	if (p_dev->suspended)
+		goto out;
+
+	ret = p_dev;
+ out:
+	pcmcia_put_dev(p_dev);
+	return ret;
+}
+EXPORT_SYMBOL(pcmcia_dev_present);
+
+
 static struct pcmcia_callback pcmcia_bus_callback = {
 	.owner = THIS_MODULE,
 	.event = ds_event,
diff -urN oldtree/drivers/pcmcia/ds_internal.h newtree/drivers/pcmcia/ds_internal.h
--- oldtree/drivers/pcmcia/ds_internal.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/ds_internal.h	2006-04-01 05:35:44.287387750 -0500
@@ -8,6 +8,8 @@
 
 struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
 
+extern int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+
 #ifdef CONFIG_PCMCIA_IOCTL
 extern void __init pcmcia_setup_ioctl(void);
 extern void __exit pcmcia_cleanup_ioctl(void);
@@ -15,7 +17,7 @@
 extern int handle_request(struct pcmcia_socket *s, event_t event);
 #else
 static inline void __init pcmcia_setup_ioctl(void) { return; }
-static inline void __init pcmcia_cleanup_ioctl(void) { return; }
+static inline void __exit pcmcia_cleanup_ioctl(void) { return; }
 static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
 static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
 #endif
diff -urN oldtree/drivers/pcmcia/i82092.c newtree/drivers/pcmcia/i82092.c
--- oldtree/drivers/pcmcia/i82092.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/i82092.c	2006-04-01 05:35:44.287387750 -0500
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -urN oldtree/drivers/pcmcia/i82365.c newtree/drivers/pcmcia/i82365.c
--- oldtree/drivers/pcmcia/i82365.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/i82365.c	2006-04-01 05:35:44.287387750 -0500
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/string.h>
diff -urN oldtree/drivers/pcmcia/pcmcia_compat.c newtree/drivers/pcmcia/pcmcia_compat.c
--- oldtree/drivers/pcmcia/pcmcia_compat.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/pcmcia_compat.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,65 +0,0 @@
-/*
- * PCMCIA 16-bit compatibility functions
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * Copyright (C) 2004 Dominik Brodowski
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#define IN_CARD_SERVICES
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ss.h>
-
-#include "cs_internal.h"
-
-int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
-	return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_first_tuple);
-
-int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
-	return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_next_tuple);
-
-int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple)
-{
-	return pccard_get_tuple_data(p_dev->socket, tuple);
-}
-EXPORT_SYMBOL(pcmcia_get_tuple_data);
-
-int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse)
-{
-	return pccard_parse_tuple(tuple, parse);
-}
-EXPORT_SYMBOL(pcmcia_parse_tuple);
-
-int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info)
-{
-	return pccard_validate_cis(p_dev->socket, p_dev->func, info);
-}
-EXPORT_SYMBOL(pcmcia_validate_cis);
-
-
-int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req)
-{
-	return pccard_reset_card(p_dev->socket);
-}
-EXPORT_SYMBOL(pcmcia_reset_card);
diff -urN oldtree/drivers/pcmcia/pcmcia_ioctl.c newtree/drivers/pcmcia/pcmcia_ioctl.c
--- oldtree/drivers/pcmcia/pcmcia_ioctl.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/pcmcia_ioctl.c	2006-04-01 05:35:44.295388250 -0500
@@ -18,7 +18,6 @@
  */
 
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -70,10 +69,26 @@
 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
 #endif
 
+static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
+						unsigned int function)
+{
+	struct pcmcia_device *p_dev = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+	list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+		if (p_dev->func == function) {
+			spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+			return pcmcia_get_dev(p_dev);
+		}
+	}
+	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+	return NULL;
+}
 
 /* backwards-compatible accessing of driver --- by name! */
 
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
+static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
 {
 	struct device_driver *drv;
 	struct pcmcia_driver *p_drv;
@@ -214,7 +229,7 @@
 					 * by userspace before, we need to
 					 * return the "instance". */
 					spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-					bind_info->instance = p_dev->instance;
+					bind_info->instance = p_dev;
 					ret = -EBUSY;
 					goto err_put_module;
 				} else {
@@ -253,9 +268,9 @@
 	/*
 	 * Prevent this racing with a card insertion.
 	 */
-	down(&s->skt_sem);
+	mutex_lock(&s->skt_mutex);
 	bus_rescan_devices(&pcmcia_bus_type);
-	up(&s->skt_sem);
+	mutex_unlock(&s->skt_mutex);
 
 	/* check whether the driver indeed matched. I don't care if this
 	 * is racy or not, because it can only happen on cardmgr access
@@ -289,6 +304,7 @@
 {
 	dev_node_t *node;
 	struct pcmcia_device *p_dev;
+	struct pcmcia_driver *p_drv;
 	unsigned long flags;
 	int ret = 0;
 
@@ -343,16 +359,16 @@
  found:
 	spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
 
-	if ((!p_dev->instance) ||
-	    (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+	p_drv = to_pcmcia_drv(p_dev->dev.driver);
+	if (p_drv && !p_dev->_locked) {
 		ret = -EAGAIN;
 		goto err_put;
 	}
 
 	if (first)
-		node = p_dev->instance->dev;
+		node = p_dev->dev_node;
 	else
-		for (node = p_dev->instance->dev; node; node = node->next)
+		for (node = p_dev->dev_node; node; node = node->next)
 			if (node == bind_info->next)
 				break;
 	if (!node) {
@@ -583,14 +599,16 @@
 	if (buf->config.Function &&
 	   (buf->config.Function >= s->functions))
 	    ret = CS_BAD_ARGS;
-	else
-	    ret = pccard_get_configuration_info(s,
-			buf->config.Function, &buf->config);
+	else {
+	    struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
+	    ret = pccard_get_configuration_info(s, p_dev, &buf->config);
+	    pcmcia_put_dev(p_dev);
+	}
 	break;
     case DS_GET_FIRST_TUPLE:
-	down(&s->skt_sem);
+	mutex_lock(&s->skt_mutex);
 	pcmcia_validate_mem(s);
-	up(&s->skt_sem);
+	mutex_unlock(&s->skt_mutex);
 	ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
 	break;
     case DS_GET_NEXT_TUPLE:
@@ -609,16 +627,19 @@
 	ret = pccard_reset_card(s);
 	break;
     case DS_GET_STATUS:
-	if (buf->status.Function &&
-	   (buf->status.Function >= s->functions))
-	    ret = CS_BAD_ARGS;
-	else
-	ret = pccard_get_status(s, buf->status.Function, &buf->status);
-	break;
+	    if (buf->status.Function &&
+		(buf->status.Function >= s->functions))
+		    ret = CS_BAD_ARGS;
+	    else {
+		    struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
+		    ret = pccard_get_status(s, p_dev, &buf->status);
+		    pcmcia_put_dev(p_dev);
+	    }
+	    break;
     case DS_VALIDATE_CIS:
-	down(&s->skt_sem);
+	mutex_lock(&s->skt_mutex);
 	pcmcia_validate_mem(s);
-	up(&s->skt_sem);
+	mutex_unlock(&s->skt_mutex);
 	ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
 	break;
     case DS_SUSPEND_CARD:
@@ -638,12 +659,16 @@
 	    err = -EPERM;
 	    goto free_out;
 	}
-	if (buf->conf_reg.Function &&
-	   (buf->conf_reg.Function >= s->functions))
-	    ret = CS_BAD_ARGS;
-	else
-	    ret = pccard_access_configuration_register(s,
-			buf->conf_reg.Function, &buf->conf_reg);
+
+	ret = CS_BAD_ARGS;
+
+	if (!(buf->conf_reg.Function &&
+	     (buf->conf_reg.Function >= s->functions))) {
+		struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
+		if (p_dev)
+			ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
+		pcmcia_put_dev(p_dev);
+	}
 	break;
     case DS_GET_FIRST_REGION:
     case DS_GET_NEXT_REGION:
diff -urN oldtree/drivers/pcmcia/pcmcia_resource.c newtree/drivers/pcmcia/pcmcia_resource.c
--- oldtree/drivers/pcmcia/pcmcia_resource.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/pcmcia_resource.c	2006-04-01 05:35:44.295388250 -0500
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -89,7 +88,7 @@
 	}
 	if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
 		*base = s->io_offset | (*base & 0x0fff);
-		s->io[0].Attributes = attr;
+		s->io[0].res->flags = (s->io[0].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
 		return 0;
 	}
 	/* Check for an already-allocated window that must conflict with
@@ -97,38 +96,36 @@
 	 * potential conflicts, just the most obvious ones.
 	 */
 	for (i = 0; i < MAX_IO_WIN; i++)
-		if ((s->io[i].NumPorts != 0) &&
-		    ((s->io[i].BasePort & (align-1)) == *base))
+		if ((s->io[i].res) &&
+		    ((s->io[i].res->start & (align-1)) == *base))
 			return 1;
 	for (i = 0; i < MAX_IO_WIN; i++) {
-		if (s->io[i].NumPorts == 0) {
+		if (!s->io[i].res) {
 			s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
 			if (s->io[i].res) {
-				s->io[i].Attributes = attr;
-				s->io[i].BasePort = *base = s->io[i].res->start;
-				s->io[i].NumPorts = s->io[i].InUse = num;
+				*base = s->io[i].res->start;
+				s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
+				s->io[i].InUse = num;
 				break;
 			} else
 				return 1;
-		} else if (s->io[i].Attributes != attr)
+		} else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS))
 			continue;
 		/* Try to extend top of window */
-		try = s->io[i].BasePort + s->io[i].NumPorts;
+		try = s->io[i].res->end + 1;
 		if ((*base == 0) || (*base == try))
 			if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
 						    s->io[i].res->end + num, s) == 0) {
 				*base = try;
-				s->io[i].NumPorts += num;
 				s->io[i].InUse += num;
 				break;
 			}
 		/* Try to extend bottom of window */
-		try = s->io[i].BasePort - num;
+		try = s->io[i].res->start - num;
 		if ((*base == 0) || (*base == try))
 			if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
 						    s->io[i].res->end, s) == 0) {
-				s->io[i].BasePort = *base = try;
-				s->io[i].NumPorts += num;
+				*base = try;
 				s->io[i].InUse += num;
 				break;
 			}
@@ -143,12 +140,13 @@
 	int i;
 
 	for (i = 0; i < MAX_IO_WIN; i++) {
-		if ((s->io[i].BasePort <= base) &&
-		    (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+		if (!s->io[i].res)
+			continue;
+		if ((s->io[i].res->start <= base) &&
+		    (s->io[i].res->end >= base+num-1)) {
 			s->io[i].InUse -= num;
 			/* Free the window if no one else is using it */
 			if (s->io[i].InUse == 0) {
-				s->io[i].NumPorts = 0;
 				release_resource(s->io[i].res);
 				kfree(s->io[i].res);
 				s->io[i].res = NULL;
@@ -165,21 +163,19 @@
  * this and the tuple reading services.
  */
 
-int pccard_access_configuration_register(struct pcmcia_socket *s,
-					 unsigned int function,
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
 					 conf_reg_t *reg)
 {
+	struct pcmcia_socket *s;
 	config_t *c;
 	int addr;
 	u_char val;
 
-	if (!s || !s->config)
+	if (!p_dev || !p_dev->function_config)
 		return CS_NO_CARD;
 
-	c = &s->config[function];
-
-	if (c == NULL)
-		return CS_NO_CARD;
+	s = p_dev->socket;
+	c = p_dev->function_config;
 
 	if (!(c->state & CONFIG_LOCKED))
 		return CS_CONFIGURATION_LOCKED;
@@ -200,20 +196,12 @@
 		break;
 	}
 	return CS_SUCCESS;
-} /* pccard_access_configuration_register */
-
-int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
-					 conf_reg_t *reg)
-{
-	return pccard_access_configuration_register(p_dev->socket,
-						    p_dev->func, reg);
-}
+} /* pcmcia_access_configuration_register */
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 
 
-
 int pccard_get_configuration_info(struct pcmcia_socket *s,
-				  unsigned int function,
+				  struct pcmcia_device *p_dev,
 				  config_info_t *config)
 {
 	config_t *c;
@@ -221,7 +209,7 @@
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 
-	config->Function = function;
+	config->Function = p_dev->func;
 
 #ifdef CONFIG_CARDBUS
 	if (s->state & SOCKET_CARDBUS) {
@@ -235,14 +223,14 @@
 			config->AssignedIRQ = s->irq.AssignedIRQ;
 			if (config->AssignedIRQ)
 				config->Attributes |= CONF_ENABLE_IRQ;
-			config->BasePort1 = s->io[0].BasePort;
-			config->NumPorts1 = s->io[0].NumPorts;
+			config->BasePort1 = s->io[0].res->start;
+			config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1;
 		}
 		return CS_SUCCESS;
 	}
 #endif
 
-	c = (s->config != NULL) ? &s->config[function] : NULL;
+	c = (p_dev) ? p_dev->function_config : NULL;
 
 	if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
 		config->Attributes = 0;
@@ -271,7 +259,7 @@
 int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
 				  config_info_t *config)
 {
-	return pccard_get_configuration_info(p_dev->socket, p_dev->func,
+	return pccard_get_configuration_info(p_dev->socket, p_dev,
 					     config);
 }
 EXPORT_SYMBOL(pcmcia_get_configuration_info);
@@ -317,7 +305,7 @@
  * SocketState yet: I haven't seen any point for it.
  */
 
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
+int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev,
 		      cs_status_t *status)
 {
 	config_t *c;
@@ -334,11 +322,12 @@
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 
-	c = (s->config != NULL) ? &s->config[function] : NULL;
+	c = (p_dev) ? p_dev->function_config : NULL;
+
 	if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
 	    (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
 		u_char reg;
-		if (c->Present & PRESENT_PIN_REPLACE) {
+		if (c->CardValues & PRESENT_PIN_REPLACE) {
 			pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
 			status->CardState |=
 				(reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
@@ -352,7 +341,7 @@
 			/* No PRR?  Then assume we're always ready */
 			status->CardState |= CS_EVENT_READY_CHANGE;
 		}
-		if (c->Present & PRESENT_EXT_STATUS) {
+		if (c->CardValues & PRESENT_EXT_STATUS) {
 			pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
 			status->CardState |=
 				(reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
@@ -370,11 +359,9 @@
 	return CS_SUCCESS;
 } /* pccard_get_status */
 
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status)
 {
-	struct pcmcia_socket *s;
-	s = SOCKET(handle);
-	return pccard_get_status(s, handle->func, status);
+	return pccard_get_status(p_dev->socket, p_dev, status);
 }
 EXPORT_SYMBOL(pcmcia_get_status);
 
@@ -422,7 +409,8 @@
 	config_t *c;
 
 	s = p_dev->socket;
-	c = CONFIG(p_dev);
+	c = p_dev->function_config;
+
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
 	if (!(c->state & CONFIG_LOCKED))
@@ -454,6 +442,28 @@
 		   (mod->Attributes & CONF_VPP2_CHANGE_VALID))
 		return CS_BAD_VPP;
 
+	if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
+		pccard_io_map io_off = { 0, 0, 0, 0, 1 };
+		pccard_io_map io_on;
+		int i;
+
+		io_on.speed = io_speed;
+		for (i = 0; i < MAX_IO_WIN; i++) {
+			if (!s->io[i].res)
+				continue;
+			io_off.map = i;
+			io_on.map = i;
+
+			io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
+			io_on.start = s->io[i].res->start;
+			io_on.stop = s->io[i].res->end;
+
+			s->ops->set_io_map(s, &io_off);
+			mdelay(40);
+			s->ops->set_io_map(s, &io_on);
+		}
+	}
+
 	return CS_SUCCESS;
 } /* modify_configuration */
 EXPORT_SYMBOL(pcmcia_modify_configuration);
@@ -463,23 +473,23 @@
 {
 	pccard_io_map io = { 0, 0, 0, 0, 1 };
 	struct pcmcia_socket *s = p_dev->socket;
+	config_t *c = p_dev->function_config;
 	int i;
 
-	if (!(p_dev->state & CLIENT_CONFIG_LOCKED))
-		return CS_BAD_HANDLE;
-	p_dev->state &= ~CLIENT_CONFIG_LOCKED;
-
-	if (!(p_dev->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(p_dev);
+	if (p_dev->_locked) {
+		p_dev->_locked = 0;
 		if (--(s->lock_count) == 0) {
 			s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
 			s->socket.Vpp = 0;
 			s->socket.io_irq = 0;
 			s->ops->set_socket(s, &s->socket);
 		}
+	}
+	if (c->state & CONFIG_LOCKED) {
+		c->state &= ~CONFIG_LOCKED;
 		if (c->state & CONFIG_IO_REQ)
 			for (i = 0; i < MAX_IO_WIN; i++) {
-				if (s->io[i].NumPorts == 0)
+				if (!s->io[i].res)
 					continue;
 				s->io[i].Config--;
 				if (s->io[i].Config != 0)
@@ -487,12 +497,10 @@
 				io.map = i;
 				s->ops->set_io_map(s, &io);
 			}
-		c->state &= ~CONFIG_LOCKED;
 	}
 
 	return CS_SUCCESS;
 } /* pcmcia_release_configuration */
-EXPORT_SYMBOL(pcmcia_release_configuration);
 
 
 /** pcmcia_release_io
@@ -503,25 +511,23 @@
  * don't bother checking the port ranges against the current socket
  * values.
  */
-int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
 {
 	struct pcmcia_socket *s = p_dev->socket;
+	config_t *c = p_dev->function_config;
 
-	if (!(p_dev->state & CLIENT_IO_REQ))
+	if (!p_dev->_io )
 		return CS_BAD_HANDLE;
-	p_dev->state &= ~CLIENT_IO_REQ;
 
-	if (!(p_dev->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(p_dev);
-		if (c->state & CONFIG_LOCKED)
-			return CS_CONFIGURATION_LOCKED;
-		if ((c->io.BasePort1 != req->BasePort1) ||
-		    (c->io.NumPorts1 != req->NumPorts1) ||
-		    (c->io.BasePort2 != req->BasePort2) ||
-		    (c->io.NumPorts2 != req->NumPorts2))
-			return CS_BAD_ARGS;
-		c->state &= ~CONFIG_IO_REQ;
-	}
+	p_dev->_io = 0;
+
+	if ((c->io.BasePort1 != req->BasePort1) ||
+	    (c->io.NumPorts1 != req->NumPorts1) ||
+	    (c->io.BasePort2 != req->BasePort2) ||
+	    (c->io.NumPorts2 != req->NumPorts2))
+		return CS_BAD_ARGS;
+
+	c->state &= ~CONFIG_IO_REQ;
 
 	release_io_space(s, req->BasePort1, req->NumPorts1);
 	if (req->NumPorts2)
@@ -529,28 +535,26 @@
 
 	return CS_SUCCESS;
 } /* pcmcia_release_io */
-EXPORT_SYMBOL(pcmcia_release_io);
 
 
-int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
+static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
 {
 	struct pcmcia_socket *s = p_dev->socket;
-	if (!(p_dev->state & CLIENT_IRQ_REQ))
+	config_t *c= p_dev->function_config;
+
+	if (!p_dev->_irq)
 		return CS_BAD_HANDLE;
-	p_dev->state &= ~CLIENT_IRQ_REQ;
+	p_dev->_irq = 0;
 
-	if (!(p_dev->state & CLIENT_STALE)) {
-		config_t *c = CONFIG(p_dev);
-		if (c->state & CONFIG_LOCKED)
-			return CS_CONFIGURATION_LOCKED;
-		if (c->irq.Attributes != req->Attributes)
-			return CS_BAD_ATTRIBUTE;
-		if (s->irq.AssignedIRQ != req->AssignedIRQ)
-			return CS_BAD_IRQ;
-		if (--s->irq.Config == 0) {
-			c->state &= ~CONFIG_IRQ_REQ;
-			s->irq.AssignedIRQ = 0;
-		}
+	if (c->state & CONFIG_LOCKED)
+		return CS_CONFIGURATION_LOCKED;
+	if (c->irq.Attributes != req->Attributes)
+		return CS_BAD_ATTRIBUTE;
+	if (s->irq.AssignedIRQ != req->AssignedIRQ)
+		return CS_BAD_IRQ;
+	if (--s->irq.Config == 0) {
+		c->state &= ~CONFIG_IRQ_REQ;
+		s->irq.AssignedIRQ = 0;
 	}
 
 	if (req->Attributes & IRQ_HANDLE_PRESENT) {
@@ -563,7 +567,6 @@
 
 	return CS_SUCCESS;
 } /* pcmcia_release_irq */
-EXPORT_SYMBOL(pcmcia_release_irq);
 
 
 int pcmcia_release_window(window_handle_t win)
@@ -573,7 +576,7 @@
 	if ((win == NULL) || (win->magic != WINDOW_MAGIC))
 		return CS_BAD_HANDLE;
 	s = win->sock;
-	if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+	if (!(win->handle->_win & CLIENT_WIN_REQ(win->index)))
 		return CS_BAD_HANDLE;
 
 	/* Shut down memory window */
@@ -587,7 +590,7 @@
 		kfree(win->ctl.res);
 		win->ctl.res = NULL;
 	}
-	win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+	win->handle->_win &= ~CLIENT_WIN_REQ(win->index);
 
 	win->magic = 0;
 
@@ -610,16 +613,12 @@
 
 	if (req->IntType & INT_CARDBUS)
 		return CS_UNSUPPORTED_MODE;
-	c = CONFIG(p_dev);
+	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 
 	/* Do power control.  We don't allow changes in Vcc. */
-	if (s->socket.Vcc != req->Vcc)
-		return CS_BAD_VCC;
-	if (req->Vpp1 != req->Vpp2)
-		return CS_BAD_VPP;
-	s->socket.Vpp = req->Vpp1;
+	s->socket.Vpp = req->Vpp;
 	if (s->ops->set_socket(s, &s->socket))
 		return CS_BAD_VPP;
 
@@ -643,7 +642,7 @@
 
 	/* Set up CIS configuration registers */
 	base = c->ConfigBase = req->ConfigBase;
-	c->Present = c->CardValues = req->Present;
+	c->CardValues = req->Present;
 	if (req->Present & PRESENT_COPY) {
 		c->Copy = req->Copy;
 		pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
@@ -690,10 +689,10 @@
 	if (c->state & CONFIG_IO_REQ) {
 		iomap.speed = io_speed;
 		for (i = 0; i < MAX_IO_WIN; i++)
-			if (s->io[i].NumPorts != 0) {
+			if (s->io[i].res) {
 				iomap.map = i;
 				iomap.flags = MAP_ACTIVE;
-				switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+				switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) {
 				case IO_DATA_PATH_WIDTH_16:
 					iomap.flags |= MAP_16BIT; break;
 				case IO_DATA_PATH_WIDTH_AUTO:
@@ -701,15 +700,15 @@
 				default:
 					break;
 				}
-				iomap.start = s->io[i].BasePort;
-				iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+				iomap.start = s->io[i].res->start;
+				iomap.stop = s->io[i].res->end;
 				s->ops->set_io_map(s, &iomap);
 				s->io[i].Config++;
 			}
 	}
 
 	c->state |= CONFIG_LOCKED;
-	p_dev->state |= CLIENT_CONFIG_LOCKED;
+	p_dev->_locked = 1;
 	return CS_SUCCESS;
 } /* pcmcia_request_configuration */
 EXPORT_SYMBOL(pcmcia_request_configuration);
@@ -730,7 +729,7 @@
 
 	if (!req)
 		return CS_UNSUPPORTED_MODE;
-	c = CONFIG(p_dev);
+	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 	if (c->state & CONFIG_IO_REQ)
@@ -755,7 +754,7 @@
 
 	c->io = *req;
 	c->state |= CONFIG_IO_REQ;
-	p_dev->state |= CLIENT_IO_REQ;
+	p_dev->_io = 1;
 	return CS_SUCCESS;
 } /* pcmcia_request_io */
 EXPORT_SYMBOL(pcmcia_request_io);
@@ -786,7 +785,7 @@
 
 	if (!(s->state & SOCKET_PRESENT))
 		return CS_NO_CARD;
-	c = CONFIG(p_dev);
+	c = p_dev->function_config;
 	if (c->state & CONFIG_LOCKED)
 		return CS_CONFIGURATION_LOCKED;
 	if (c->state & CONFIG_IRQ_REQ)
@@ -851,7 +850,7 @@
 	s->irq.Config++;
 
 	c->state |= CONFIG_IRQ_REQ;
-	p_dev->state |= CLIENT_IRQ_REQ;
+	p_dev->_irq = 1;
 
 #ifdef CONFIG_PCMCIA_PROBE
 	pcmcia_used_irq[irq]++;
@@ -911,7 +910,7 @@
 		if (!win->ctl.res)
 			return CS_IN_USE;
 	}
-	(*p_dev)->state |= CLIENT_WIN_REQ(w);
+	(*p_dev)->_win |= CLIENT_WIN_REQ(w);
 
 	/* Configure the socket controller */
 	win->ctl.map = w+1;
@@ -941,3 +940,14 @@
 	return CS_SUCCESS;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
+
+void pcmcia_disable_device(struct pcmcia_device *p_dev) {
+	pcmcia_release_configuration(p_dev);
+	pcmcia_release_io(p_dev, &p_dev->io);
+	pcmcia_release_irq(p_dev, &p_dev->irq);
+	if (&p_dev->win)
+		pcmcia_release_window(p_dev->win);
+
+	p_dev->dev_node = NULL;
+}
+EXPORT_SYMBOL(pcmcia_disable_device);
diff -urN oldtree/drivers/pcmcia/pd6729.c newtree/drivers/pcmcia/pd6729.c
--- oldtree/drivers/pcmcia/pd6729.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/pd6729.c	2006-04-01 05:35:44.295388250 -0500
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -urN oldtree/drivers/pcmcia/rsrc_mgr.c newtree/drivers/pcmcia/rsrc_mgr.c
--- oldtree/drivers/pcmcia/rsrc_mgr.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/rsrc_mgr.c	2006-04-01 05:35:44.299388500 -0500
@@ -12,7 +12,6 @@
  * (C) 1999		David A. Hinds
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 
@@ -22,6 +21,8 @@
 #include "cs_internal.h"
 
 
+#ifdef CONFIG_PCMCIA_IOCTL
+
 #ifdef CONFIG_PCMCIA_PROBE
 
 static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
@@ -98,6 +99,8 @@
 }
 EXPORT_SYMBOL(pcmcia_adjust_resource_info);
 
+#endif
+
 int pcmcia_validate_mem(struct pcmcia_socket *s)
 {
 	if (s->resource_ops->validate_mem)
diff -urN oldtree/drivers/pcmcia/rsrc_nonstatic.c newtree/drivers/pcmcia/rsrc_nonstatic.c
--- oldtree/drivers/pcmcia/rsrc_nonstatic.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/rsrc_nonstatic.c	2006-04-01 05:35:44.299388500 -0500
@@ -12,7 +12,6 @@
  * (C) 1999		David A. Hinds
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -61,7 +60,7 @@
 	unsigned int			rsrc_mem_probe;
 };
 
-static DECLARE_MUTEX(rsrc_sem);
+static DEFINE_MUTEX(rsrc_mutex);
 #define MEM_PROBE_LOW	(1 << 0)
 #define MEM_PROBE_HIGH	(1 << 1)
 
@@ -484,7 +483,7 @@
 
 
 /*
- * Locking note: Must be called with skt_sem held!
+ * Locking note: Must be called with skt_mutex held!
  */
 static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
 {
@@ -495,7 +494,7 @@
 	if (!probe_mem)
 		return 0;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 
 	if (s->features & SS_CAP_PAGE_REGS)
 		probe_mask = MEM_PROBE_HIGH;
@@ -507,7 +506,7 @@
 			s_data->rsrc_mem_probe |= probe_mask;
 	}
 
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 
 	return ret;
 }
@@ -585,7 +584,7 @@
 	struct socket_data *s_data = s->resource_data;
 	int ret = -ENOMEM;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
 		unsigned long start = m->base;
 		unsigned long end = m->base + m->num - 1;
@@ -596,7 +595,7 @@
 		ret = adjust_resource(res, r_start, r_end - r_start + 1);
 		break;
 	}
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 
 	return ret;
 }
@@ -630,7 +629,7 @@
 	data.offset = base & data.mask;
 	data.map = &s_data->io_db;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 #ifdef CONFIG_PCI
 	if (s->cb_dev) {
 		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
@@ -639,7 +638,7 @@
 #endif
 		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
 					1, pcmcia_align, &data);
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 
 	if (ret != 0) {
 		kfree(res);
@@ -672,7 +671,7 @@
 			min = 0x100000UL + base;
 		}
 
-		down(&rsrc_sem);
+		mutex_lock(&rsrc_mutex);
 #ifdef CONFIG_PCI
 		if (s->cb_dev) {
 			ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
@@ -682,7 +681,7 @@
 #endif
 			ret = allocate_resource(&iomem_resource, res, num, min,
 						max, 1, pcmcia_align, &data);
-		up(&rsrc_sem);
+		mutex_unlock(&rsrc_mutex);
 		if (ret == 0 || low)
 			break;
 		low = 1;
@@ -705,7 +704,7 @@
 	if (end < start)
 		return -EINVAL;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	switch (action) {
 	case ADD_MANAGED_RESOURCE:
 		ret = add_interval(&data->mem_db, start, size);
@@ -723,7 +722,7 @@
 	default:
 		ret = -EINVAL;
 	}
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 
 	return ret;
 }
@@ -741,7 +740,7 @@
 	if (end > IO_SPACE_LIMIT)
 		return -EINVAL;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	switch (action) {
 	case ADD_MANAGED_RESOURCE:
 		if (add_interval(&data->io_db, start, size) != 0) {
@@ -760,7 +759,7 @@
 		ret = -EINVAL;
 		break;
 	}
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 
 	return ret;
 }
@@ -867,7 +866,7 @@
 	struct socket_data *data = s->resource_data;
 	struct resource_map *p, *q;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	for (p = data->mem_db.next; p != &data->mem_db; p = q) {
 		q = p->next;
 		kfree(p);
@@ -876,7 +875,7 @@
 		q = p->next;
 		kfree(p);
 	}
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 }
 
 
@@ -901,7 +900,7 @@
 	struct resource_map *p;
 	ssize_t ret = 0;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	data = s->resource_data;
 
 	for (p = data->io_db.next; p != &data->io_db; p = p->next) {
@@ -913,7 +912,7 @@
 				 ((unsigned long) p->base + p->num - 1));
 	}
 
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 	return (ret);
 }
 
@@ -953,7 +952,7 @@
 	struct resource_map *p;
 	ssize_t ret = 0;
 
-	down(&rsrc_sem);
+	mutex_lock(&rsrc_mutex);
 	data = s->resource_data;
 
 	for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
@@ -965,7 +964,7 @@
 				 ((unsigned long) p->base + p->num - 1));
 	}
 
-	up(&rsrc_sem);
+	mutex_unlock(&rsrc_mutex);
 	return (ret);
 }
 
diff -urN oldtree/drivers/pcmcia/sa1100_cerf.c newtree/drivers/pcmcia/sa1100_cerf.c
--- oldtree/drivers/pcmcia/sa1100_cerf.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/sa1100_cerf.c	2006-04-01 05:35:44.299388500 -0500
@@ -5,7 +5,6 @@
  * Based off the Assabet.
  *
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -urN oldtree/drivers/pcmcia/socket_sysfs.c newtree/drivers/pcmcia/socket_sysfs.c
--- oldtree/drivers/pcmcia/socket_sysfs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/socket_sysfs.c	2006-04-01 05:35:44.299388500 -0500
@@ -12,7 +12,6 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/major.h>
 #include <linux/errno.h>
@@ -25,6 +24,7 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
@@ -183,7 +183,7 @@
 		s->resource_setup_done = 1;
 	spin_unlock_irqrestore(&s->lock, flags);
 
-	down(&s->skt_sem);
+	mutex_lock(&s->skt_mutex);
 	if ((s->callback) &&
 	    (s->state & SOCKET_PRESENT) &&
 	    !(s->state & SOCKET_CARDBUS)) {
@@ -192,7 +192,7 @@
 			module_put(s->callback->owner);
 		}
 	}
-	up(&s->skt_sem);
+	mutex_unlock(&s->skt_mutex);
 
 	return count;
 }
@@ -322,7 +322,7 @@
 	kfree(cis);
 
 	if (!ret) {
-		down(&s->skt_sem);
+		mutex_lock(&s->skt_mutex);
 		if ((s->callback) && (s->state & SOCKET_PRESENT) &&
 		    !(s->state & SOCKET_CARDBUS)) {
 			if (try_module_get(s->callback->owner)) {
@@ -330,7 +330,7 @@
 				module_put(s->callback->owner);
 			}
 		}
-		up(&s->skt_sem);
+		mutex_unlock(&s->skt_mutex);
 	}
 
 
diff -urN oldtree/drivers/pcmcia/ti113x.h newtree/drivers/pcmcia/ti113x.h
--- oldtree/drivers/pcmcia/ti113x.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/pcmcia/ti113x.h	2006-04-01 05:35:44.299388500 -0500
@@ -30,7 +30,6 @@
 #ifndef _LINUX_TI113X_H
 #define _LINUX_TI113X_H
 
-#include <linux/config.h>
 
 /* Register definitions for TI 113X PCI-to-CardBus bridges */
 
diff -urN oldtree/drivers/scsi/Kconfig newtree/drivers/scsi/Kconfig
--- oldtree/drivers/scsi/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/Kconfig	2006-04-01 05:35:45.919489750 -0500
@@ -27,6 +27,13 @@
 	  However, do not compile this as a module if your root file system
 	  (the one containing the directory /) is located on a SCSI device.
 
+config SCSI_TGT
+	tristate "SCSI target support"
+	depends on SCSI && EXPERIMENTAL
+	---help---
+	  If you want to use SCSI target mode drivers enable this option.
+	  If you choose M, the module will be called scsi_tgt.
+
 config SCSI_PROC_FS
 	bool "legacy /proc/scsi/ support"
 	depends on SCSI && PROC_FS
@@ -209,7 +216,7 @@
 	  there should be no noticeable performance impact as long as you have
 	  logging turned off.
 
-menu "SCSI Transport Attributes"
+menu "SCSI Transports"
 	depends on SCSI
 
 config SCSI_SPI_ATTRS
@@ -242,6 +249,8 @@
 	  If you wish to export transport-specific information about
 	  each attached SAS device to sysfs, say Y.
 
+source "drivers/scsi/sas/Kconfig"
+
 endmenu
 
 menu "SCSI low-level drivers"
@@ -423,6 +432,7 @@
 	  module will be called aic7xxx_old.
 
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
+source "drivers/scsi/aic94xx/Kconfig"
 
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
@@ -459,6 +469,20 @@
 	  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).
+
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 
 config SCSI_SATA
@@ -1071,7 +1095,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 +1106,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 +1115,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/Makefile	2006-04-01 05:35:45.919489750 -0500
@@ -21,6 +21,7 @@
 subdir-$(CONFIG_PCMCIA)		+= pcmcia
 
 obj-$(CONFIG_SCSI)		+= scsi_mod.o
+obj-$(CONFIG_SCSI_TGT)		+= scsi_tgt.o
 
 obj-$(CONFIG_RAID_ATTRS)	+= raid_class.o
 
@@ -32,6 +33,7 @@
 obj-$(CONFIG_SCSI_FC_ATTRS) 	+= scsi_transport_fc.o
 obj-$(CONFIG_SCSI_ISCSI_ATTRS)	+= scsi_transport_iscsi.o
 obj-$(CONFIG_SCSI_SAS_ATTRS)	+= scsi_transport_sas.o
+obj-$(CONFIG_SAS_CLASS)		+= sas/
 
 obj-$(CONFIG_ISCSI_TCP) 	+= iscsi_tcp.o
 obj-$(CONFIG_SCSI_AMIGA7XX)	+= amiga7xx.o	53c7xx.o
@@ -58,6 +60,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
@@ -66,6 +69,7 @@
 obj-$(CONFIG_SCSI_AIC79XX)	+= aic7xxx/
 obj-$(CONFIG_SCSI_AACRAID)	+= aacraid/
 obj-$(CONFIG_SCSI_AIC7XXX_OLD)	+= aic7xxx_old.o
+obj-$(CONFIG_SCSI_AIC94XX)	+= aic94xx/
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
 obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
 obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
@@ -155,6 +159,8 @@
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 
+scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
+
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
diff -urN oldtree/drivers/scsi/aacraid/aachba.c newtree/drivers/scsi/aacraid/aachba.c
--- oldtree/drivers/scsi/aacraid/aachba.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/aacraid/aachba.c	2006-04-01 05:35:44.767417750 -0500
@@ -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/aic94xx/Kconfig newtree/drivers/scsi/aic94xx/Kconfig
--- oldtree/drivers/scsi/aic94xx/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/Kconfig	2006-04-01 05:35:45.915489500 -0500
@@ -0,0 +1,41 @@
+#
+# Kernel configuration file for aic94xx SAS/SATA driver.
+#
+# Copyright (c) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the aic94xx driver.
+#
+# The aic94xx driver 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.
+#
+# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+# $Id: //depot/aic94xx/Kconfig#9 $
+#
+
+config SCSI_AIC94XX
+	tristate "Adaptec AIC94xx SAS/SATA support"
+	depends on PCI && SAS_CLASS
+	help
+		This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
+		AIC94xx chip based host adapters.
+
+config AIC94XX_DEBUG
+	bool "Compile in debug mode"
+	default y
+	depends on SCSI_AIC94XX
+	help
+		Compiles the aic94xx driver in debug mode.  In debug mode,
+		the driver prints some messages to the console.
diff -urN oldtree/drivers/scsi/aic94xx/Makefile newtree/drivers/scsi/aic94xx/Makefile
--- oldtree/drivers/scsi/aic94xx/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/Makefile	2006-04-01 05:35:45.919489750 -0500
@@ -0,0 +1,42 @@
+#
+# Makefile for Adaptec aic94xx SAS/SATA driver.
+#
+# Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the the aic94xx driver.
+#
+# The aic94xx driver 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.
+#
+# The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+# $Id: //depot/aic94xx/Makefile#37 $
+#
+
+ifeq ($(CONFIG_AIC94XX_DEBUG),y)
+	EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT -g
+endif
+
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
+aic94xx-y += aic94xx_init.o \
+	     aic94xx_hwi.o  \
+	     aic94xx_reg.o  \
+	     aic94xx_sds.o  \
+	     aic94xx_seq.o  \
+	     aic94xx_dump.o \
+	     aic94xx_scb.o  \
+	     aic94xx_dev.o  \
+	     aic94xx_tmf.o  \
+	     aic94xx_task.o
diff -urN oldtree/drivers/scsi/aic94xx/README newtree/drivers/scsi/aic94xx/README
--- oldtree/drivers/scsi/aic94xx/README	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/README	2006-04-01 05:35:45.919489750 -0500
@@ -0,0 +1,82 @@
+$Id: //depot/aic94xx/README#2 $
+
+Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+
+LICENSE AGREEMENT
+-----------------
+
+This file is licensed under GPLv2.
+
+This file is part of the aic94xx driver.
+
+The aic94xx driver 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.
+
+The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Introduction
+------------
+
+The aic94xx driver supports Adaptec SAS/SATA Host Adapters
+with AIC-94xx chips.  Features include 32/64 bit PCI/PCI-X
+interface supporting up to 66 MHz PCI 2.3 and up to 133 MHz
+PCI-X 2.0 operation.  It supports MSI or PCI interrupt pin.
+      * AIC-9405W is a  4 phy host adapter, 4 port maximum.
+      * AIC-9410W is an 8 phy host adapter, 8 port maximum.
+
+The driver supports Revision B0 or later of the controller.
+
+
+Hot plugging
+------------
+
+Hot plugging is supported, it works and has been tested.
+
+
+Dynamic PCI IDs
+---------------
+
+To make the driver probe and attach to a new device it
+doesn't quite recognize, you can dynamically add to the PCI
+ID table of the driver as follows:
+
+echo "vendor device" > /sys/bus/pci/drivers/aic94xx/new_id
+
+For the complete details see Documentation/pci.txt file.
+
+
+Not a HostRAID driver
+---------------------
+
+This driver is _not_ a HostRAID driver, it does _not_
+provide RAID capabilities.  Although RAID could be built on
+top of the devices exported by this driver.
+
+If you would like this driver to attach to a HostRAID
+enabled controller*, set the "attach_HostRAID" module
+parameter to "1" either at module load time or through sysfs.
+
+Kernel command line; append this:
+
+       aic94xx.attach_HostRAID=1
+
+Module loading, append this to your modprobe/insmod:
+
+       attach_HostRAID=1
+
+Or through sysfs, if the driver has already been loaded:
+
+echo "1" > /sys/module/aic94xx/parameters/attach_HostRAID
+
+* This of course could COMPLETELY destroy your HostRAID
+  array, and is NOT recommended.
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx.h newtree/drivers/scsi/aic94xx/aic94xx.h
--- oldtree/drivers/scsi/aic94xx/aic94xx.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx.h	2006-04-01 05:35:45.899488500 -0500
@@ -0,0 +1,114 @@
+/*
+ * Aic94xx SAS/SATA driver header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx.h#31 $
+ */
+
+#ifndef _AIC94XX_H_
+#define _AIC94XX_H_
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <scsi/sas/sas_discover.h>
+
+#define ASD_DRIVER_NAME		"aic94xx"
+#define ASD_DRIVER_DESCRIPTION	"Adaptec aic94xx SAS/SATA driver"
+
+#define asd_printk(fmt, ...)	printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
+
+#ifdef ASD_ENTER_EXIT
+#define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
+		__FUNCTION__)
+#define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
+		__FUNCTION__)
+#else
+#define ENTER
+#define EXIT
+#endif
+
+#ifdef ASD_DEBUG
+#define ASD_DPRINTK asd_printk
+#else
+#define ASD_DPRINTK(fmt, ...)
+#endif
+
+/* 2*ITNL timeout + 1 second */
+#define AIC94XX_SCB_TIMEOUT  (5*HZ)
+
+extern kmem_cache_t *asd_dma_token_cache;
+extern kmem_cache_t *asd_ascb_cache;
+extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
+
+static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
+{
+	int i;
+	for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
+		snprintf(p, 3, "%02X", sas_addr[i]);
+	*p = '\0';
+}
+
+static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
+{
+	int i;
+	for (i = 0; i < SAS_ADDR_SIZE; i++) {
+		u8 h, l;
+		if (!*p)
+			break;
+		h = isdigit(*p) ? *p-'0' : *p-'A'+10;
+		p++;
+		l = isdigit(*p) ? *p-'0' : *p-'A'+10;
+		p++;
+		sas_addr[i] = (h<<4) | l;
+	}
+}
+
+struct asd_ha_struct;
+struct asd_ascb;
+
+int  asd_read_ocm(struct asd_ha_struct *asd_ha);
+int  asd_read_flash(struct asd_ha_struct *asd_ha);
+
+int  asd_dev_found(struct domain_device *dev);
+void asd_dev_gone(struct domain_device *dev);
+
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
+
+int  asd_execute_task(struct sas_task *, int num, unsigned long gfp_flags);
+
+/* ---------- TMFs ---------- */
+int  asd_abort_task(struct sas_task *);
+int  asd_abort_task_set(struct domain_device *, u8 *lun);
+int  asd_clear_aca(struct domain_device *, u8 *lun);
+int  asd_clear_task_set(struct domain_device *, u8 *lun);
+int  asd_lu_reset(struct domain_device *, u8 *lun);
+int  asd_query_task(struct sas_task *);
+
+/* ---------- Adapter and Port management ---------- */
+int  asd_clear_nexus_port(struct sas_port *port);
+int  asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
+
+/* ---------- Phy Management ---------- */
+int  asd_control_phy(struct sas_phy *phy, enum phy_func func);
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_dev.c newtree/drivers/scsi/aic94xx/aic94xx_dev.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_dev.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_dev.c	2006-04-01 05:35:45.895488250 -0500
@@ -0,0 +1,350 @@
+/*
+ * Aic94xx SAS/SATA DDB management
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_dev.c#21 $
+ */
+
+#include "aic94xx.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_sas.h"
+
+#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
+					       (_ha)->hw_prof.max_ddbs)
+#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+
+static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
+{
+	unsigned long flags;
+	int ddb, i;
+
+	spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+	ddb = FIND_FREE_DDB(asd_ha);
+	if (ddb >= asd_ha->hw_prof.max_ddbs) {
+		ddb = -ENOMEM;
+		spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+		goto out;
+	}
+	SET_DDB(ddb, asd_ha);
+	spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
+	for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
+		asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
+out:
+	return ddb;
+}
+
+#define INIT_CONN_TAG   offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
+#define DEST_SAS_ADDR   offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
+#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
+#define DDB_TYPE        offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
+#define CONN_MASK       offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
+#define DDB_TARG_FLAGS  offsetof(struct asd_ddb_ssp_smp_target_port, flags)
+#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
+#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
+#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
+#define SISTER_DDB      offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
+#define MAX_CCONN       offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
+#define NUM_CTX         offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
+#define ATA_CMD_SCBPTR  offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
+#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
+#define NUM_SATA_TAGS   offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
+#define SATA_STATUS     offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
+#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
+#define ITNL_TIMEOUT    offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
+
+static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
+{
+	unsigned long flags;
+
+	if (!ddb || ddb >= 0xFFFF)
+		return;
+	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
+	spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+	CLEAR_DDB(ddb, asd_ha);
+	spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+}
+
+static inline void asd_set_ddb_type(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	int ddb = (int) (unsigned long) dev->lldd_dev;
+
+	if (dev->dev_type == SATA_PM_PORT)
+		asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
+	else if (dev->tproto)
+		asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
+	else
+		asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
+}
+
+static int asd_init_sata_tag_ddb(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	int ddb, i;
+
+	ddb = asd_get_ddb(asd_ha);
+	if (ddb < 0)
+		return ddb;
+
+	for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
+		asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+	asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+			       SISTER_DDB, ddb);
+	return 0;
+}
+
+static inline int asd_init_sata(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	int ddb = (int) (unsigned long) dev->lldd_dev;
+	u32 qdepth = 0;
+	int res = 0;
+
+	asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+	if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
+	    dev->sata_dev.identify_device &&
+	    dev->sata_dev.identify_device[10] != 0) {
+		u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
+		u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
+
+		if (w76 & 0x100) /* NCQ? */
+			qdepth = (w75 & 0x1F) + 1;
+		asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
+					(1<<qdepth)-1);
+		asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
+	}
+	if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
+	    dev->dev_type == SATA_PM_PORT) {
+		struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
+			dev->frame_rcvd;
+		asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
+	}
+	asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
+	if (qdepth > 0)
+		res = asd_init_sata_tag_ddb(dev);
+	return res;
+}
+
+static int asd_init_target_ddb(struct domain_device *dev)
+{
+	int ddb, i;
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	u8 flags = 0;
+
+	ddb = asd_get_ddb(asd_ha);
+	if (ddb < 0)
+		return ddb;
+
+	dev->lldd_dev = (void *) (unsigned long) ddb;
+
+	asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
+	asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
+	asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
+	for (i = 0; i < SAS_ADDR_SIZE; i++)
+		asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
+				       dev->sas_addr[i]);
+	asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
+	asd_set_ddb_type(dev);
+	asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
+	if (dev->port->oob_mode != SATA_OOB_MODE) {
+		flags |= OPEN_REQUIRED;
+		if ((dev->dev_type == SATA_DEV) ||
+		    (dev->tproto & SAS_PROTO_STP)) {
+			struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
+			if (rps_resp->frame_type == SMP_RESPONSE &&
+			    rps_resp->function == SMP_REPORT_PHY_SATA &&
+			    rps_resp->result == SMP_RESP_FUNC_ACC) {
+				if (rps_resp->rps.affil_valid)
+					flags |= STP_AFFIL_POL;
+				if (rps_resp->rps.affil_supp)
+					flags |= SUPPORTS_AFFIL;
+			}
+		} else {
+			flags |= CONCURRENT_CONN_SUPP;
+			if (!dev->parent &&
+			    (dev->dev_type == EDGE_DEV ||
+			     dev->dev_type == FANOUT_DEV))
+				asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+						       4);
+			else
+				asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+						       dev->pathways);
+			asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
+		}
+	}
+	if (dev->dev_type == SATA_PM)
+		flags |= SATA_MULTIPORT;
+	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
+
+	flags = 0;
+	if (dev->tproto & SAS_PROTO_STP)
+		flags |= STP_CL_POL_NO_TX;
+	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+
+	asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
+	asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
+	asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+
+	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+		i = asd_init_sata(dev);
+		if (i < 0) {
+			asd_free_ddb(asd_ha, ddb);
+			return i;
+		}
+	}
+
+	if (dev->dev_type == SAS_END_DEV && dev->end_dev.itnl_timeout > 0)
+		asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+				       min(dev->end_dev.itnl_timeout,
+					   (u16)ITNL_TIMEOUT_CONST));
+	else
+		asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+				       (u16)ITNL_TIMEOUT_CONST);
+	return 0;
+}
+
+static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	int ddb, i;
+
+	ddb = asd_get_ddb(asd_ha);
+	if (ddb < 0)
+		return ddb;
+
+	for (i = 0; i < 32; i += 2)
+		asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+	asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+			       SISTER_DDB, ddb);
+
+	return 0;
+}
+
+#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
+#define PARENT_DDB    offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
+
+/**
+ * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
+ * dev: pointer to domain device
+ *
+ * For SATA Port Multiplier Ports we need to allocate one SATA Port
+ * Multiplier Port DDB and depending on whether the target on it
+ * supports SATA II NCQ, one SATA Tag DDB.
+ */
+static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
+{
+	int ddb, i, parent_ddb, pmtable_ddb;
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	u8  flags;
+
+	ddb = asd_get_ddb(asd_ha);
+	if (ddb < 0)
+		return ddb;
+
+	asd_set_ddb_type(dev);
+	flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
+	asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
+	asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+	asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+	asd_init_sata(dev);
+
+	parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
+	asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
+	pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
+	asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
+
+	if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
+		i = asd_init_sata_tag_ddb(dev);
+		if (i < 0) {
+			asd_free_ddb(asd_ha, ddb);
+			return i;
+		}
+	}
+	return 0;
+}
+
+static int asd_init_initiator_ddb(struct domain_device *dev)
+{
+	return -ENODEV;
+}
+
+/**
+ * asd_init_sata_pm_ddb -- SATA Port Multiplier
+ * dev: pointer to domain device
+ *
+ * For STP and direct-attached SATA Port Multipliers we need
+ * one target port DDB entry and one SATA PM table DDB entry.
+ */
+static int asd_init_sata_pm_ddb(struct domain_device *dev)
+{
+	int res = 0;
+
+	res = asd_init_target_ddb(dev);
+	if (res)
+		goto out;
+	res = asd_init_sata_pm_table_ddb(dev);
+	if (res)
+		asd_free_ddb(dev->port->ha->lldd_ha,
+			     (int) (unsigned long) dev->lldd_dev);
+out:
+	return res;
+}
+
+int asd_dev_found(struct domain_device *dev)
+{
+	int res = 0;
+
+	switch (dev->dev_type) {
+	case SATA_PM:
+		res = asd_init_sata_pm_ddb(dev);
+		break;
+	case SATA_PM_PORT:
+		res = asd_init_sata_pm_port_ddb(dev);
+		break;
+	default:
+		if (dev->tproto)
+			res = asd_init_target_ddb(dev);
+		else
+			res = asd_init_initiator_ddb(dev);
+	}
+	return res;
+}
+
+void asd_dev_gone(struct domain_device *dev)
+{
+	int ddb, sister_ddb;
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+
+	ddb = (int) (unsigned long) dev->lldd_dev;
+	sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
+
+	if (sister_ddb != 0xFFFF)
+		asd_free_ddb(asd_ha, sister_ddb);
+	asd_free_ddb(asd_ha, ddb);
+	dev->lldd_dev = NULL;
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_dump.c newtree/drivers/scsi/aic94xx/aic94xx_dump.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_dump.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_dump.c	2006-04-01 05:35:45.895488250 -0500
@@ -0,0 +1,959 @@
+/*
+ * Aic94xx SAS/SATA driver dump interface.
+ *
+ * Copyright (C) 2004 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * 2005/07/14/LT  Complete overhaul of this file.  Update pages, register
+ * locations, names, etc.  Make use of macros.  Print more information.
+ * Print all cseq and lseq mip and mdp.
+ *
+ * $Id: //depot/aic94xx/aic94xx_dump.c#29 $
+ */
+
+#include "linux/pci.h"
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_reg_def.h"
+#include "aic94xx_sas.h"
+
+#include "aic94xx_dump.h"
+
+#ifdef ASD_DEBUG
+
+#define MD(x)	    (1 << (x))
+#define MODE_COMMON (1 << 31)
+#define MODE_0_7    (0xFF)
+
+static const struct lseq_cio_regs {
+	char	*name;
+	u32	offs;
+	u8	width;
+	u32	mode;
+} LSEQmCIOREGS[] = {
+	{"LmMnSCBPTR",    0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+	{"LmMnDDBPTR",    0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+	{"LmREQMBX",      0x30, 32, MODE_COMMON },
+	{"LmRSPMBX",      0x34, 32, MODE_COMMON },
+	{"LmMnINT",       0x38, 32, MODE_0_7 },
+	{"LmMnINTEN",     0x3C, 32, MODE_0_7 },
+	{"LmXMTPRIMD",    0x40, 32, MODE_COMMON },
+	{"LmXMTPRIMCS",   0x44,  8, MODE_COMMON },
+	{"LmCONSTAT",     0x45,  8, MODE_COMMON },
+	{"LmMnDMAERRS",   0x46,  8, MD(0)|MD(1) },
+	{"LmMnSGDMAERRS", 0x47,  8, MD(0)|MD(1) },
+	{"LmMnEXPHDRP",   0x48,  8, MD(0) },
+	{"LmMnSASAALIGN", 0x48,  8, MD(1) },
+	{"LmMnMSKHDRP",   0x49,  8, MD(0) },
+	{"LmMnSTPALIGN",  0x49,  8, MD(1) },
+	{"LmMnRCVHDRP",   0x4A,  8, MD(0) },
+	{"LmMnXMTHDRP",   0x4A,  8, MD(1) },
+	{"LmALIGNMODE",   0x4B,  8, MD(1) },
+	{"LmMnEXPRCVCNT", 0x4C, 32, MD(0) },
+	{"LmMnXMTCNT",    0x4C, 32, MD(1) },
+	{"LmMnCURRTAG",   0x54, 16, MD(0) },
+	{"LmMnPREVTAG",   0x56, 16, MD(0) },
+	{"LmMnACKOFS",    0x58,  8, MD(1) },
+	{"LmMnXFRLVL",    0x59,  8, MD(0)|MD(1) },
+	{"LmMnSGDMACTL",  0x5A,  8, MD(0)|MD(1) },
+	{"LmMnSGDMASTAT", 0x5B,  8, MD(0)|MD(1) },
+	{"LmMnDDMACTL",   0x5C,  8, MD(0)|MD(1) },
+	{"LmMnDDMASTAT",  0x5D,  8, MD(0)|MD(1) },
+	{"LmMnDDMAMODE",  0x5E, 16, MD(0)|MD(1) },
+	{"LmMnPIPECTL",   0x61,  8, MD(0)|MD(1) },
+	{"LmMnACTSCB",    0x62, 16, MD(0)|MD(1) },
+	{"LmMnSGBHADR",   0x64,  8, MD(0)|MD(1) },
+	{"LmMnSGBADR",    0x65,  8, MD(0)|MD(1) },
+	{"LmMnSGDCNT",    0x66,  8, MD(0)|MD(1) },
+	{"LmMnSGDMADR",   0x68, 32, MD(0)|MD(1) },
+	{"LmMnSGDMADR",   0x6C, 32, MD(0)|MD(1) },
+	{"LmMnXFRCNT",    0x70, 32, MD(0)|MD(1) },
+	{"LmMnXMTCRC",    0x74, 32, MD(1) },
+	{"LmCURRTAG",     0x74, 16, MD(0) },
+	{"LmPREVTAG",     0x76, 16, MD(0) },
+	{"LmMnDPSEL",     0x7B,  8, MD(0)|MD(1) },
+	{"LmDPTHSTAT",    0x7C,  8, MODE_COMMON },
+	{"LmMnHOLDLVL",   0x7D,  8, MD(0) },
+	{"LmMnSATAFS",    0x7E,  8, MD(1) },
+	{"LmMnCMPLTSTAT", 0x7F,  8, MD(0)|MD(1) },
+	{"LmPRMSTAT0",    0x80, 32, MODE_COMMON },
+	{"LmPRMSTAT1",    0x84, 32, MODE_COMMON },
+	{"LmGPRMINT",     0x88,  8, MODE_COMMON },
+        {"LmMnCURRSCB",   0x8A, 16, MD(0) },
+	{"LmPRMICODE",    0x8C, 32, MODE_COMMON },
+	{"LmMnRCVCNT",    0x90, 16, MD(0) },
+	{"LmMnBUFSTAT",   0x92, 16, MD(0) },
+	{"LmMnXMTHDRSIZE",0x92,  8, MD(1) },
+	{"LmMnXMTSIZE",   0x93,  8, MD(1) },
+	{"LmMnTGTXFRCNT", 0x94, 32, MD(0) },
+	{"LmMnEXPROFS",   0x98, 32, MD(0) },
+	{"LmMnXMTROFS",   0x98, 32, MD(1) },
+	{"LmMnRCVROFS",   0x9C, 32, MD(0) },
+	{"LmCONCTL",      0xA0, 16, MODE_COMMON },
+	{"LmBITLTIMER",   0xA2, 16, MODE_COMMON },
+	{"LmWWNLOW",      0xA8, 32, MODE_COMMON },
+	{"LmWWNHIGH",     0xAC, 32, MODE_COMMON },
+	{"LmMnFRMERR",    0xB0, 32, MD(0) },
+	{"LmMnFRMERREN",  0xB4, 32, MD(0) },
+	{"LmAWTIMER",     0xB8, 16, MODE_COMMON },
+	{"LmAWTCTL",      0xBA,  8, MODE_COMMON },
+	{"LmMnHDRCMPS",   0xC0, 32, MD(0) },
+	{"LmMnXMTSTAT",   0xC4,  8, MD(1) },
+	{"LmHWTSTATEN",   0xC5,  8, MODE_COMMON },
+	{"LmMnRRDYRC",    0xC6,  8, MD(0) },
+        {"LmMnRRDYTC",    0xC6,  8, MD(1) },
+	{"LmHWTSTAT",     0xC7,  8, MODE_COMMON },
+	{"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) },
+	{"LmDWSSTATUS",   0xCB,  8, MODE_COMMON },
+	{"LmMnACTSTAT",   0xCE, 16, MD(0)|MD(1) },
+	{"LmMnREQSCB",    0xD2, 16, MD(0)|MD(1) },
+	{"LmXXXPRIM",     0xD4, 32, MODE_COMMON },
+	{"LmRCVASTAT",    0xD9,  8, MODE_COMMON },
+	{"LmINTDIS1",     0xDA,  8, MODE_COMMON },
+	{"LmPSTORESEL",   0xDB,  8, MODE_COMMON },
+	{"LmPSTORE",      0xDC, 32, MODE_COMMON },
+	{"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON },
+	{"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON },
+	{"LmDONETCTL",    0xF2, 16, MODE_COMMON },
+	{NULL, 0, 0, 0 }
+};
+/*
+static struct lseq_cio_regs LSEQmOOBREGS[] = {
+   {"OOB_BFLTR"        ,0x100, 8, MD(5)},
+   {"OOB_INIT_MIN"     ,0x102,16, MD(5)},
+   {"OOB_INIT_MAX"     ,0x104,16, MD(5)},
+   {"OOB_INIT_NEG"     ,0x106,16, MD(5)},
+   {"OOB_SAS_MIN"      ,0x108,16, MD(5)},
+   {"OOB_SAS_MAX"      ,0x10A,16, MD(5)},
+   {"OOB_SAS_NEG"      ,0x10C,16, MD(5)},
+   {"OOB_WAKE_MIN"     ,0x10E,16, MD(5)},
+   {"OOB_WAKE_MAX"     ,0x110,16, MD(5)},
+   {"OOB_WAKE_NEG"     ,0x112,16, MD(5)},
+   {"OOB_IDLE_MAX"     ,0x114,16, MD(5)},
+   {"OOB_BURST_MAX"    ,0x116,16, MD(5)},
+   {"OOB_XMIT_BURST"   ,0x118, 8, MD(5)},
+   {"OOB_SEND_PAIRS"   ,0x119, 8, MD(5)},
+   {"OOB_INIT_IDLE"    ,0x11A, 8, MD(5)},
+   {"OOB_INIT_NEGO"    ,0x11C, 8, MD(5)},
+   {"OOB_SAS_IDLE"     ,0x11E, 8, MD(5)},
+   {"OOB_SAS_NEGO"     ,0x120, 8, MD(5)},
+   {"OOB_WAKE_IDLE"    ,0x122, 8, MD(5)},
+   {"OOB_WAKE_NEGO"    ,0x124, 8, MD(5)},
+   {"OOB_DATA_KBITS"   ,0x126, 8, MD(5)},
+   {"OOB_BURST_DATA"   ,0x128,32, MD(5)},
+   {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)},
+   {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)},
+   {"OOB_SYNC_DATA"    ,0x134,32, MD(5)},
+   {"OOB_D10_2_DATA"   ,0x138,32, MD(5)},
+   {"OOB_PHY_RST_CNT"  ,0x13C,32, MD(5)},
+   {"OOB_SIG_GEN"      ,0x140, 8, MD(5)},
+   {"OOB_XMIT"         ,0x141, 8, MD(5)},
+   {"FUNCTION_MAKS"    ,0x142, 8, MD(5)},
+   {"OOB_MODE"         ,0x143, 8, MD(5)},
+   {"CURRENT_STATUS"   ,0x144, 8, MD(5)},
+   {"SPEED_MASK"       ,0x145, 8, MD(5)},
+   {"PRIM_COUNT"       ,0x146, 8, MD(5)},
+   {"OOB_SIGNALS"      ,0x148, 8, MD(5)},
+   {"OOB_DATA_DET"     ,0x149, 8, MD(5)},
+   {"OOB_TIME_OUT"     ,0x14C, 8, MD(5)},
+   {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)},
+   {"OOB_STATUS"       ,0x14E, 8, MD(5)},
+   {"HOT_PLUG_DELAY"   ,0x150, 8, MD(5)},
+   {"RCD_DELAY"        ,0x151, 8, MD(5)},
+   {"COMSAS_TIMER"     ,0x152, 8, MD(5)},
+   {"SNTT_DELAY"       ,0x153, 8, MD(5)},
+   {"SPD_CHNG_DELAY"   ,0x154, 8, MD(5)},
+   {"SNLT_DELAY"       ,0x155, 8, MD(5)},
+   {"SNWT_DELAY"       ,0x156, 8, MD(5)},
+   {"ALIGN_DELAY"      ,0x157, 8, MD(5)},
+   {"INT_ENABLE_0"     ,0x158, 8, MD(5)},
+   {"INT_ENABLE_1"     ,0x159, 8, MD(5)},
+   {"INT_ENABLE_2"     ,0x15A, 8, MD(5)},
+   {"INT_ENABLE_3"     ,0x15B, 8, MD(5)},
+   {"OOB_TEST_REG"     ,0x15C, 8, MD(5)},
+   {"PHY_CONTROL_0"    ,0x160, 8, MD(5)},
+   {"PHY_CONTROL_1"    ,0x161, 8, MD(5)},
+   {"PHY_CONTROL_2"    ,0x162, 8, MD(5)},
+   {"PHY_CONTROL_3"    ,0x163, 8, MD(5)},
+   {"PHY_OOB_CAL_TX"   ,0x164, 8, MD(5)},
+   {"PHY_OOB_CAL_RX"   ,0x165, 8, MD(5)},
+   {"OOB_PHY_CAL_TX"   ,0x166, 8, MD(5)},
+   {"OOB_PHY_CAL_RX"   ,0x167, 8, MD(5)},
+   {"PHY_CONTROL_4"    ,0x168, 8, MD(5)},
+   {"PHY_TEST"         ,0x169, 8, MD(5)},
+   {"PHY_PWR_CTL"      ,0x16A, 8, MD(5)},
+   {"PHY_PWR_DELAY"    ,0x16B, 8, MD(5)},
+   {"OOB_SM_CON"       ,0x16C, 8, MD(5)},
+   {"ADDR_TRAP_1"      ,0x16D, 8, MD(5)},
+   {"ADDR_NEXT_1"      ,0x16E, 8, MD(5)},
+   {"NEXT_ST_1"        ,0x16F, 8, MD(5)},
+   {"OOB_SM_STATE"     ,0x170, 8, MD(5)},
+   {"ADDR_TRAP_2"      ,0x171, 8, MD(5)},
+   {"ADDR_NEXT_2"      ,0x172, 8, MD(5)},
+   {"NEXT_ST_2"        ,0x173, 8, MD(5)},
+   {NULL, 0, 0, 0 }
+};
+*/
+#define STR_8BIT   "   %30s[0x%04x]:0x%02x\n"
+#define STR_16BIT  "   %30s[0x%04x]:0x%04x\n"
+#define STR_32BIT  "   %30s[0x%04x]:0x%08x\n"
+#define STR_64BIT  "   %30s[0x%04x]:0x%016Lx\n"
+
+#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n,      \
+					     asd_read_reg_byte(_ha, _r))
+#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n,     \
+					      asd_read_reg_word(_ha, _r))
+#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n,      \
+					      asd_read_reg_dword(_ha, _r))
+
+#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n,      \
+					     asd_read_reg_byte(_ha, C##_n))
+#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n,     \
+					      asd_read_reg_word(_ha, C##_n))
+#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n,      \
+					      asd_read_reg_dword(_ha, C##_n))
+
+#define MSTR_8BIT   "   Mode:%02d %30s[0x%04x]:0x%02x\n"
+#define MSTR_16BIT  "   Mode:%02d %30s[0x%04x]:0x%04x\n"
+#define MSTR_32BIT  "   Mode:%02d %30s[0x%04x]:0x%08x\n"
+
+#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n,   \
+					     asd_read_reg_byte(_ha, _r))
+#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \
+					      asd_read_reg_word(_ha, _r))
+#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \
+					      asd_read_reg_dword(_ha, _r))
+
+/* can also be used for MD when the register is mode aware already */
+#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\
+                                           asd_read_reg_byte(_ha, CSEQ_##_n))
+#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+                                           asd_read_reg_word(_ha, CSEQ_##_n))
+#define PRINT_MIS_dword(_ha, _n)                      \
+        asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+                   asd_read_reg_dword(_ha, CSEQ_##_n))
+#define PRINT_MIS_qword(_ha, _n)                                       \
+        asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR,                \
+                   (u64)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n))     \
+                 | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32)))
+
+#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n)
+#define PRINT_CMDP_word(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+	#_n, \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \
+	asd_read_reg_word(_ha, CMDP_REG(_n, 7)))
+
+#define PRINT_CMDP_byte(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+	#_n, \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \
+	asd_read_reg_byte(_ha, CMDP_REG(_n, 7)))
+
+static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha)
+{
+	int mode;
+
+	asd_printk("CSEQ STATE\n");
+
+	asd_printk("ARP2 REGISTERS\n");
+
+	PRINT_CREG_32bit(asd_ha, ARP2CTL);
+	PRINT_CREG_32bit(asd_ha, ARP2INT);
+	PRINT_CREG_32bit(asd_ha, ARP2INTEN);
+	PRINT_CREG_8bit(asd_ha, MODEPTR);
+	PRINT_CREG_8bit(asd_ha, ALTMODE);
+	PRINT_CREG_8bit(asd_ha, FLAG);
+	PRINT_CREG_8bit(asd_ha, ARP2INTCTL);
+	PRINT_CREG_16bit(asd_ha, STACK);
+	PRINT_CREG_16bit(asd_ha, PRGMCNT);
+	PRINT_CREG_16bit(asd_ha, ACCUM);
+	PRINT_CREG_16bit(asd_ha, SINDEX);
+	PRINT_CREG_16bit(asd_ha, DINDEX);
+	PRINT_CREG_8bit(asd_ha, SINDIR);
+	PRINT_CREG_8bit(asd_ha, DINDIR);
+	PRINT_CREG_8bit(asd_ha, JUMLDIR);
+	PRINT_CREG_8bit(asd_ha, ARP2HALTCODE);
+	PRINT_CREG_16bit(asd_ha, CURRADDR);
+	PRINT_CREG_16bit(asd_ha, LASTADDR);
+	PRINT_CREG_16bit(asd_ha, NXTLADDR);
+
+	asd_printk("IOP REGISTERS\n");
+
+	PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL);
+	PRINT_CREG_32bit(asd_ha, MAPPEDSCR);
+
+	asd_printk("CIO REGISTERS\n");
+
+	for (mode = 0; mode < 9; mode++)
+		PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode));
+	PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15));
+
+	for (mode = 0; mode < 9; mode++)
+		PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode));
+	PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15));
+
+	for (mode = 0; mode < 8; mode++)
+		PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode));
+	for (mode = 0; mode < 8; mode++)
+		PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode));
+	for (mode = 0; mode < 8; mode++)
+		PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode));
+	for (mode = 0; mode < 8; mode++)
+		PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode));
+
+	PRINT_CREG_8bit(asd_ha, SCRATCHPAGE);
+	for (mode = 0; mode < 8; mode++)
+		PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE,
+				CMnSCRATCHPAGE(mode));
+
+	PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON);
+	PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK);
+	PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST);
+	PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE);
+	PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC);
+	PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS);
+
+	asd_printk("SCRATCH MEMORY\n");
+
+	asd_printk("MIP 4 >>>>>\n");
+	PRINT_MIS_word(asd_ha, Q_EXE_HEAD);
+	PRINT_MIS_word(asd_ha, Q_EXE_TAIL);
+	PRINT_MIS_word(asd_ha, Q_DONE_HEAD);
+	PRINT_MIS_word(asd_ha, Q_DONE_TAIL);
+	PRINT_MIS_word(asd_ha, Q_SEND_HEAD);
+	PRINT_MIS_word(asd_ha, Q_SEND_TAIL);
+	PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD);
+	PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL);
+	PRINT_MIS_word(asd_ha, Q_COPY_HEAD);
+	PRINT_MIS_word(asd_ha, Q_COPY_TAIL);
+	PRINT_MIS_word(asd_ha, REG0);
+	PRINT_MIS_word(asd_ha, REG1);
+	PRINT_MIS_dword(asd_ha, REG2);
+	PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP);
+	PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE);
+	PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT);
+
+	asd_printk("MIP 5 >>>>\n");
+	PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE);
+	PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT);
+	PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD);
+	PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL);
+	PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB);
+	PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD);
+	PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL);
+	PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET);
+
+	asd_printk("MIP 6 >>>>\n");
+	PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0);
+	PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1);
+	PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR);
+	PRINT_MIS_byte(asd_ha, INT_ROUT_MODE);
+	PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS);
+	PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX);
+	PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX);
+	PRINT_MIS_word(asd_ha, SLS_SAVE_ACCUM);
+	PRINT_MIS_word(asd_ha, SLS_SAVE_SINDEX);
+	PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD);
+	PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL);
+	PRINT_MIS_byte(asd_ha, FREE_SCB_MASK);
+	PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD);
+	PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL);
+	PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD);
+	PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL);
+
+	asd_printk("MIP 7 >>>>\n");
+	PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE);
+	PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT);
+	PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD);
+	PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL);
+	PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB);
+	PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD);
+	PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL);
+	PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET);
+	PRINT_MIS_word(asd_ha, PRIMITIVE_DATA);
+	PRINT_MIS_dword(asd_ha, TIMEOUT_CONST);
+
+	asd_printk("MDP 0 >>>>\n");
+	asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+		   "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7");
+	PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX);
+	PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR);
+	PRINT_CMDP_word(asd_ha, Q_LINK_HEAD);
+	PRINT_CMDP_word(asd_ha, Q_LINK_TAIL);
+	PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE);
+
+	asd_printk("MDP 0 Mode 8 >>>>\n");
+	PRINT_MIS_word(asd_ha, RET_ADDR);
+	PRINT_MIS_word(asd_ha, RET_SCBPTR);
+	PRINT_MIS_word(asd_ha, SAVE_SCBPTR);
+	PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX);
+	PRINT_MIS_word(asd_ha, RESP_LEN);
+	PRINT_MIS_word(asd_ha, TMF_SCBPTR);
+	PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB);
+	PRINT_MIS_word(asd_ha, GLOBAL_HEAD);
+	PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD);
+	PRINT_MIS_byte(asd_ha, TMF_OPCODE);
+	PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS);
+	PRINT_MIS_word(asd_ha, HSB_SITE);
+	PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE);
+	PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE);
+
+	asd_printk("MDP 1 Mode 8 >>>>\n");
+	PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR);
+	PRINT_MIS_qword(asd_ha, LUN_TO_CHECK);
+
+	asd_printk("MDP 2 Mode 8 >>>>\n");
+	PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER);
+	PRINT_MIS_qword(asd_ha, HQ_DONE_BASE);
+	PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER);
+	PRINT_MIS_byte(asd_ha, HQ_DONE_PASS);
+}
+
+#define PRINT_LREG_8bit(_h, _lseq, _n) \
+        asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_16bit(_h, _lseq, _n) \
+        asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_32bit(_h, _lseq, _n) \
+        asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq)))
+
+#define PRINT_LMIP_byte(_h, _lseq, _n)                              \
+	asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+		   asd_read_reg_byte(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_word(_h, _lseq, _n)                              \
+	asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+		   asd_read_reg_word(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_dword(_h, _lseq, _n)                             \
+	asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+		   asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_qword(_h, _lseq, _n)                                \
+	asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+		   (u64)(((u64)asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))\
+	          | (((u64)asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32)))
+
+static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha,
+				   u32 lseq_cio_addr, int i)
+{
+	switch (LSEQmCIOREGS[i].width) {
+	case 8:
+		asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name,
+			   LSEQmCIOREGS[i].offs,
+			   asd_read_reg_byte(asd_ha, lseq_cio_addr +
+					     LSEQmCIOREGS[i].offs));
+
+		break;
+	case 16:
+		asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name,
+			   LSEQmCIOREGS[i].offs,
+			   asd_read_reg_word(asd_ha, lseq_cio_addr +
+					     LSEQmCIOREGS[i].offs));
+
+		break;
+	case 32:
+		asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name,
+			   LSEQmCIOREGS[i].offs,
+			   asd_read_reg_dword(asd_ha, lseq_cio_addr +
+					      LSEQmCIOREGS[i].offs));
+		break;
+	}
+}
+
+static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
+{
+	u32 moffs;
+	int mode;
+
+	asd_printk("LSEQ %d STATE\n", lseq);
+
+	asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq);
+	PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL);
+	PRINT_LREG_32bit(asd_ha, lseq, ARP2INT);
+	PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN);
+	PRINT_LREG_8bit(asd_ha, lseq, MODEPTR);
+	PRINT_LREG_8bit(asd_ha, lseq, ALTMODE);
+	PRINT_LREG_8bit(asd_ha, lseq, FLAG);
+	PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL);
+	PRINT_LREG_16bit(asd_ha, lseq, STACK);
+	PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT);
+	PRINT_LREG_16bit(asd_ha, lseq, ACCUM);
+	PRINT_LREG_16bit(asd_ha, lseq, SINDEX);
+	PRINT_LREG_16bit(asd_ha, lseq, DINDEX);
+	PRINT_LREG_8bit(asd_ha, lseq, SINDIR);
+	PRINT_LREG_8bit(asd_ha, lseq, DINDIR);
+	PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR);
+	PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE);
+	PRINT_LREG_16bit(asd_ha, lseq, CURRADDR);
+	PRINT_LREG_16bit(asd_ha, lseq, LASTADDR);
+	PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR);
+
+	asd_printk("LSEQ%d: IOP REGISTERS\n", lseq);
+
+	PRINT_LREG_32bit(asd_ha, lseq, MODECTL);
+	PRINT_LREG_32bit(asd_ha, lseq, DBGMODE);
+	PRINT_LREG_32bit(asd_ha, lseq, CONTROL);
+	PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq));
+	PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq));
+
+	asd_printk("LSEQ%d: CIO REGISTERS\n", lseq);
+	asd_printk("Mode common:\n");
+
+	for (mode = 0; mode < 8; mode++) {
+		u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+		int i;
+
+		for (i = 0; LSEQmCIOREGS[i].name; i++)
+			if (LSEQmCIOREGS[i].mode == MODE_COMMON)
+				asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i);
+	}
+
+	asd_printk("Mode unique:\n");
+	for (mode = 0; mode < 8; mode++) {
+		u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+		int i;
+
+		asd_printk("Mode %d\n", mode);
+		for  (i = 0; LSEQmCIOREGS[i].name; i++) {
+			if (!(LSEQmCIOREGS[i].mode & (1 << mode)))
+				continue;
+			asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i);
+		}
+	}
+
+	asd_printk("SCRATCH MEMORY\n");
+
+	asd_printk("LSEQ%d MIP 0 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD);
+	PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
+	PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
+	PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
+	PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
+	PRINT_LMIP_word(asd_ha, lseq, CONCTL);
+	PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
+	PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
+	PRINT_LMIP_word(asd_ha, lseq, REG1_ISR);
+	PRINT_LMIP_word(asd_ha, lseq, REG2_ISR);
+	PRINT_LMIP_word(asd_ha, lseq, REG3_ISR);
+	PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR);
+
+	asd_printk("LSEQ%d MIP 1 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0);
+	PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1);
+	PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2);
+	PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL);
+	PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL);
+	PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST);
+	PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX);
+	PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX);
+
+	asd_printk("LSEQ%d MIP 2 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0);
+	PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1);
+	PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2);
+	PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL);
+	PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL);
+
+	asd_printk("LSEQ%d MIP 3 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST);
+	PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT);
+	PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT);
+	PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT);
+	PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT);
+	PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT);
+	PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT);
+
+	for (mode = 0; mode < 3; mode++) {
+		asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode);
+		moffs = mode * LSEQ_MODE_SCRATCH_SIZE;
+
+		asd_printk(STR_16BIT, "RET_ADDR", 0,
+			   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)
+					     + moffs));
+		asd_printk(STR_16BIT, "REG0_MODE", 2,
+			   asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)
+					     + moffs));
+		asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+			   asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)
+					     + moffs));
+		asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+			   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)
+					     + moffs));
+		asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+			   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)
+					     + moffs));
+		asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+			   asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)
+					     + moffs));
+		asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+			   asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)
+					     + moffs));
+	}
+
+	asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq);
+	moffs = LSEQ_MODE5_PAGE0_OFFSET;
+	asd_printk(STR_16BIT, "RET_ADDR", 0,
+		   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs));
+	asd_printk(STR_16BIT, "REG0_MODE", 2,
+		   asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs));
+	asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+		   asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs));
+	asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+		   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs));
+	asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+		   asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs));
+	asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+	   asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs));
+	asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+	   asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs));
+
+	asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE);
+	PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX);
+	PRINT_LMIP_word(asd_ha, lseq, RESP_LEN);
+	PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE);
+	PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE);
+	PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN);
+	PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL);
+	PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS);
+	PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE);
+	PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR);
+
+	asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD);
+	PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX);
+	PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG);
+	PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS);
+	PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE);
+	PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS);
+	PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE);
+	PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR);
+
+	asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq);
+	PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER);
+	PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR);
+	PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE);
+	PRINT_LMIP_word(asd_ha, lseq, IP_BITL);
+	PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG);
+	PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH);
+
+	asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq);
+	PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS);
+	PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE);
+	PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD);
+	PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR);
+	PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS);
+	PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE);
+	PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT);
+	PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES);
+	PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES);
+	PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT);
+	PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT);
+
+	asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq);
+	PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0);
+	PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1);
+
+	asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq);
+	PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0);
+	PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1);
+
+	asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT);
+	PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT);
+	PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT);
+
+	asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK);
+	PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT);
+	PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK);
+	PRINT_LMIP_word(asd_ha, lseq, TAG_MASK);
+	PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG);
+	PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET);
+
+	asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS);
+	PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS);
+	PRINT_LMIP_word(asd_ha, lseq, SDB_DDB);
+	PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS);
+	PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG);
+
+	asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq);
+	PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME);
+	PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL);
+
+	asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS);
+
+	asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq);
+	PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS);
+	PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS);
+}
+
+/**
+ * asd_dump_ddb_site -- dump a CSEQ DDB site
+ * @asd_ha: pointer to host adapter structure
+ * @site_no: site number of interest
+ */
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+	if (site_no >= asd_ha->hw_prof.max_ddbs)
+		return;
+
+#define DDB_FIELDB(__name)                                        \
+	asd_ddbsite_read_byte(asd_ha, site_no,                    \
+			      offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+#define DDB2_FIELDB(__name)                                       \
+	asd_ddbsite_read_byte(asd_ha, site_no,                    \
+			      offsetof(struct asd_ddb_stp_sata_target_port, __name))
+#define DDB_FIELDW(__name)                                        \
+	asd_ddbsite_read_word(asd_ha, site_no,                    \
+			      offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+#define DDB_FIELDD(__name)                                         \
+	asd_ddbsite_read_dword(asd_ha, site_no,                    \
+			       offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+	asd_printk("DDB: 0x%02x\n", site_no);
+	asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type));
+	asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate));
+	asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag)));
+	asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head)));
+	asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended));
+	asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type));
+	asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def));
+	asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features));
+	asd_printk("Pathway Blocked Count: 0x%02x\n",
+		   DDB_FIELDB(pathway_blocked_count));
+	asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time));
+	asd_printk("more_compat_features: 0x%08x\n",
+		   DDB_FIELDD(more_compat_features));
+	asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask));
+	asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags));
+	asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2));
+	asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail));
+	asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail));
+	asd_printk("Active Task Count: 0x%04x\n",
+		   DDB_FIELDW(active_task_count));
+	asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason));
+	asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout));
+	asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp));
+}
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha)
+{
+#define DDB0_FIELDB(__name)                                  \
+	asd_ddbsite_read_byte(asd_ha, 0,                     \
+			      offsetof(struct asd_ddb_seq_shared, __name))
+#define DDB0_FIELDW(__name)                                  \
+	asd_ddbsite_read_word(asd_ha, 0,                     \
+			      offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDD(__name)                                  \
+	asd_ddbsite_read_dword(asd_ha,0 ,                    \
+			       offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDA(__name, _o)                              \
+	asd_ddbsite_read_byte(asd_ha, 0,                     \
+			      offsetof(struct asd_ddb_seq_shared, __name)+_o)
+
+
+	asd_printk("DDB: 0\n");
+	asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head));
+	asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail));
+	asd_printk("q_free_ddb_cnt:%04x\n",  DDB0_FIELDW(q_free_ddb_cnt));
+	asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head));
+	asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail));
+	asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock));
+	asd_printk("smp_conn_tag:%04x\n",    DDB0_FIELDW(smp_conn_tag));
+	asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt));
+	asd_printk("est_nexus_buf_thresh:%04x\n",
+		   DDB0_FIELDW(est_nexus_buf_thresh));
+	asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active));
+	asd_printk("phy_is_up:%02x\n",       DDB0_FIELDB(phy_is_up));
+	asd_printk("port_map_by_links:%02x %02x %02x %02x "
+		   "%02x %02x %02x %02x\n",
+		   DDB0_FIELDA(port_map_by_links, 0),
+		   DDB0_FIELDA(port_map_by_links, 1),
+		   DDB0_FIELDA(port_map_by_links, 2),
+		   DDB0_FIELDA(port_map_by_links, 3),
+		   DDB0_FIELDA(port_map_by_links, 4),
+		   DDB0_FIELDA(port_map_by_links, 5),
+		   DDB0_FIELDA(port_map_by_links, 6),
+		   DDB0_FIELDA(port_map_by_links, 7));
+}
+
+static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+
+#define SCB_FIELDB(__name)                                                 \
+	asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header)   \
+			      + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDW(__name)                                                 \
+	asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header)   \
+			      + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDD(__name)                                                 \
+	asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header)  \
+			       + offsetof(struct initiate_ssp_task, __name))
+
+	asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len));
+	asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type));
+	asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag));
+	asd_printk("Target Port Xfer Tag: 0x%04x.\n",
+		   SCB_FIELDW(ssp_frame.tptt));
+	asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs));
+	asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count));
+}
+
+/**
+ * asd_dump_scb_sites -- dump currently used CSEQ SCB sites
+ * @asd_ha: pointer to host adapter struct
+ */
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha)
+{
+	u16	site_no;
+
+	for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) {
+		u8 opcode;
+
+		if (!SCB_SITE_VALID(site_no))
+			continue;
+
+		/* We are only interested in SCB sites currently used.
+		 */
+		opcode = asd_scbsite_read_byte(asd_ha, site_no,
+					       offsetof(struct scb_header,
+							opcode));
+		if (opcode == 0xFF)
+			continue;
+
+		asd_printk("\nSCB: 0x%x\n", site_no);
+		asd_dump_scb_site(asd_ha, site_no);
+	}
+}
+
+/**
+ * ads_dump_seq_state -- dump CSEQ and LSEQ states
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of LSEQs of interest
+ */
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+	int lseq;
+
+	asd_dump_cseq_state(asd_ha);
+
+	if (lseq_mask != 0)
+		for_each_sequencer(lseq_mask, lseq_mask, lseq)
+			asd_dump_lseq_state(asd_ha, lseq);
+}
+
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+			 struct done_list_struct *dl)
+{
+	unsigned long flags;
+	int i;
+
+	switch ((dl->status_block[1] & 0x70) >> 3) {
+	case SAS_PROTO_STP:
+		ASD_DPRINTK("STP proto device-to-host FIS:\n");
+		break;
+	default:
+	case SAS_PROTO_SSP:
+		ASD_DPRINTK("SAS proto IDENTIFY:\n");
+		break;
+	}
+	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+	for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4)
+		ASD_DPRINTK("%02x: %02x %02x %02x %02x\n",
+			    i,
+			    phy->frame_rcvd[i],
+			    phy->frame_rcvd[i+1],
+			    phy->frame_rcvd[i+2],
+			    phy->frame_rcvd[i+3]);
+	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+}
+
+static inline void asd_dump_scb(struct asd_ascb *ascb, int ind)
+{
+	asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%08llx, next: 0x%08llx, "
+		   "index:%d, opcode:0x%02x\n",
+		   ind, ascb->dma_scb.vaddr,
+		   (u64)ascb->dma_scb.dma_handle,
+		   le64_to_cpu(ascb->scb->header.next_scb),
+		   le16_to_cpu(ascb->scb->header.index),
+		   ascb->scb->header.opcode);
+}
+
+void asd_dump_scb_list(struct asd_ascb *ascb, int num)
+{
+	int i = 0;
+
+	asd_printk("dumping %d scbs:\n", num);
+
+	asd_dump_scb(ascb, i++);
+	--num;
+
+	if (num > 0 && !list_empty(&ascb->list)) {
+		struct list_head *el;
+
+		list_for_each(el, &ascb->list) {
+			struct asd_ascb *s = list_entry(el, struct asd_ascb,
+							list);
+			asd_dump_scb(s, i++);
+			if (--num <= 0)
+				break;
+		}
+	}
+}
+
+#endif /* ASD_DEBUG */
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_dump.h newtree/drivers/scsi/aic94xx/aic94xx_dump.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_dump.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_dump.h	2006-04-01 05:35:45.899488500 -0500
@@ -0,0 +1,53 @@
+/*
+ * Aic94xx SAS/SATA driver dump header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_dump.h#10 $
+ */
+
+#ifndef _AIC94XX_DUMP_H_
+#define _AIC94XX_DUMP_H_
+
+#ifdef ASD_DEBUG
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+			 struct done_list_struct *dl);
+void asd_dump_scb_list(struct asd_ascb *ascb, int num);
+#else /* ASD_DEBUG */
+
+static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
+				     u16 site_no) { }
+static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
+				      u8 lseq_mask) { }
+static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
+				       struct done_list_struct *dl) { }
+static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
+#endif /* ASD_DEBUG */
+
+#endif /* _AIC94XX_DUMP_H_ */
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_hwi.c newtree/drivers/scsi/aic94xx/aic94xx_hwi.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_hwi.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_hwi.c	2006-04-01 05:35:45.899488500 -0500
@@ -0,0 +1,1364 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_hwi.c#107 $
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <scsi/sas/sas_task.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+u32 MBAR0_SWB_SIZE;
+
+/* ---------- Initialization ---------- */
+
+static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
+{
+	extern char sas_addr_str[];
+	/* If the user has specified a WWN it overrides other settings
+	 */
+	if (sas_addr_str[0] != '\0')
+		asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,
+					 sas_addr_str);
+	else if (asd_ha->hw_prof.sas_addr[0] != 0)
+		asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);
+}
+
+static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
+{
+	int i;
+
+	for (i = 0; i < ASD_MAX_PHYS; i++) {
+		if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
+			continue;
+		/* Set a phy's address only if it has none.
+		 */
+		ASD_DPRINTK("setting phy%d addr to %llx\n", i,
+			    SAS_ADDR(asd_ha->hw_prof.sas_addr));
+		memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
+		       asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+	}
+}
+
+/* ---------- PHY initialization ---------- */
+
+static void asd_init_phy_identify(struct asd_phy *phy)
+{
+	phy->identify_frame = phy->id_frm_tok->vaddr;
+
+	memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
+
+	phy->identify_frame->dev_type = SAS_END_DEV;
+	if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
+		phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
+	if (phy->sas_phy.role & PHY_ROLE_TARGET)
+		phy->identify_frame->target_bits = phy->sas_phy.tproto;
+	memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
+	       SAS_ADDR_SIZE);
+	phy->identify_frame->phy_id = phy->sas_phy.id;
+}
+
+static int asd_init_phy(struct asd_phy *phy)
+{
+	struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+	struct sas_phy *sas_phy = &phy->sas_phy;
+
+	sas_phy->enabled = 1;
+	sas_phy->class = SAS;
+	sas_phy->iproto = SAS_PROTO_ALL;
+	sas_phy->tproto = 0;
+	sas_phy->type = PHY_TYPE_PHYSICAL;
+	sas_phy->role = PHY_ROLE_INITIATOR;
+	sas_phy->oob_mode = OOB_NOT_CONNECTED;
+	sas_phy->linkrate = PHY_LINKRATE_NONE;
+
+	phy->id_frm_tok = asd_alloc_coherent(asd_ha,
+					     sizeof(*phy->identify_frame),
+					     GFP_KERNEL);
+	if (!phy->id_frm_tok) {
+		asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
+		return -ENOMEM;
+	} else
+		asd_init_phy_identify(phy);
+
+	memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
+
+	return 0;
+}
+
+static int asd_init_phys(struct asd_ha_struct *asd_ha)
+{
+	u8 i;
+	u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+
+	for (i = 0; i < ASD_MAX_PHYS; i++) {
+		struct asd_phy *phy = &asd_ha->phys[i];
+
+		phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
+
+		phy->sas_phy.enabled = 0;
+		phy->sas_phy.id = i;
+		phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
+		phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
+		phy->sas_phy.ha = &asd_ha->sas_ha;
+		phy->sas_phy.lldd_phy = phy;
+	}
+
+	/* Now enable and initialize only the enabled phys. */
+	for_each_phy(phy_mask, phy_mask, i) {
+		int err = asd_init_phy(&asd_ha->phys[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/* ---------- Sliding windows ---------- */
+
+static int asd_init_sw(struct asd_ha_struct *asd_ha)
+{
+	struct pci_dev *pcidev = asd_ha->pcidev;
+	int err;
+	u32 v;
+
+	/* Unlock MBARs */
+	err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
+	if (err) {
+		asd_printk("couldn't access conf. space of %s\n",
+			   pci_name(pcidev));
+		goto Err;
+	}
+	if (v)
+		err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
+	if (err) {
+		asd_printk("couldn't write to MBAR_KEY of %s\n",
+			   pci_name(pcidev));
+		goto Err;
+	}
+
+	/* Set sliding windows A, B and C to point to proper internal
+	 * memory regions.
+	 */
+	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
+	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
+			       REG_BASE_ADDR_CSEQCIO);
+	pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
+	asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
+	asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
+	asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
+	MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
+	if (!asd_ha->iospace) {
+		/* MBAR1 will point to OCM (On Chip Memory) */
+		pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
+		asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
+	}
+	spin_lock_init(&asd_ha->iolock);
+Err:
+	return err;
+}
+
+/* ---------- SCB initialization ---------- */
+
+/**
+ * asd_init_scbs - manually allocate the first SCB.
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This allocates the very first SCB which would be sent to the
+ * sequencer for execution.  Its bus address is written to
+ * CSEQ_Q_NEW_POINTER, mode page 2, mode 8.  Since the bus address of
+ * the _next_ scb to be DMA-ed to the host adapter is read from the last
+ * SCB DMA-ed to the host adapter, we have to always stay one step
+ * ahead of the sequencer and keep one SCB already allocated.
+ */
+static int asd_init_scbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int bitmap_bytes;
+
+	/* allocate the index array and bitmap */
+	asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
+	asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
+					     sizeof(void *), GFP_KERNEL);
+	if (!asd_ha->seq.tc_index_array)
+		return -ENOMEM;
+
+	bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
+	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+	asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+	if (!asd_ha->seq.tc_index_bitmap)
+		return -ENOMEM;
+
+	spin_lock_init(&seq->tc_index_lock);
+
+	seq->next_scb.size = sizeof(struct scb);
+	seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
+					     &seq->next_scb.dma_handle);
+	if (!seq->next_scb.vaddr) {
+		kfree(asd_ha->seq.tc_index_bitmap);
+		kfree(asd_ha->seq.tc_index_array);
+		asd_ha->seq.tc_index_bitmap = NULL;
+		asd_ha->seq.tc_index_array = NULL;
+		return -ENOMEM;
+	}
+
+	seq->pending = 0;
+	spin_lock_init(&seq->pend_q_lock);
+	INIT_LIST_HEAD(&seq->pend_q);
+
+	return 0;
+}
+
+static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
+{
+	asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
+	asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
+	ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
+		    asd_ha->hw_prof.max_scbs,
+		    asd_ha->hw_prof.max_ddbs);
+}
+
+/* ---------- Done List initialization ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long);
+
+static int asd_init_dl(struct asd_ha_struct *asd_ha)
+{
+	asd_ha->seq.actual_dl
+		= asd_alloc_coherent(asd_ha,
+			     ASD_DL_SIZE * sizeof(struct done_list_struct),
+				     GFP_KERNEL);
+	if (!asd_ha->seq.actual_dl)
+		return -ENOMEM;
+	asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
+	asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
+	asd_ha->seq.dl_next = 0;
+	tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
+		     (unsigned long) asd_ha);
+
+	return 0;
+}
+
+/* ---------- EDB and ESCB init ---------- */
+
+static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, unsigned int gfp_flags)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int i;
+
+	seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
+	if (!seq->edb_arr)
+		return -ENOMEM;
+
+	for (i = 0; i < seq->num_edbs; i++) {
+		seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
+						     gfp_flags);
+		if (!seq->edb_arr[i])
+			goto Err_unroll;
+		memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
+	}
+
+	ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
+
+	return 0;
+
+Err_unroll:
+	for (i-- ; i >= 0; i--)
+		asd_free_coherent(asd_ha, seq->edb_arr[i]);
+	kfree(seq->edb_arr);
+	seq->edb_arr = NULL;
+
+	return -ENOMEM;
+}
+
+static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
+			   unsigned int gfp_flags)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	struct asd_ascb *escb;
+	int i, escbs;
+
+	seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
+				gfp_flags);
+	if (!seq->escb_arr)
+		return -ENOMEM;
+
+	escbs = seq->num_escbs;
+	escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
+	if (!escb) {
+		asd_printk("couldn't allocate list of escbs\n");
+		goto Err;
+	}
+	seq->num_escbs -= escbs;  /* subtract what was not allocated */
+	ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
+
+	for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
+							       struct asd_ascb,
+							       list)) {
+		seq->escb_arr[i] = escb;
+		escb->scb->header.opcode = EMPTY_SCB;
+	}
+
+	return 0;
+Err:
+	kfree(seq->escb_arr);
+	seq->escb_arr = NULL;
+	return -ENOMEM;
+
+}
+
+static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int i, k, z = 0;
+
+	for (i = 0; i < seq->num_escbs; i++) {
+		struct asd_ascb *ascb = seq->escb_arr[i];
+		struct empty_scb *escb = &ascb->scb->escb;
+
+		ascb->edb_index = z;
+
+		escb->num_valid = ASD_EDBS_PER_SCB;
+
+		for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
+			struct sg_el *eb = &escb->eb[k];
+			struct asd_dma_tok *edb = seq->edb_arr[z++];
+
+			memset(eb, 0, sizeof(*eb));
+			eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
+			eb->size = cpu_to_le32(((u32) edb->size));
+		}
+	}
+}
+
+/**
+ * asd_init_escbs -- allocate and initialize empty scbs
+ * @asd_ha: pointer to host adapter structure
+ *
+ * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
+ * They transport sense data, etc.
+ */
+static int asd_init_escbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int err = 0;
+
+	/* Allocate two empty data buffers (edb) per sequencer. */
+	int edbs = 2*(1+asd_ha->hw_prof.num_phys);
+
+	seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
+	seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
+
+	err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
+	if (err) {
+		asd_printk("couldn't allocate edbs\n");
+		return err;
+	}
+
+	err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
+	if (err) {
+		asd_printk("couldn't allocate escbs\n");
+		return err;
+	}
+
+	asd_assign_edbs2escbs(asd_ha);
+	/* In order to insure that normal SCBs do not overfill sequencer
+	 * memory and leave no space for escbs (halting condition),
+	 * we increment pending here by the number of escbs.  However,
+	 * escbs are never pending.
+	 */
+	seq->pending   = seq->num_escbs;
+	seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
+
+	return 0;
+}
+
+/* ---------- HW initialization ---------- */
+
+/**
+ * asd_chip_hardrst -- hard reset the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This takes 16 cycles and is synchronous to CFCLK, which runs
+ * at 200 MHz, so this should take at most 80 nanoseconds.
+ */
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha)
+{
+	int i;
+	int count = 100;
+	u32 reg;
+
+	for (i = 0 ; i < 4 ; i++) {
+		asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
+	}
+
+	do {
+		udelay(1);
+		reg = asd_read_reg_dword(asd_ha, CHIMINT);
+		if (reg & HARDRSTDET) {
+			asd_write_reg_dword(asd_ha, CHIMINT,
+					    HARDRSTDET|PORRSTDET);
+			return 0;
+		}
+	} while (--count > 0);
+
+	return -ENODEV;
+}
+
+/**
+ * asd_init_chip -- initialize the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Hard resets the chip, disables HA interrupts, downloads the sequnecer
+ * microcode and starts the sequencers.  The caller has to explicitly
+ * enable HA interrupts with asd_enable_ints(asd_ha).
+ */
+static int asd_init_chip(struct asd_ha_struct *asd_ha)
+{
+	int err;
+
+	err = asd_chip_hardrst(asd_ha);
+	if (err) {
+		asd_printk("couldn't hard reset %s\n",
+			    pci_name(asd_ha->pcidev));
+		goto out;
+	}
+
+	asd_disable_ints(asd_ha);
+
+	err = asd_init_seqs(asd_ha);
+	if (err) {
+		asd_printk("couldn't init seqs for %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto out;
+	}
+
+	err = asd_start_seqs(asd_ha);
+	if (err) {
+		asd_printk("coudln't start seqs for %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto out;
+	}
+out:
+	return err;
+}
+
+#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
+
+static int max_devs = 0;
+module_param_named(max_devs, max_devs, int, S_IRUGO);
+MODULE_PARM_DESC(max_devs, "\n"
+	"\tMaximum number of SAS devices to support (not LUs).\n"
+	"\tDefault: 2176, Maximum: 65663.\n");
+
+static int max_cmnds = 0;
+module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
+MODULE_PARM_DESC(max_cmnds, "\n"
+	"\tMaximum number of commands queuable.\n"
+	"\tDefault: 512, Maximum: 66047.\n");
+
+static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
+{
+	unsigned long dma_addr = OCM_BASE_ADDR;
+	u32 d;
+
+	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+	asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
+	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+	d |= 4;
+	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+	asd_ha->hw_prof.max_ddbs += MAX_DEVS;
+}
+
+static int asd_extend_devctx(struct asd_ha_struct *asd_ha)
+{
+	dma_addr_t dma_handle;
+	unsigned long dma_addr;
+	u32 d;
+	int size;
+
+	asd_extend_devctx_ocm(asd_ha);
+
+	asd_ha->hw_prof.ddb_ext = NULL;
+	if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
+		max_devs = asd_ha->hw_prof.max_ddbs;
+		return 0;
+	}
+
+	size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
+
+	asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+	if (!asd_ha->hw_prof.ddb_ext) {
+		asd_printk("couldn't allocate memory for %d devices\n",
+			   max_devs);
+		max_devs = asd_ha->hw_prof.max_ddbs;
+		return -ENOMEM;
+	}
+	dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
+	dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
+	dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+	dma_handle = (dma_addr_t) dma_addr;
+	asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
+	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+	d &= ~4;
+	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+	asd_ha->hw_prof.max_ddbs = max_devs;
+
+	return 0;
+}
+
+static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
+{
+	dma_addr_t dma_handle;
+	unsigned long dma_addr;
+	u32 d;
+	int size;
+
+	asd_ha->hw_prof.scb_ext = NULL;
+	if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
+		max_cmnds = asd_ha->hw_prof.max_scbs;
+		return 0;
+	}
+
+	size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
+
+	asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+	if (!asd_ha->hw_prof.scb_ext) {
+		asd_printk("couldn't allocate memory for %d commands\n",
+			   max_cmnds);
+		max_cmnds = asd_ha->hw_prof.max_scbs;
+		return -ENOMEM;
+	}
+	dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
+	dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
+	dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
+	dma_handle = (dma_addr_t) dma_addr;
+	asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
+	d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+	d &= ~1;
+	asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+	asd_ha->hw_prof.max_scbs = max_cmnds;
+
+	return 0;
+}
+
+/**
+ * asd_init_ctxmem -- initialize context memory
+ * asd_ha: pointer to host adapter structure
+ *
+ * This function sets the maximum number of SCBs and
+ * DDBs which can be used by the sequencer.  This is normally
+ * 512 and 128 respectively.  If support for more SCBs or more DDBs
+ * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
+ * initialized here to extend context memory to point to host memory,
+ * thus allowing unlimited support for SCBs and DDBs -- only limited
+ * by host memory.
+ */
+static int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
+{
+	int bitmap_bytes;
+
+	asd_get_max_scb_ddb(asd_ha);
+	asd_extend_devctx(asd_ha);
+	asd_extend_cmdctx(asd_ha);
+
+	/* The kernel wants bitmaps to be unsigned long sized. */
+	bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
+	bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+	asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+	if (!asd_ha->hw_prof.ddb_bitmap)
+		return -ENOMEM;
+	spin_lock_init(&asd_ha->hw_prof.ddb_lock);
+
+	return 0;
+}
+
+int asd_init_hw(struct asd_ha_struct *asd_ha)
+{
+	int err;
+
+	err = asd_init_sw(asd_ha);
+	if (err)
+		return err;
+
+	err = asd_read_ocm(asd_ha);
+	if (err) {
+		asd_printk("couldn't read ocm(%d)\n", err);
+		/* While suspicios, it is not an error that we
+		 * couldn't read the OCM. */
+	}
+
+	err = asd_read_flash(asd_ha);
+	if (err) {
+		asd_printk("couldn't read flash(%d)\n", err);
+		/* While suspicios, it is not an error that we
+		 * couldn't read FLASH memory.
+		 */
+	}
+
+	asd_init_ctxmem(asd_ha);
+
+	asd_get_user_sas_addr(asd_ha);
+	if (!asd_ha->hw_prof.sas_addr[0]) {
+		asd_printk("No SAS Address provided for %s\n",
+			   pci_name(asd_ha->pcidev));
+		err = -ENODEV;
+		goto Out;
+	}
+
+	asd_propagate_sas_addr(asd_ha);
+
+	err = asd_init_phys(asd_ha);
+	if (err) {
+		asd_printk("couldn't initialize phys for %s\n",
+			    pci_name(asd_ha->pcidev));
+		goto Out;
+	}
+
+	err = asd_init_scbs(asd_ha);
+	if (err) {
+		asd_printk("couldn't initialize scbs for %s\n",
+			    pci_name(asd_ha->pcidev));
+		goto Out;
+	}
+
+	err = asd_init_dl(asd_ha);
+	if (err) {
+		asd_printk("couldn't initialize the done list:%d\n",
+			    err);
+		goto Out;
+	}
+
+	err = asd_init_escbs(asd_ha);
+	if (err) {
+		asd_printk("couldn't initialize escbs\n");
+		goto Out;
+	}
+
+	err = asd_init_chip(asd_ha);
+	if (err) {
+		asd_printk("couldn't init the chip\n");
+		goto Out;
+	}
+Out:
+	return err;
+}
+
+/* ---------- Chip reset ---------- */
+
+/**
+ * asd_chip_reset -- reset the host adapter, etc
+ * @asd_ha: pointer to host adapter structure of interest
+ *
+ * Called from the ISR.  Hard reset the chip.  Let everything
+ * timeout.  This should be no different than hot-unplugging the
+ * host adapter.  Once everything times out we'll init the chip with
+ * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
+ * XXX finish.
+ */
+static void asd_chip_reset(struct asd_ha_struct *asd_ha)
+{
+	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+
+	ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
+	asd_chip_hardrst(asd_ha);
+	sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+}
+
+/* ---------- Done List Routines ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long data)
+{
+	struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
+	struct asd_seq_data *seq = &asd_ha->seq;
+	unsigned long flags;
+
+	while (1) {
+		struct done_list_struct *dl = &seq->dl[seq->dl_next];
+		struct asd_ascb *ascb;
+
+		if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
+			break;
+
+		/* find the aSCB */
+		spin_lock_irqsave(&seq->tc_index_lock, flags);
+		ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
+		spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+		if (unlikely(!ascb)) {
+			ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
+			goto next_1;
+		} else if (ascb->scb->header.opcode == EMPTY_SCB) {
+			goto out;
+		} else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
+			goto next_1;
+		}
+		spin_lock_irqsave(&seq->pend_q_lock, flags);
+		list_del_init(&ascb->list);
+		seq->pending--;
+		spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+	out:
+		ascb->tasklet_complete(ascb, dl);
+
+	next_1:
+		seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
+		if (!seq->dl_next)
+			seq->dl_toggle ^= DL_TOGGLE_MASK;
+	}
+}
+
+/* ---------- Interrupt Service Routines ---------- */
+
+/**
+ * asd_process_donelist_isr -- schedule processing of done list entries
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
+{
+	tasklet_schedule(&asd_ha->seq.dl_tasklet);
+}
+
+/**
+ * asd_com_sas_isr -- process device communication interrupt (COMINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
+{
+	u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
+
+	/* clear COMSTAT int */
+	asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
+
+	if (comstat & CSBUFPERR) {
+		asd_printk("%s: command/status buffer dma parity error\n",
+			   pci_name(asd_ha->pcidev));
+	} else if (comstat & CSERR) {
+		int i;
+		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+		dmaerr &= 0xFF;
+		asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
+			   "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
+			   pci_name(asd_ha->pcidev),
+			   dmaerr,
+			   asd_read_reg_dword(asd_ha, CSDMAADR),
+			   asd_read_reg_dword(asd_ha, CSDMAADR+4));
+		asd_printk("CSBUFFER:\n");
+		for (i = 0; i < 8; i++) {
+			asd_printk("%08x %08x %08x %08x\n",
+				   asd_read_reg_dword(asd_ha, CSBUFFER),
+				   asd_read_reg_dword(asd_ha, CSBUFFER+4),
+				   asd_read_reg_dword(asd_ha, CSBUFFER+8),
+				   asd_read_reg_dword(asd_ha, CSBUFFER+12));
+		}
+		asd_dump_seq_state(asd_ha, 0);
+	} else if (comstat & OVLYERR) {
+		u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+		dmaerr = (dmaerr >> 8) & 0xFF;
+		asd_printk("%s: overlay dma error:0x%x\n",
+			   pci_name(asd_ha->pcidev),
+			   dmaerr);
+	}
+	asd_chip_reset(asd_ha);
+}
+
+static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
+{
+	static const char *halt_code[256] = {
+		"UNEXPECTED_INTERRUPT0",
+		"UNEXPECTED_INTERRUPT1",
+		"UNEXPECTED_INTERRUPT2",
+		"UNEXPECTED_INTERRUPT3",
+		"UNEXPECTED_INTERRUPT4",
+		"UNEXPECTED_INTERRUPT5",
+		"UNEXPECTED_INTERRUPT6",
+		"UNEXPECTED_INTERRUPT7",
+		"UNEXPECTED_INTERRUPT8",
+		"UNEXPECTED_INTERRUPT9",
+		"UNEXPECTED_INTERRUPT10",
+		[11 ... 19] = "unknown[11,19]",
+		"NO_FREE_SCB_AVAILABLE",
+		"INVALID_SCB_OPCODE",
+		"INVALID_MBX_OPCODE",
+		"INVALID_ATA_STATE",
+		"ATA_QUEUE_FULL",
+		"ATA_TAG_TABLE_FAULT",
+		"ATA_TAG_MASK_FAULT",
+		"BAD_LINK_QUEUE_STATE",
+		"DMA2CHIM_QUEUE_ERROR",
+		"EMPTY_SCB_LIST_FULL",
+		"unknown[30]",
+		"IN_USE_SCB_ON_FREE_LIST",
+		"BAD_OPEN_WAIT_STATE",
+		"INVALID_STP_AFFILIATION",
+		"unknown[34]",
+		"EXEC_QUEUE_ERROR",
+		"TOO_MANY_EMPTIES_NEEDED",
+		"EMPTY_REQ_QUEUE_ERROR",
+		"Q_MONIRTT_MGMT_ERROR",
+		"TARGET_MODE_FLOW_ERROR",
+		"DEVICE_QUEUE_NOT_FOUND",
+		"START_IRTT_TIMER_ERROR",
+		"ABORT_TASK_ILLEGAL_REQ",
+		[43 ... 255] = "unknown[43,255]"
+	};
+
+	if (dchstatus & CSEQINT) {
+		u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
+
+		if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
+			asd_printk("%s: CSEQ arp2int:0x%x\n",
+				   pci_name(asd_ha->pcidev),
+				   arp2int);
+		} else if (arp2int & ARP2HALTC)
+			asd_printk("%s: CSEQ halted: %s\n",
+				   pci_name(asd_ha->pcidev),
+				   halt_code[(arp2int>>16)&0xFF]);
+		else
+			asd_printk("%s: CARP2INT:0x%x\n",
+				   pci_name(asd_ha->pcidev),
+				   arp2int);
+	}
+	if (dchstatus & LSEQINT_MASK) {
+		int lseq;
+		u8  lseq_mask = dchstatus & LSEQINT_MASK;
+
+		for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+			u32 arp2int = asd_read_reg_dword(asd_ha,
+							 LmARP2INT(lseq));
+			if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
+				       | ARP2CIOPERR)) {
+				asd_printk("%s: LSEQ%d arp2int:0x%x\n",
+					   pci_name(asd_ha->pcidev),
+					   lseq, arp2int);
+				/* XXX we should only do lseq reset */
+			} else if (arp2int & ARP2HALTC)
+				asd_printk("%s: LSEQ%d halted: %s\n",
+					   pci_name(asd_ha->pcidev),
+					   lseq,halt_code[(arp2int>>16)&0xFF]);
+			else
+				asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
+					   pci_name(asd_ha->pcidev), lseq,
+					   arp2int);
+		}
+	}
+	asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
+{
+	u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
+
+	if (dchstatus & CFIFTOERR) {
+		asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
+		asd_chip_reset(asd_ha);
+	} else
+		asd_arp2_err(asd_ha, dchstatus);
+}
+
+/**
+ * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
+{
+	u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
+
+	if (!(stat0r & ASIERR)) {
+		asd_printk("hmm, EXSI interrupted but no error?\n");
+		return;
+	}
+
+	if (stat0r & ASIFMTERR) {
+		asd_printk("ASI SEEPROM format error for %s\n",
+			   pci_name(asd_ha->pcidev));
+	} else if (stat0r & ASISEECHKERR) {
+		u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
+		asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
+			   stat1r & CHECKSUM_MASK,
+			   pci_name(asd_ha->pcidev));
+	} else {
+		u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
+
+		if (!(statr & CPI2ASIMSTERR_MASK)) {
+			ASD_DPRINTK("hmm, ASIERR?\n");
+			return;
+		} else {
+			u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
+			u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
+
+			asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
+				   "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
+				   "master id: 0x%x, master err: 0x%x\n",
+				   pci_name(asd_ha->pcidev),
+				   addr, data,
+				   (statr & CPI2ASIBYTECNT_MASK) >> 16,
+				   (statr & CPI2ASIBYTEEN_MASK) >> 12,
+				   (statr & CPI2ASITARGERR_MASK) >> 8,
+				   (statr & CPI2ASITARGMID_MASK) >> 4,
+				   (statr & CPI2ASIMSTERR_MASK));
+		}
+	}
+	asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hst_pcix_isr -- process host interface interrupts
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Asserted on PCIX errors: target abort, etc.
+ */
+static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
+{
+	u16 status;
+	u32 pcix_status;
+	u32 ecc_status;
+
+	pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
+	pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
+	pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
+
+	if (status & PCI_STATUS_DETECTED_PARITY)
+		asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
+	else if (status & PCI_STATUS_REC_MASTER_ABORT)
+		asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
+	else if (status & PCI_STATUS_REC_TARGET_ABORT)
+		asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
+	else if (status & PCI_STATUS_PARITY)
+		asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
+	else if (pcix_status & RCV_SCE) {
+		asd_printk("received split completion error for %s\n",
+			   pci_name(asd_ha->pcidev));
+		pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+		/* XXX: Abort task? */
+		return;
+	} else if (pcix_status & UNEXP_SC) {
+		asd_printk("unexpected split completion for %s\n",
+			   pci_name(asd_ha->pcidev));
+		pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+		/* ignore */
+		return;
+	} else if (pcix_status & SC_DISCARD)
+		asd_printk("split completion discarded for %s\n",
+			   pci_name(asd_ha->pcidev));
+	else if (ecc_status & UNCOR_ECCERR)
+		asd_printk("uncorrectable ECC error for %s\n",
+			   pci_name(asd_ha->pcidev));
+	asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hw_isr -- host adapter interrupt service routine
+ * @irq: ignored
+ * @dev_id: pointer to host adapter structure
+ * @regs: ignored
+ *
+ * The ISR processes done list entries and level 3 error handling.
+ */
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct asd_ha_struct *asd_ha = dev_id;
+	u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
+
+	if (!chimint)
+		return IRQ_NONE;
+
+	asd_write_reg_dword(asd_ha, CHIMINT, chimint);
+	(void) asd_read_reg_dword(asd_ha, CHIMINT);
+
+	if (chimint & DLAVAIL)
+		asd_process_donelist_isr(asd_ha);
+	if (chimint & COMINT)
+		asd_com_sas_isr(asd_ha);
+	if (chimint & DEVINT)
+		asd_dch_sas_isr(asd_ha);
+	if (chimint & INITERR)
+		asd_rbi_exsi_isr(asd_ha);
+	if (chimint & HOSTERR)
+		asd_hst_pcix_isr(asd_ha);
+
+	return IRQ_HANDLED;
+}
+
+/* ---------- SCB handling ---------- */
+
+static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
+					      unsigned int gfp_flags)
+{
+	extern kmem_cache_t *asd_ascb_cache;
+	struct asd_seq_data *seq = &asd_ha->seq;
+	struct asd_ascb *ascb;
+	unsigned long flags;
+
+	ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
+
+	if (ascb) {
+		memset(ascb, 0, sizeof(*ascb));
+		ascb->dma_scb.size = sizeof(struct scb);
+		ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
+						     gfp_flags,
+						    &ascb->dma_scb.dma_handle);
+		if (!ascb->dma_scb.vaddr) {
+			kmem_cache_free(asd_ascb_cache, ascb);
+			return NULL;
+		}
+		memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
+		asd_init_ascb(asd_ha, ascb);
+
+		spin_lock_irqsave(&seq->tc_index_lock, flags);
+		ascb->tc_index = asd_tc_index_get(seq, ascb);
+		spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+		if (ascb->tc_index == -1)
+			goto undo;
+
+		ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
+	}
+
+	return ascb;
+undo:
+	dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+		      ascb->dma_scb.dma_handle);
+	kmem_cache_free(asd_ascb_cache, ascb);
+	ASD_DPRINTK("no index for ascb\n");
+	return NULL;
+}
+
+/**
+ * asd_ascb_alloc_list -- allocate a list of aSCBs
+ * @asd_ha: pointer to host adapter structure
+ * @num: pointer to integer number of aSCBs
+ * @gfp_flags: GFP_ flags.
+ *
+ * This is the only function which is used to allocate aSCBs.
+ * It can allocate one or many. If more than one, then they form
+ * a linked list in two ways: by their list field of the ascb struct
+ * and by the next_scb field of the scb_header.
+ *
+ * Returns NULL if no memory was available, else pointer to a list
+ * of ascbs.  When this function returns, @num would be the number
+ * of SCBs which were not able to be allocated, 0 if all requested
+ * were able to be allocated.
+ */
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+				     *asd_ha, int *num,
+				     unsigned int gfp_flags)
+{
+	struct asd_ascb *first = NULL;
+
+	for ( ; *num > 0; --*num) {
+		struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
+
+		if (!ascb)
+			break;
+		else if (!first)
+			first = ascb;
+		else {
+			struct asd_ascb *last = list_entry(first->list.prev,
+							   struct asd_ascb,
+							   list);
+			list_add_tail(&ascb->list, &first->list);
+			last->scb->header.next_scb =
+				cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
+		}
+	}
+
+	return first;
+}
+
+/**
+ * asd_swap_head_scb -- swap the head scb
+ * @asd_ha: pointer to host adapter structure
+ * @ascb: pointer to the head of an ascb list
+ *
+ * The sequencer knows the DMA address of the next SCB to be DMAed to
+ * the host adapter, from initialization or from the last list DMAed.
+ * seq->next_scb keeps the address of this SCB.  The sequencer will
+ * DMA to the host adapter this list of SCBs.  But the head (first
+ * element) of this list is not known to the sequencer.  Here we swap
+ * the head of the list with the known SCB (memcpy()).
+ * Only one memcpy() is required per list so it is in our interest
+ * to keep the list of SCB as long as possible so that the ratio
+ * of number of memcpy calls to the number of SCB DMA-ed is as small
+ * as possible.
+ *
+ * LOCKING: called with the pending list lock held.
+ */
+static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
+				     struct asd_ascb *ascb)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	struct asd_ascb *last = list_entry(ascb->list.prev,
+					   struct asd_ascb,
+					   list);
+	struct asd_dma_tok t = ascb->dma_scb;
+
+	memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
+	ascb->dma_scb = seq->next_scb;
+	ascb->scb = ascb->dma_scb.vaddr;
+	seq->next_scb = t;
+	last->scb->header.next_scb =
+		cpu_to_le64(((u64)seq->next_scb.dma_handle));
+}
+
+/**
+ * asd_start_timers -- (add and) start timers of SCBs
+ * @list: pointer to struct list_head of the scbs
+ * @to: timeout in jiffies
+ *
+ * If an SCB in the @list has no timer function, assign the default
+ * one,  then start the timer of the SCB.  This function is
+ * intended to be called from asd_post_ascb_list(), just prior to
+ * posting the SCBs to the sequencer.
+ */
+static inline void asd_start_scb_timers(struct list_head *list)
+{
+	struct asd_ascb *ascb;
+	list_for_each_entry(ascb, list, list) {
+		if (!ascb->uldd_timer) {
+			ascb->timer.data = (unsigned long) ascb;
+			ascb->timer.function = asd_ascb_timedout;
+			ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+			add_timer(&ascb->timer);
+		}
+	}
+}
+
+/**
+ * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first aSCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * See queueing comment in asd_post_escb_list().
+ *
+ * Additional note on queuing: In order to minimize the ratio of memcpy()
+ * to the number of ascbs sent, we try to batch-send as many ascbs as possible
+ * in one go.
+ * Two cases are possible:
+ *    A) can_queue >= num,
+ *    B) can_queue < num.
+ * Case A: we can send the whole batch at once.  Increment "pending"
+ * in the beginning of this function, when it is checked, in order to
+ * eliminate races when this function is called by multiple processes.
+ * Case B: should never happen if the managing layer considers
+ * lldd_queue_size.
+ */
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+		       int num)
+{
+	unsigned long flags;
+	LIST_HEAD(list);
+	int can_queue;
+
+	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+	can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
+	if (can_queue >= num)
+		asd_ha->seq.pending += num;
+	else
+		can_queue = 0;
+
+	if (!can_queue) {
+		spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+		asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
+		return -SAS_QUEUE_FULL;
+	}
+
+	asd_swap_head_scb(asd_ha, ascb);
+
+	__list_add(&list, ascb->list.prev, &ascb->list);
+
+	asd_start_scb_timers(&list);
+
+	asd_ha->seq.scbpro += num;
+	list_splice_init(&list, asd_ha->seq.pend_q.prev);
+	asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+	return 0;
+}
+
+/**
+ * asd_post_escb_list -- post a list of 1 or more empty scb
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first empty SCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * This is essentially the same as asd_post_ascb_list, but we do not
+ * increment pending, add those to the pending list or get indexes.
+ * See asd_init_escbs() and asd_init_post_escbs().
+ *
+ * Since sending a list of ascbs is a superset of sending a single
+ * ascb, this function exists to generalize this.  More specifically,
+ * when sending a list of those, we want to do only a _single_
+ * memcpy() at swap head, as opposed to for each ascb sent (in the
+ * case of sending them one by one).  That is, we want to minimize the
+ * ratio of memcpy() operations to the number of ascbs sent.  The same
+ * logic applies to asd_post_ascb_list().
+ */
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+		       int num)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+	asd_swap_head_scb(asd_ha, ascb);
+	asd_ha->seq.scbpro += num;
+	asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+	return 0;
+}
+
+/* ---------- LED ---------- */
+
+/**
+ * asd_turn_led -- turn on/off an LED
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: the PHY id whose LED we want to manupulate
+ * @op: 1 to turn on, 0 to turn off
+ */
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+	if (phy_id < ASD_MAX_PHYS) {
+		u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
+		if (op)
+			v |= LEDPOL;
+		else
+			v &= ~LEDPOL;
+		asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
+	}
+}
+
+/**
+ * asd_control_led -- enable/disable an LED on the board
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: integer, the phy id
+ * @op: integer, 1 to enable, 0 to disable the LED
+ *
+ * First we output enable the LED, then we set the source
+ * to be an external module.
+ */
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+	if (phy_id < ASD_MAX_PHYS) {
+		u32 v;
+
+		v = asd_read_reg_dword(asd_ha, GPIOOER);
+		if (op)
+			v |= (1 << phy_id);
+		else
+			v &= ~(1 << phy_id);
+		asd_write_reg_dword(asd_ha, GPIOOER, v);
+
+		v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
+		if (op)
+			v |= (1 << phy_id);
+		else
+			v &= ~(1 << phy_id);
+		asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
+	}
+}
+
+/* ---------- PHY enable ---------- */
+
+static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
+{
+	struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
+			   HOTPLUG_DELAY_TIMEOUT);
+
+	/* Get defaults from manuf. sector */
+	/* XXX we need defaults for those in case MS is broken. */
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
+			   phy->phy_desc->phy_control_0);
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
+			   phy->phy_desc->phy_control_1);
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
+			   phy->phy_desc->phy_control_2);
+	asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
+			   phy->phy_desc->phy_control_3);
+
+	asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
+			    ASD_COMINIT_TIMEOUT);
+
+	asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
+			   phy->id_frm_tok->dma_handle);
+
+	asd_control_led(asd_ha, phy_id, 1);
+
+	return 0;
+}
+
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
+{
+	u8  phy_m;
+	u8  i;
+	int num = 0, k;
+	struct asd_ascb *ascb;
+	struct asd_ascb *ascb_list;
+
+	if (!phy_mask) {
+		asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+		return 0;
+	}
+
+	for_each_phy(phy_mask, phy_m, i) {
+		num++;
+		asd_enable_phy(asd_ha, i);
+	}
+
+	k = num;
+	ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
+	if (!ascb_list) {
+		asd_printk("no memory for control phy ascb list\n");
+		return -ENOMEM;
+	}
+	num -= k;
+
+	ascb = ascb_list;
+	for_each_phy(phy_mask, phy_m, i) {
+		asd_build_control_phy(ascb, i, ENABLE_PHY);
+		ascb = list_entry(ascb->list.next, struct asd_ascb, list);
+	}
+	ASD_DPRINTK("posting %d control phy scbs\n", num);
+	k = asd_post_ascb_list(asd_ha, ascb_list, num);
+	if (k)
+		asd_ascb_free_list(ascb_list);
+
+	return k;
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_hwi.h newtree/drivers/scsi/aic94xx/aic94xx_hwi.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_hwi.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_hwi.h	2006-04-01 05:35:45.899488500 -0500
@@ -0,0 +1,398 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_hwi.h#74 $
+ */
+
+#ifndef _AIC94XX_HWI_H_
+#define _AIC94XX_HWI_H_
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <scsi/sas/sas_class.h>
+
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+
+/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
+#define ASD_MAX_PHYS       8
+#define ASD_PCBA_SN_SIZE   12
+
+/* Those are to be further named properly, the "RAZORx" part, and
+ * subsequently included in include/linux/pci_ids.h.
+ */
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
+
+struct asd_ha_addrspace {
+	void __iomem  *addr;
+	unsigned long  start;       /* pci resource start */
+	unsigned long  len;         /* pci resource len */
+	unsigned long  flags;       /* pci resource flags */
+
+	/* addresses internal to the host adapter */
+	u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
+	u32 swb_base;
+	u32 swc_base;
+};
+
+struct bios_struct {
+	int    present;
+	u8     maj;
+	u8     min;
+	u32    bld;
+};
+
+struct unit_element_struct {
+	u16    num;
+	u16    size;
+	void   *area;
+};
+
+struct flash_struct {
+	u32    bar;
+	int    present;
+	int    wide;
+	u8     manuf;
+	u8     dev_id;
+	u8     sec_prot;
+
+	u32    dir_offs;
+};
+
+struct asd_phy_desc {
+	/* From CTRL-A settings, then set to what is appropriate */
+	u8     sas_addr[SAS_ADDR_SIZE];
+	u8     max_sas_lrate;
+	u8     min_sas_lrate;
+	u8     max_sata_lrate;
+	u8     min_sata_lrate;
+	u8     flags;
+#define ASD_CRC_DIS  1
+#define ASD_SATA_SPINUP_HOLD 2
+
+	u8     phy_control_0; /* mode 5 reg 0x160 */
+	u8     phy_control_1; /* mode 5 reg 0x161 */
+	u8     phy_control_2; /* mode 5 reg 0x162 */
+	u8     phy_control_3; /* mode 5 reg 0x163 */
+};
+
+struct asd_dma_tok {
+	void *vaddr;
+	dma_addr_t dma_handle;
+	size_t size;
+};
+
+struct hw_profile {
+	struct bios_struct bios;
+	struct unit_element_struct ue;
+	struct flash_struct flash;
+
+	u8     sas_addr[SAS_ADDR_SIZE];
+	char   pcba_sn[ASD_PCBA_SN_SIZE+1];
+
+	u8     enabled_phys;	  /* mask of enabled phys */
+	struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
+	u32    max_scbs;	  /* absolute sequencer scb queue size */
+	struct asd_dma_tok *scb_ext;
+	u32    max_ddbs;
+	struct asd_dma_tok *ddb_ext;
+
+	spinlock_t ddb_lock;
+	void  *ddb_bitmap;
+
+	int    num_phys;	  /* ENABLEABLE */
+	int    max_phys;	  /* REPORTED + ENABLEABLE */
+
+	unsigned addr_range;	  /* max # of addrs; max # of possible ports */
+	unsigned port_name_base;
+	unsigned dev_name_base;
+	unsigned sata_name_base;
+};
+
+struct asd_ascb {
+	struct list_head list;
+	struct asd_ha_struct *ha;
+
+	struct scb *scb;	  /* equals dma_scb->vaddr */
+	struct asd_dma_tok dma_scb;
+	struct asd_dma_tok *sg_arr;
+
+	void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+	u8     uldd_timer:1;
+
+	/* internally generated command */
+	struct timer_list timer;
+	struct completion completion;
+	u8        tag_valid:1;
+	__be16    tag;		  /* error recovery only */
+
+	/* If this is an Empty SCB, index of first edb in seq->edb_arr. */
+	int    edb_index;
+
+	/* Used by the timer timeout function. */
+	int    tc_index;
+
+	void   *uldd_task;
+};
+
+#define ASD_DL_SIZE_BITS   0x8
+#define ASD_DL_SIZE        (1<<(2+ASD_DL_SIZE_BITS))
+#define ASD_DEF_DL_TOGGLE  0x01
+
+struct asd_seq_data {
+	spinlock_t pend_q_lock;
+	u16    scbpro;
+	int    pending;
+	struct list_head pend_q;
+	int    can_queue;	  /* per adapter */
+	struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
+
+	spinlock_t tc_index_lock;
+	void **tc_index_array;
+	void *tc_index_bitmap;
+	int   tc_index_bitmap_bits;
+
+	struct tasklet_struct dl_tasklet;
+	struct done_list_struct *dl; /* array of done list entries, equals */
+	struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
+	int    dl_toggle;
+	int    dl_next;
+
+	int    num_edbs;
+	struct asd_dma_tok **edb_arr;
+	int    num_escbs;
+	struct asd_ascb **escb_arr; /* array of pointers to escbs */
+};
+
+/* This is the Host Adapter structure.  It describes the hardware
+ * SAS adapter.
+ */
+struct asd_ha_struct {
+	struct pci_dev   *pcidev;
+	const char       *name;
+
+	struct sas_ha_struct sas_ha;
+
+	u8                revision_id;
+
+	int               iospace;
+	spinlock_t        iolock;
+	struct asd_ha_addrspace io_handle[2];
+
+	struct hw_profile hw_prof;
+
+	struct asd_phy    phys[ASD_MAX_PHYS];
+	struct sas_port   ports[ASD_MAX_PHYS];
+
+	struct dma_pool  *scb_pool;
+
+	struct asd_seq_data  seq; /* sequencer related */
+};
+
+/* ---------- Common macros ---------- */
+
+#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
+#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8)     \
+                                    ? ((u32)((__dma_handle) >> 32)) \
+                                    : ((u32)0))
+
+#define dev_to_asd_ha(__dev)  pci_get_drvdata(to_pci_dev(__dev))
+#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF   \
+				 && ((__site_no) & 0xF0FF) > 0x001F)
+/* For each bit set in __lseq_mask, set __lseq to equal the bit
+ * position of the set bit and execute the statement following.
+ * __mc is the temporary mask, used as a mask "counter".
+ */
+#define for_each_sequencer(__lseq_mask, __mc, __lseq)                        \
+	for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+		if (((__mc) & 1))
+#define for_each_phy(__lseq_mask, __mc, __lseq)                              \
+	for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+		if (((__mc) & 1))
+
+#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
+
+/* ---------- DMA allocs ---------- */
+
+static inline struct asd_dma_tok *asd_dmatok_alloc(unsigned int flags)
+{
+	return kmem_cache_alloc(asd_dma_token_cache, flags);
+}
+
+static inline void asd_dmatok_free(struct asd_dma_tok *token)
+{
+	kmem_cache_free(asd_dma_token_cache, token);
+}
+
+static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
+						     asd_ha, size_t size,
+						     unsigned int flags)
+{
+	struct asd_dma_tok *token = asd_dmatok_alloc(flags);
+	if (token) {
+		token->size = size;
+		token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
+						  token->size,
+						  &token->dma_handle,
+						  flags);
+		if (!token->vaddr) {
+			asd_dmatok_free(token);
+			token = NULL;
+		}
+	}
+	return token;
+}
+
+static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
+				     struct asd_dma_tok *token)
+{
+	if (token) {
+		dma_free_coherent(&asd_ha->pcidev->dev, token->size,
+				  token->vaddr, token->dma_handle);
+		asd_dmatok_free(token);
+	}
+}
+
+static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
+				 struct asd_ascb *ascb)
+{
+	INIT_LIST_HEAD(&ascb->list);
+	ascb->scb = ascb->dma_scb.vaddr;
+	ascb->ha = asd_ha;
+	ascb->timer.function = NULL;
+	init_timer(&ascb->timer);
+	ascb->tc_index = -1;
+	init_completion(&ascb->completion);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
+{
+	seq->tc_index_array[index] = NULL;
+	clear_bit(index, seq->tc_index_bitmap);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
+{
+	int index;
+
+	index = find_first_zero_bit(seq->tc_index_bitmap,
+				    seq->tc_index_bitmap_bits);
+	if (index == seq->tc_index_bitmap_bits)
+		return -1;
+
+	seq->tc_index_array[index] = ptr;
+	set_bit(index, seq->tc_index_bitmap);
+
+	return index;
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
+{
+	return seq->tc_index_array[index];
+}
+
+/**
+ * asd_ascb_free -- free a single aSCB after is has completed
+ * @ascb: pointer to the aSCB of interest
+ *
+ * This frees an aSCB after it has been executed/completed by
+ * the sequencer.
+ */
+static inline void asd_ascb_free(struct asd_ascb *ascb)
+{
+	if (ascb) {
+		struct asd_ha_struct *asd_ha = ascb->ha;
+		unsigned long flags;
+
+		BUG_ON(!list_empty(&ascb->list));
+		spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
+		asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
+		spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
+		dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+			      ascb->dma_scb.dma_handle);
+		kmem_cache_free(asd_ascb_cache, ascb);
+	}
+}
+
+/**
+ * asd_ascb_list_free -- free a list of ascbs
+ * @ascb_list: a list of ascbs
+ *
+ * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
+ * It is used when say the scb queueing function returned QUEUE_FULL,
+ * and we do not need the ascbs any more.
+ */
+static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
+{
+	LIST_HEAD(list);
+	struct list_head *n, *pos;
+
+	__list_add(&list, ascb_list->list.prev, &ascb_list->list);
+	list_for_each_safe(pos, n, &list) {
+		list_del_init(pos);
+		asd_ascb_free(list_entry(pos, struct asd_ascb, list));
+	}
+}
+
+/* ---------- Function declarations ---------- */
+
+int  asd_init_hw(struct asd_ha_struct *asd_ha);
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
+
+
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+				     *asd_ha, int *num,
+				     unsigned int gfp_mask);
+
+int  asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+			int num);
+int  asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+			int num);
+
+int  asd_init_post_escbs(struct asd_ha_struct *asd_ha);
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+int  asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+				      u8 subfunc);
+
+void asd_ascb_timedout(unsigned long data);
+int  asd_chip_hardrst(struct asd_ha_struct *asd_ha);
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_init.c newtree/drivers/scsi/aic94xx/aic94xx_init.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_init.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_init.c	2006-04-01 05:35:45.951491750 -0500
@@ -0,0 +1,808 @@
+/*
+ * Aic94xx SAS/SATA driver initialization.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_init.c#99 $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+/* The format is "version.release.patchlevel" */
+#define ASD_DRIVER_VERSION "1.0.2"
+
+static int attach_HostRAID = 0;
+module_param_named(attach_HostRAID, attach_HostRAID, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(attach_HostRAID, "\n"
+	"\tEnable(1) or disable(0) attaching to HostRAID enabled host adapters.\n"
+	"\tDefault: 0");
+
+static int use_msi = 0;
+module_param_named(use_msi, use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "\n"
+	"\tEnable(1) or disable(0) using PCI MSI.\n"
+	"\tDefault: 0");
+
+static int lldd_max_execute_num = 0;
+module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
+MODULE_PARM_DESC(collector, "\n"
+	"\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
+	"\tMode.  If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
+	"\tThe aic94xx SAS LLDD supports both modes.\n"
+	"\tDefault: 0 (Direct Mode).\n");
+
+char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
+
+static const struct scsi_host_template aic94xx_sht = {
+	.module			= THIS_MODULE,
+	/* .name is initialized */
+	.name			= "aic94xx",
+	.queuecommand		= sas_queuecommand,
+	.eh_strategy_handler	= sas_scsi_recover_host,
+	.slave_alloc		= sas_slave_alloc,
+	.slave_configure	= sas_slave_configure,
+	.slave_destroy		= sas_slave_destroy,
+	.change_queue_depth	= sas_change_queue_depth,
+	.change_queue_type	= sas_change_queue_type,
+	.bios_param		= sas_bios_param,
+	/* .can_queue is initialized */
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
+	/* .cmd_per_lun is initilized to .can_queue */
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+{
+	int err, i;
+	struct asd_ha_addrspace *io_handle;
+
+	asd_ha->iospace = 0;
+	for (i = 0; i < 3; i += 2) {
+		io_handle = &asd_ha->io_handle[i==0?0:1];
+		io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+		io_handle->len   = pci_resource_len(asd_ha->pcidev, i);
+		io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+		err = -ENODEV;
+		if (!io_handle->start || !io_handle->len) {
+			asd_printk("MBAR%d start or length for %s is 0.\n",
+				   i==0?0:1, pci_name(asd_ha->pcidev));
+			goto Err;
+		}
+		err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+		if (err) {
+			asd_printk("couldn't reserve memory region for %s\n",
+				   pci_name(asd_ha->pcidev));
+			goto Err;
+		}
+		if (io_handle->flags & IORESOURCE_CACHEABLE)
+			io_handle->addr = ioremap(io_handle->start,
+						  io_handle->len);
+		else
+			io_handle->addr = ioremap_nocache(io_handle->start,
+							  io_handle->len);
+		if (!io_handle->addr) {
+			asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,
+				   pci_name(asd_ha->pcidev));
+			goto Err_unreq;
+		}
+	}
+
+	return 0;
+Err_unreq:
+	pci_release_region(asd_ha->pcidev, i);
+Err:
+	if (i > 0) {
+		io_handle = &asd_ha->io_handle[0];
+		iounmap(io_handle->addr);
+		pci_release_region(asd_ha->pcidev, 0);
+	}
+	return err;
+}
+
+static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+{
+	struct asd_ha_addrspace *io_handle;
+
+	io_handle = &asd_ha->io_handle[1];
+	iounmap(io_handle->addr);
+	pci_release_region(asd_ha->pcidev, 2);
+
+	io_handle = &asd_ha->io_handle[0];
+	iounmap(io_handle->addr);
+	pci_release_region(asd_ha->pcidev, 0);
+}
+
+static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+{
+	int i = PCI_IOBAR_OFFSET, err;
+	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
+
+	asd_ha->iospace = 1;
+	io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+	io_handle->len   = pci_resource_len(asd_ha->pcidev, i);
+	io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+	io_handle->addr  = (void __iomem *) io_handle->start;
+	if (!io_handle->start || !io_handle->len) {
+		asd_printk("couldn't get IO ports for %s\n",
+			   pci_name(asd_ha->pcidev));
+		return -ENODEV;
+	}
+	err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+	if (err) {
+		asd_printk("couldn't reserve io space for %s\n",
+			   pci_name(asd_ha->pcidev));
+	}
+
+	return err;
+}
+
+static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+{
+	pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
+}
+
+static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
+{
+	int err;
+	u16 cmd_reg;
+
+	err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);
+	if (err) {
+		asd_printk("couldn't read command register of %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto Err;
+	}
+
+	err = -ENODEV;
+	if (cmd_reg & PCI_COMMAND_MEMORY) {
+		if ((err = asd_map_memio(asd_ha)))
+			goto Err;
+	} else if (cmd_reg & PCI_COMMAND_IO) {
+		if ((err = asd_map_ioport(asd_ha)))
+			goto Err;
+		asd_printk("%s ioport mapped -- upgrade your hardware\n",
+			   pci_name(asd_ha->pcidev));
+	} else {
+		asd_printk("no proper device access to %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto Err;
+	}
+
+	return 0;
+Err:
+	return err;
+}
+
+static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+{
+	if (asd_ha->iospace)
+		asd_unmap_ioport(asd_ha);
+	else
+		asd_unmap_memio(asd_ha);
+}
+
+static const char *asd_dev_rev[30] = {
+	[0] = "A0",
+	[1] = "A1",
+	[8] = "B0",
+};
+
+static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+{
+	int err, i;
+
+	err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
+				   &asd_ha->revision_id);
+	if (err) {
+		asd_printk("couldn't read REVISION ID register of %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto Err;
+	}
+	err = -ENODEV;
+	if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
+		asd_printk("%s is revision %s (%X), which is not supported\n",
+			   pci_name(asd_ha->pcidev),
+			   asd_dev_rev[asd_ha->revision_id],
+			   asd_ha->revision_id);
+		goto Err;
+	}
+	/* Provide some sane default values. */
+	asd_ha->hw_prof.max_scbs = 512;
+	asd_ha->hw_prof.max_ddbs = 128;
+	asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
+	/* All phys are enabled, by default. */
+	asd_ha->hw_prof.enabled_phys = 0xFF;
+	for (i = 0; i < ASD_MAX_PHYS; i++) {
+		asd_ha->hw_prof.phy_desc[i].max_sas_lrate = PHY_LINKRATE_3;
+		asd_ha->hw_prof.phy_desc[i].min_sas_lrate = PHY_LINKRATE_1_5;
+		asd_ha->hw_prof.phy_desc[i].max_sata_lrate= PHY_LINKRATE_1_5;
+		asd_ha->hw_prof.phy_desc[i].min_sata_lrate= PHY_LINKRATE_1_5;
+	}
+
+	return 0;
+Err:
+	return err;
+}
+
+static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+{
+	int err = asd_common_setup(asd_ha);
+
+	if (err)
+		return err;
+
+	asd_ha->hw_prof.addr_range = 8;
+	asd_ha->hw_prof.port_name_base = 0;
+	asd_ha->hw_prof.dev_name_base = 8;
+	asd_ha->hw_prof.sata_name_base = 16;
+
+	return 0;
+}
+
+static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+{
+	int err = asd_common_setup(asd_ha);
+
+	if (err)
+		return err;
+
+	asd_ha->hw_prof.addr_range = 4;
+	asd_ha->hw_prof.port_name_base = 0;
+	asd_ha->hw_prof.dev_name_base = 4;
+	asd_ha->hw_prof.sata_name_base = 8;
+
+	return 0;
+}
+
+static ssize_t asd_show_dev_rev(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			asd_dev_rev[asd_ha->revision_id]);
+}
+static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);
+
+static ssize_t asd_show_dev_bios_build(struct device *dev,
+				       struct device_attribute *attr,char *buf)
+{
+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+	return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);
+}
+static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);
+
+static ssize_t asd_show_dev_pcba_sn(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+	return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);
+}
+static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+
+static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+	device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+	device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+	device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+/* The first entry, 0, is used for dynamic ids, the rest for devices
+ * we know about.
+ */
+static struct asd_pcidev_struct {
+	const char * name;
+	int (*setup)(struct asd_ha_struct *asd_ha);
+} asd_pcidev_data[] = {
+	/* Id 0 is used for dynamic ids. */
+	{ .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",
+	  .setup = asd_aic9410_setup
+	},
+	{ .name  = "Adaptec AIC-9410W SAS/SATA Host Adapter",
+	  .setup = asd_aic9410_setup
+	},
+	{ .name  = "Adaptec AIC-9405W SAS/SATA Host Adapter",
+	  .setup = asd_aic9405_setup
+	},
+};
+
+static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+{
+	asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
+					   &asd_ha->pcidev->dev,
+					   sizeof(struct scb),
+					   8, 0);
+	if (!asd_ha->scb_pool) {
+		asd_printk("couldn't create scb pool\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * asd_free_edbs -- free empty data buffers
+ * asd_ha: pointer to host adapter structure
+ */
+static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int i;
+
+	for (i = 0; i < seq->num_edbs; i++)
+		asd_free_coherent(asd_ha, seq->edb_arr[i]);
+	kfree(seq->edb_arr);
+	seq->edb_arr = NULL;
+}
+
+static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int i;
+
+	for (i = 0; i < seq->num_escbs; i++) {
+		if (!list_empty(&seq->escb_arr[i]->list))
+			list_del_init(&seq->escb_arr[i]->list);
+
+		asd_ascb_free(seq->escb_arr[i]);
+	}
+	kfree(seq->escb_arr);
+	seq->escb_arr = NULL;
+}
+
+static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+{
+	int i;
+
+	if (asd_ha->hw_prof.ddb_ext)
+		asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);
+	if (asd_ha->hw_prof.scb_ext)
+		asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);
+
+	if (asd_ha->hw_prof.ddb_bitmap)
+		kfree(asd_ha->hw_prof.ddb_bitmap);
+	asd_ha->hw_prof.ddb_bitmap = NULL;
+
+	for (i = 0; i < ASD_MAX_PHYS; i++) {
+		struct asd_phy *phy = &asd_ha->phys[i];
+
+		asd_free_coherent(asd_ha, phy->id_frm_tok);
+	}
+	if (asd_ha->seq.escb_arr)
+		asd_free_escbs(asd_ha);
+	if (asd_ha->seq.edb_arr)
+		asd_free_edbs(asd_ha);
+	if (asd_ha->hw_prof.ue.area) {
+		kfree(asd_ha->hw_prof.ue.area);
+		asd_ha->hw_prof.ue.area = NULL;
+	}
+	if (asd_ha->seq.tc_index_array) {
+		kfree(asd_ha->seq.tc_index_array);
+		kfree(asd_ha->seq.tc_index_bitmap);
+		asd_ha->seq.tc_index_array = NULL;
+		asd_ha->seq.tc_index_bitmap = NULL;
+	}
+	if (asd_ha->seq.actual_dl) {
+			asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);
+			asd_ha->seq.actual_dl = NULL;
+			asd_ha->seq.dl = NULL;
+	}
+	if (asd_ha->seq.next_scb.vaddr) {
+		dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,
+			      asd_ha->seq.next_scb.dma_handle);
+		asd_ha->seq.next_scb.vaddr = NULL;
+	}
+	dma_pool_destroy(asd_ha->scb_pool);
+	asd_ha->scb_pool = NULL;
+}
+
+kmem_cache_t *asd_dma_token_cache;
+kmem_cache_t *asd_ascb_cache;
+
+static int asd_create_global_caches(void)
+{
+	if (!asd_dma_token_cache) {
+		asd_dma_token_cache
+			= kmem_cache_create(ASD_DRIVER_NAME "_dma_token",
+					    sizeof(struct asd_dma_tok),
+					    0,
+					    SLAB_HWCACHE_ALIGN,
+					    NULL, NULL);
+		if (!asd_dma_token_cache) {
+			asd_printk("couldn't create dma token cache\n");
+			return -ENOMEM;
+		}
+	}
+
+	if (!asd_ascb_cache) {
+		asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb",
+						   sizeof(struct asd_ascb),
+						   0,
+						   SLAB_HWCACHE_ALIGN,
+						   NULL, NULL);
+		if (!asd_ascb_cache) {
+			asd_printk("couldn't create ascb cache\n");
+			goto Err;
+		}
+	}
+
+	return 0;
+Err:
+	kmem_cache_destroy(asd_dma_token_cache);
+	asd_dma_token_cache = NULL;
+	return -ENOMEM;
+}
+
+static void asd_destroy_global_caches(void)
+{
+	if (asd_dma_token_cache)
+		kmem_cache_destroy(asd_dma_token_cache);
+	asd_dma_token_cache = NULL;
+
+	if (asd_ascb_cache)
+		kmem_cache_destroy(asd_ascb_cache);
+	asd_ascb_cache = NULL;
+}
+
+static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
+{
+	int i;
+	static struct sas_phy   *sas_phys[ASD_MAX_PHYS];
+	static struct sas_port  *sas_ports[ASD_MAX_PHYS];
+
+	asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name;
+	asd_ha->sas_ha.lldd_module = THIS_MODULE;
+	asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0];
+
+	for (i = 0; i < ASD_MAX_PHYS; i++) {
+		sas_phys[i] = &asd_ha->phys[i].sas_phy;
+		sas_ports[i] = &asd_ha->ports[i];
+	}
+
+	asd_ha->sas_ha.sas_phy = sas_phys;
+	asd_ha->sas_ha.sas_port= sas_ports;
+	asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
+
+	asd_ha->sas_ha.lldd_port_formed = asd_update_port_links;
+
+	asd_ha->sas_ha.lldd_dev_found = asd_dev_found;
+	asd_ha->sas_ha.lldd_dev_gone = asd_dev_gone;
+
+	asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num;
+	asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+	asd_ha->sas_ha.lldd_execute_task = asd_execute_task;
+
+	asd_ha->sas_ha.lldd_abort_task     = asd_abort_task;
+	asd_ha->sas_ha.lldd_abort_task_set = asd_abort_task_set;
+	asd_ha->sas_ha.lldd_clear_aca      = asd_clear_aca;
+	asd_ha->sas_ha.lldd_clear_task_set = asd_clear_task_set;
+	asd_ha->sas_ha.lldd_I_T_nexus_reset= NULL;
+	asd_ha->sas_ha.lldd_lu_reset       = asd_lu_reset;
+	asd_ha->sas_ha.lldd_query_task     = asd_query_task;
+
+	asd_ha->sas_ha.lldd_clear_nexus_port = asd_clear_nexus_port;
+	asd_ha->sas_ha.lldd_clear_nexus_ha = asd_clear_nexus_ha;
+
+	asd_ha->sas_ha.lldd_control_phy = asd_control_phy;
+
+	return sas_register_ha(&asd_ha->sas_ha, &aic94xx_sht);
+}
+
+static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
+{
+	return sas_unregister_ha(&asd_ha->sas_ha);
+}
+
+static int __devinit asd_pci_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct asd_pcidev_struct *asd_dev;
+	unsigned asd_id = (unsigned) id->driver_data;
+	struct asd_ha_struct *asd_ha;
+	int err;
+
+	if (dev->class == (PCI_CLASS_STORAGE_RAID << 8) && !attach_HostRAID) {
+		asd_printk("will not attach to HostRAID enabled device %s, "
+			   "unless attach_HostRAID parameter is set\n",
+			   pci_name(dev));
+		return -ENODEV;
+	}
+
+	if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) {
+		asd_printk("wrong driver_data in PCI table\n");
+		return -ENODEV;
+	}
+
+	if ((err = pci_enable_device(dev))) {
+		asd_printk("couldn't enable device %s\n", pci_name(dev));
+		return err;
+	}
+
+	pci_set_master(dev);
+
+	asd_dev = &asd_pcidev_data[asd_id];
+
+	err = -ENOMEM;
+	asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
+	if (!asd_ha) {
+		asd_printk("out of memory\n");
+		goto Err;
+	}
+	asd_ha->pcidev = dev;
+	asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+	asd_ha->sas_ha.lldd_ha = asd_ha;
+
+	asd_ha->name = asd_dev->name;
+	asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
+	err = asd_dev->setup(asd_ha);
+	if (err)
+		goto Err_free;
+
+	err = -ENODEV;
+	if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
+	    && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
+		;
+	else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
+		 && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
+		;
+	else {
+		asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
+		goto Err_free;
+	}
+
+	pci_set_drvdata(dev, asd_ha);
+
+	err = asd_map_ha(asd_ha);
+	if (err)
+		goto Err_free;
+
+	err = asd_create_ha_caches(asd_ha);
+        if (err)
+		goto Err_unmap;
+
+	err = asd_init_hw(asd_ha);
+	if (err)
+		goto Err_free_cache;
+
+	asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled "
+		   "phys, flash %s, BIOS %s%d\n",
+		   pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr),
+		   asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys,
+		   asd_ha->hw_prof.num_phys,
+		   asd_ha->hw_prof.flash.present ? "present" : "not present",
+		   asd_ha->hw_prof.bios.present ? "build " : "not present",
+		   asd_ha->hw_prof.bios.bld);
+
+	if (use_msi)
+		pci_enable_msi(asd_ha->pcidev);
+
+	err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+			  ASD_DRIVER_NAME, asd_ha);
+	if (err) {
+		asd_printk("couldn't get irq %d for %s\n",
+			   asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
+		goto Err_irq;
+	}
+	asd_enable_ints(asd_ha);
+
+	err = asd_init_post_escbs(asd_ha);
+	if (err) {
+		asd_printk("couldn't post escbs for %s\n",
+			   pci_name(asd_ha->pcidev));
+		goto Err_escbs;
+	}
+	ASD_DPRINTK("escbs posted\n");
+
+	asd_create_dev_attrs(asd_ha);
+
+	err = asd_register_sas_ha(asd_ha);
+	if (err)
+		goto Err_reg_sas;
+
+	err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+	if (err) {
+		asd_printk("coudln't enable phys, err:%d\n", err);
+		goto Err_en_phys;
+	}
+	ASD_DPRINTK("enabled phys\n");
+
+	return 0;
+Err_en_phys:
+	asd_unregister_sas_ha(asd_ha);
+Err_reg_sas:
+	asd_remove_dev_attrs(asd_ha);
+Err_escbs:
+	asd_disable_ints(asd_ha);
+	free_irq(dev->irq, asd_ha);
+Err_irq:
+	if (use_msi)
+		pci_disable_msi(dev);
+	asd_chip_hardrst(asd_ha);
+Err_free_cache:
+	asd_destroy_ha_caches(asd_ha);
+Err_unmap:
+	asd_unmap_ha(asd_ha);
+Err_free:
+	kfree(asd_ha);
+Err:
+	pci_disable_device(dev);
+	return err;
+}
+
+static void asd_free_queues(struct asd_ha_struct *asd_ha)
+{
+	unsigned long flags;
+	LIST_HEAD(pending);
+	struct list_head *n, *pos;
+
+	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+	asd_ha->seq.pending = 0;
+	list_splice_init(&asd_ha->seq.pend_q, &pending);
+	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+	if (!list_empty(&pending))
+		ASD_DPRINTK("Uh-oh! Pending is not empty!\n");
+
+	list_for_each_safe(pos, n, &pending) {
+		struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+		list_del_init(pos);
+		ASD_DPRINTK("freeing from pending\n");
+		asd_ascb_free(ascb);
+	}
+}
+
+static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
+{
+	u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+	u8 i;
+
+	for_each_phy(phy_mask, phy_mask, i) {
+		asd_turn_led(asd_ha, i, 0);
+		asd_control_led(asd_ha, i, 0);
+	}
+}
+
+static void __devexit asd_pci_remove(struct pci_dev *dev)
+{
+	struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
+
+	if (!asd_ha)
+		return;
+
+	asd_unregister_sas_ha(asd_ha);
+
+	asd_disable_ints(asd_ha);
+
+	asd_remove_dev_attrs(asd_ha);
+
+	/* XXX more here as needed */
+
+	free_irq(dev->irq, asd_ha);
+	if (use_msi)
+		pci_disable_msi(asd_ha->pcidev);
+	asd_turn_off_leds(asd_ha);
+	asd_chip_hardrst(asd_ha);
+	asd_free_queues(asd_ha);
+	asd_destroy_ha_caches(asd_ha);
+	asd_unmap_ha(asd_ha);
+	kfree(asd_ha);
+	pci_disable_device(dev);
+	return;
+}
+
+static ssize_t asd_version_show(struct device_driver *driver, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
+}
+static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
+
+static void asd_create_driver_attrs(struct device_driver *driver)
+{
+	driver_create_file(driver, &driver_attr_version);
+}
+
+static void asd_remove_driver_attrs(struct device_driver *driver)
+{
+	driver_remove_file(driver, &driver_attr_version);
+}
+
+static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
+	 0, 0, 1},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
+	 0, 0, 1},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
+	 0, 0, 1},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
+	 0, 0, 2},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
+	 0, 0, 2},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
+	 0, 0, 2},
+	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
+	 0, 0, 2},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);
+
+static struct pci_driver aic94xx_pci_driver = {
+	.name		= ASD_DRIVER_NAME,
+	.id_table	= aic94xx_pci_table,
+	.probe		= asd_pci_probe,
+	.remove		= __devexit_p(asd_pci_remove),
+};
+
+static int __init aic94xx_init(void)
+{
+	int err;
+
+
+	asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION,
+		   ASD_DRIVER_VERSION);
+
+	err = asd_create_global_caches();
+	if (err)
+		return err;
+
+	err = pci_register_driver(&aic94xx_pci_driver);
+	if (!err)
+		asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+
+	return err;
+}
+
+static void __exit aic94xx_exit(void)
+{
+	asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
+	pci_unregister_driver(&aic94xx_pci_driver);
+	asd_destroy_global_caches();
+	asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
+		   ASD_DRIVER_VERSION);
+}
+
+module_init(aic94xx_init);
+module_exit(aic94xx_exit);
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ASD_DRIVER_VERSION);
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_reg.c newtree/drivers/scsi/aic94xx/aic94xx_reg.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_reg.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_reg.c	2006-04-01 05:35:45.903488750 -0500
@@ -0,0 +1,333 @@
+/*
+ * Aic94xx SAS/SATA driver register access.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg.c#14 $
+ */
+
+#include <linux/pci.h>
+#include "aic94xx_reg.h"
+#include "aic94xx.h"
+
+/* Writing to device address space.
+ * Offset comes before value to remind that the operation of
+ * this function is *offs = val.
+ */
+static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
+				  unsigned long offs, u8 val)
+{
+	if (unlikely(asd_ha->iospace))
+		outb(val,
+		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+	else
+		writeb(val, asd_ha->io_handle[0].addr + offs);
+	wmb();
+}
+
+static inline void asd_write_word(struct asd_ha_struct *asd_ha,
+				  unsigned long offs, u16 val)
+{
+	if (unlikely(asd_ha->iospace))
+		outw(val,
+		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+	else
+		writew(val, asd_ha->io_handle[0].addr + offs);
+	wmb();
+}
+
+static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
+				   unsigned long offs, u32 val)
+{
+	if (unlikely(asd_ha->iospace))
+		outl(val,
+		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+	else
+		writel(val, asd_ha->io_handle[0].addr + offs);
+	wmb();
+}
+
+/* Reading from device address space.
+ */
+static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
+			       unsigned long offs)
+{
+	u8 val;
+	if (unlikely(asd_ha->iospace))
+		val = inb((unsigned long) asd_ha->io_handle[0].addr
+			  + (offs & 0xFF));
+	else
+		val = readb(asd_ha->io_handle[0].addr + offs);
+	rmb();
+	return val;
+}
+
+static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
+				unsigned long offs)
+{
+	u16 val;
+	if (unlikely(asd_ha->iospace))
+		val = inw((unsigned long)asd_ha->io_handle[0].addr
+			  + (offs & 0xFF));
+	else
+		val = readw(asd_ha->io_handle[0].addr + offs);
+	rmb();
+	return val;
+}
+
+static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
+				 unsigned long offs)
+{
+	u32 val;
+	if (unlikely(asd_ha->iospace))
+		val = inl((unsigned long) asd_ha->io_handle[0].addr
+			  + (offs & 0xFF));
+	else
+		val = readl(asd_ha->io_handle[0].addr + offs);
+	rmb();
+	return val;
+}
+
+static inline u32 asd_mem_offs_swa(void)
+{
+	return 0;
+}
+
+static inline u32 asd_mem_offs_swc(void)
+{
+	return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
+}
+
+static inline u32 asd_mem_offs_swb(void)
+{
+	return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
+}
+
+/* We know that the register wanted is in the range
+ * of the sliding window.
+ */
+#define ASD_READ_SW(ww, type, ord)                                     \
+static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+					  u32 reg)                     \
+{                                                                      \
+	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];    \
+	u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+	return asd_read_##ord (asd_ha, (unsigned long) map_offs);      \
+}
+
+#define ASD_WRITE_SW(ww, type, ord)                                    \
+static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+				  u32 reg, type val)                   \
+{                                                                      \
+	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];    \
+	u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+	asd_write_##ord (asd_ha, (unsigned long) map_offs, val);       \
+}
+
+ASD_READ_SW(swa, u8,  byte);
+ASD_READ_SW(swa, u16, word);
+ASD_READ_SW(swa, u32, dword);
+
+ASD_READ_SW(swb, u8,  byte);
+ASD_READ_SW(swb, u16, word);
+ASD_READ_SW(swb, u32, dword);
+
+ASD_READ_SW(swc, u8,  byte);
+ASD_READ_SW(swc, u16, word);
+ASD_READ_SW(swc, u32, dword);
+
+ASD_WRITE_SW(swa, u8,  byte);
+ASD_WRITE_SW(swa, u16, word);
+ASD_WRITE_SW(swa, u32, dword);
+
+ASD_WRITE_SW(swb, u8,  byte);
+ASD_WRITE_SW(swb, u16, word);
+ASD_WRITE_SW(swb, u32, dword);
+
+ASD_WRITE_SW(swc, u8,  byte);
+ASD_WRITE_SW(swc, u16, word);
+ASD_WRITE_SW(swc, u32, dword);
+
+/*
+ * A word about sliding windows:
+ * MBAR0 is divided into sliding windows A, C and B, in that order.
+ * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
+ * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
+ * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
+ * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
+ * See asd_init_sw() in aic94xx_hwi.c
+ *
+ * We map the most common registers we'd access of the internal 4GB
+ * host adapter memory space.  If a register/internal memory location
+ * is wanted which is not mapped, we slide SWB, by paging it,
+ * see asd_move_swb() in aic94xx_reg.c.
+ */
+
+/**
+ * asd_move_swb -- move sliding window B
+ * @asd_ha: pointer to host adapter structure
+ * @reg: register desired to be within range of the new window
+ */
+static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
+{
+	u32 base = reg & ~(MBAR0_SWB_SIZE-1);
+	pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
+	asd_ha->io_handle[0].swb_base = base;
+}
+
+static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
+{
+	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+	if (io_handle->swa_base <= reg
+	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+		asd_write_swa_byte (asd_ha, reg,val);
+	else if (io_handle->swb_base <= reg
+		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+		asd_write_swb_byte (asd_ha, reg, val);
+	else if (io_handle->swc_base <= reg
+		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+		asd_write_swc_byte (asd_ha, reg, val);
+	else {
+		/* Ok, we have to move SWB */
+		asd_move_swb(asd_ha, reg);
+		asd_write_swb_byte (asd_ha, reg, val);
+	}
+}
+
+#define ASD_WRITE_REG(type, ord)                                  \
+void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
+{                                                                 \
+	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+	unsigned long flags;                                      \
+	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
+	spin_lock_irqsave(&asd_ha->iolock, flags);                \
+	if (io_handle->swa_base <= reg                            \
+	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
+		asd_write_swa_##ord (asd_ha, reg,val);            \
+	else if (io_handle->swb_base <= reg                       \
+		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
+		asd_write_swb_##ord (asd_ha, reg, val);           \
+	else if (io_handle->swc_base <= reg                       \
+		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
+		asd_write_swc_##ord (asd_ha, reg, val);           \
+	else {                                                    \
+		/* Ok, we have to move SWB */                     \
+		asd_move_swb(asd_ha, reg);                        \
+		asd_write_swb_##ord (asd_ha, reg, val);           \
+	}                                                         \
+	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
+}
+
+ASD_WRITE_REG(u8, byte);
+ASD_WRITE_REG(u16,word);
+ASD_WRITE_REG(u32,dword);
+
+static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
+{
+	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+	u8 val;
+	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+	if (io_handle->swa_base <= reg
+	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+		val = asd_read_swa_byte (asd_ha, reg);
+	else if (io_handle->swb_base <= reg
+		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+		val = asd_read_swb_byte (asd_ha, reg);
+	else if (io_handle->swc_base <= reg
+		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+		val = asd_read_swc_byte (asd_ha, reg);
+	else {
+		/* Ok, we have to move SWB */
+		asd_move_swb(asd_ha, reg);
+		val = asd_read_swb_byte (asd_ha, reg);
+	}
+	return val;
+}
+
+#define ASD_READ_REG(type, ord)                                   \
+type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
+{                                                                 \
+	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+	type val;                                                 \
+	unsigned long flags;                                      \
+	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
+	spin_lock_irqsave(&asd_ha->iolock, flags);                \
+	if (io_handle->swa_base <= reg                            \
+	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
+		val = asd_read_swa_##ord (asd_ha, reg);           \
+	else if (io_handle->swb_base <= reg                       \
+		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
+		val = asd_read_swb_##ord (asd_ha, reg);           \
+	else if (io_handle->swc_base <= reg                       \
+		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
+		val = asd_read_swc_##ord (asd_ha, reg);           \
+	else {                                                    \
+		/* Ok, we have to move SWB */                     \
+		asd_move_swb(asd_ha, reg);                        \
+		val = asd_read_swb_##ord (asd_ha, reg);           \
+	}                                                         \
+	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
+	return val;                                               \
+}
+
+ASD_READ_REG(u8, byte);
+ASD_READ_REG(u16,word);
+ASD_READ_REG(u32,dword);
+
+/**
+ * asd_read_reg_string -- read a string of bytes from io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @dst: pointer to a destination buffer where data will be written to
+ * @offs: start offset (register) to read from
+ * @count: number of bytes to read
+ */
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+			 u32 offs, int count)
+{
+	u8 *p = dst;
+	unsigned long flags;
+
+	spin_lock_irqsave(&asd_ha->iolock, flags);
+	for ( ; count > 0; count--, offs++, p++)
+		*p = __asd_read_reg_byte(asd_ha, offs);
+	spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
+
+/**
+ * asd_write_reg_string -- write a string of bytes to io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @src: pointer to source buffer where data will be read from
+ * @offs: start offset (register) to write to
+ * @count: number of bytes to write
+ */
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+			  u32 offs, int count)
+{
+	u8 *p = src;
+	unsigned long flags;
+
+	spin_lock_irqsave(&asd_ha->iolock, flags);
+	for ( ; count > 0; count--, offs++, p++)
+		__asd_write_reg_byte(asd_ha, offs, *p);
+	spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_reg.h newtree/drivers/scsi/aic94xx/aic94xx_reg.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_reg.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_reg.h	2006-04-01 05:35:45.907489000 -0500
@@ -0,0 +1,303 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers definitions.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg.h#19 $
+ */
+
+#ifndef _AIC94XX_REG_H_
+#define _AIC94XX_REG_H_
+
+#include <asm/io.h>
+#include "aic94xx_hwi.h"
+
+/* Values */
+#define AIC9410_DEV_REV_B0            0x8
+
+/* MBAR0, SWA, SWB, SWC, internal memory space addresses */
+#define REG_BASE_ADDR                 0xB8000000
+#define REG_BASE_ADDR_CSEQCIO         0xB8002000
+#define REG_BASE_ADDR_EXSI            0xB8042800
+
+#define MBAR0_SWA_SIZE                0x58
+extern  u32    MBAR0_SWB_SIZE;
+#define MBAR0_SWC_SIZE                0x8
+
+/* MBAR1, points to On Chip Memory */
+#define OCM_BASE_ADDR                 0xA0000000
+#define OCM_MAX_SIZE                  0x20000
+
+/* Smallest address possible to reference */
+#define ALL_BASE_ADDR                 OCM_BASE_ADDR
+
+/* PCI configuration space registers */
+#define PCI_IOBAR_OFFSET              4
+
+#define PCI_CONF_MBAR1                0x6C
+#define PCI_CONF_MBAR0_SWA            0x70
+#define PCI_CONF_MBAR0_SWB            0x74
+#define PCI_CONF_MBAR0_SWC            0x78
+#define PCI_CONF_MBAR_KEY             0x7C
+#define PCI_CONF_FLSH_BAR             0xB8
+
+#include "aic94xx_reg_def.h"
+
+u8  asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg);
+u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg);
+u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg);
+
+void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val);
+void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val);
+void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val);
+
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+			 u32 offs, int count);
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+			  u32 offs, int count);
+
+#define ASD_READ_OCM(type, ord, S)                                    \
+static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha,  \
+					 u32 offs)                    \
+{                                                                     \
+	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1];   \
+	type val = read##S (io_handle->addr + (unsigned long) offs);  \
+	rmb();                                                        \
+	return val;                                                   \
+}
+
+ASD_READ_OCM(u8, byte, b);
+ASD_READ_OCM(u16,word, w);
+ASD_READ_OCM(u32,dword,l);
+
+#define ASD_WRITE_OCM(type, ord, S)                                    \
+static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha,  \
+					 u32 offs, type val)          \
+{                                                                     \
+	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1];   \
+	write##S (val, io_handle->addr + (unsigned long) offs);       \
+	return;                                                       \
+}
+
+ASD_WRITE_OCM(u8, byte, b);
+ASD_WRITE_OCM(u16,word, w);
+ASD_WRITE_OCM(u32,dword,l);
+
+#define ASD_DDBSITE_READ(type, ord)                                        \
+static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha,   \
+					   u16 ddb_site_no,                \
+					   u16 offs)                       \
+{                                                                          \
+	asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs);          \
+	asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no);                  \
+	return asd_read_reg_##ord (asd_ha, CTXACCESS);                     \
+}
+
+ASD_DDBSITE_READ(u32, dword);
+ASD_DDBSITE_READ(u16, word);
+
+static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha,
+				       u16 ddb_site_no,
+				       u16 offs)
+{
+	if (offs & 1)
+		return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+					     offs & ~1) >> 8;
+	else
+		return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+					     offs) & 0xFF;
+}
+
+
+#define ASD_DDBSITE_WRITE(type, ord)                                       \
+static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha,  \
+					u16 ddb_site_no,                   \
+					u16 offs, type val)                \
+{                                                                          \
+	asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs);          \
+	asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no);                  \
+	asd_write_reg_##ord (asd_ha, CTXACCESS, val);                      \
+}
+
+ASD_DDBSITE_WRITE(u32, dword);
+ASD_DDBSITE_WRITE(u16, word);
+
+static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha,
+					  u16 ddb_site_no,
+					  u16 offs, u8 val)
+{
+	u16 base = offs & ~1;
+	u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+	if (offs & 1)
+		rval = (val << 8) | (rval & 0xFF);
+	else
+		rval = (rval & 0xFF00) | val;
+	asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval);
+}
+
+
+#define ASD_SCBSITE_READ(type, ord)                                        \
+static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha,   \
+					   u16 scb_site_no,                \
+					   u16 offs)                       \
+{                                                                          \
+	asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs);          \
+	asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no);                  \
+	return asd_read_reg_##ord (asd_ha, CTXACCESS);                     \
+}
+
+ASD_SCBSITE_READ(u32, dword);
+ASD_SCBSITE_READ(u16, word);
+
+static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha,
+				       u16 scb_site_no,
+				       u16 offs)
+{
+	if (offs & 1)
+		return asd_scbsite_read_word(asd_ha, scb_site_no,
+					     offs & ~1) >> 8;
+	else
+		return asd_scbsite_read_word(asd_ha, scb_site_no,
+					     offs) & 0xFF;
+}
+
+
+#define ASD_SCBSITE_WRITE(type, ord)                                       \
+static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha,  \
+					u16 scb_site_no,                   \
+					u16 offs, type val)                \
+{                                                                          \
+	asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs);          \
+	asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no);                  \
+	asd_write_reg_##ord (asd_ha, CTXACCESS, val);                      \
+}
+
+ASD_SCBSITE_WRITE(u32, dword);
+ASD_SCBSITE_WRITE(u16, word);
+
+static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha,
+					  u16 scb_site_no,
+					  u16 offs, u8 val)
+{
+	u16 base = offs & ~1;
+	u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base);
+	if (offs & 1)
+		rval = (val << 8) | (rval & 0xFF);
+	else
+		rval = (rval & 0xFF00) | val;
+	asd_scbsite_write_word(asd_ha, scb_site_no, base, rval);
+}
+
+/**
+ * asd_ddbsite_update_word -- atomically update a word in a ddb site
+ * @asd_ha: pointer to host adapter structure
+ * @ddb_site_no: the DDB site number
+ * @offs: the offset into the DDB
+ * @oldval: old value found in that offset
+ * @newval: the new value to replace it
+ *
+ * This function is used when the sequencers are running and we need to
+ * update a DDB site atomically without expensive pausing and upausing
+ * of the sequencers and accessing the DDB site through the CIO bus.
+ *
+ * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value
+ * is different than the current value at that offset.
+ */
+static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha,
+					  u16 ddb_site_no, u16 offs,
+					  u16 oldval, u16 newval)
+{
+	u8  done;
+	u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs);
+	if (oval != oldval)
+		return -EAGAIN;
+	asd_write_reg_word(asd_ha, AOLDDATA, oldval);
+	asd_write_reg_word(asd_ha, ANEWDATA, newval);
+	do {
+		done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL);
+	} while (!(done & ATOMICDONE));
+	if (done & ATOMICERR)
+		return -EFAULT;	  /* parity error */
+	else if (done & ATOMICWIN)
+		return 0;	  /* success */
+	else
+		return -EAGAIN;	  /* oldval different than current value */
+}
+
+static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha,
+					  u16 ddb_site_no, u16 offs,
+					  u8 _oldval, u8 _newval)
+{
+	u16 base = offs & ~1;
+	u16 oval;
+	u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+	if (offs & 1) {
+		if ((nval >> 8) != _oldval)
+			return -EAGAIN;
+		nval = (_newval << 8) | (nval & 0xFF);
+		oval = (_oldval << 8) | (nval & 0xFF);
+	} else {
+		if ((nval & 0xFF) != _oldval)
+			return -EAGAIN;
+		nval = (nval & 0xFF00) | _newval;
+		oval = (nval & 0xFF00) | _oldval;
+	}
+	return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval);
+}
+
+static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg,
+				      dma_addr_t dma_handle)
+{
+	asd_write_reg_dword(asd_ha, reg,   ASD_BUSADDR_LO(dma_handle));
+	asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle));
+}
+
+static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha)
+{
+	/* DCHREVISION returns 0, possibly broken */
+	u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+	return ctxmemsize ? 65536 : 32768;
+}
+
+static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha)
+{
+	u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+	return ctxmemsize ? 8192 : 4096;
+}
+
+static inline void asd_disable_ints(struct asd_ha_struct *asd_ha)
+{
+	asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+}
+
+static inline void asd_enable_ints(struct asd_ha_struct *asd_ha)
+{
+	/* Enable COM SAS interrupt on errors, COMSTAT */
+	asd_write_reg_dword(asd_ha, COMSTATEN,
+			    EN_CSBUFPERR | EN_CSERR | EN_OVLYERR);
+	/* Enable DCH SAS CFIFTOERR */
+	asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR);
+	/* Enable Host Device interrupts */
+	asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN);
+}
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_reg_def.h newtree/drivers/scsi/aic94xx/aic94xx_reg_def.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_reg_def.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_reg_def.h	2006-04-01 05:35:45.903488750 -0500
@@ -0,0 +1,2399 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers defintions.
+ *
+ * Copyright (C) 2004 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Luben Tuikov: Some register value updates to make it work with the window
+ * agnostic register r/w functions.  Some register corrections, sizes,
+ * etc.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
+ *
+ */
+
+#ifndef _ADP94XX_REG_DEF_H_
+#define _ADP94XX_REG_DEF_H_
+
+/*
+ * Common definitions.
+ */
+#define CSEQ_MODE_PAGE_SIZE	0x200		/* CSEQ mode page size */
+#define LmSEQ_MODE_PAGE_SIZE	0x200		/* LmSEQ mode page size */
+#define LmSEQ_HOST_REG_SIZE   	0x4000		/* LmSEQ Host Register size */
+
+/********************* COM_SAS registers definition *************************/
+
+/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h.
+ */
+
+/*
+ * CHIM Registers, Address Range : (0x00-0xFF)
+ */
+#define COMBIST		(REG_BASE_ADDR + 0x00)
+
+/* bits 31:24 */
+#define		L7BLKRST		0x80000000
+#define		L6BLKRST		0x40000000
+#define		L5BLKRST		0x20000000
+#define		L4BLKRST		0x10000000
+#define		L3BLKRST		0x08000000
+#define		L2BLKRST		0x04000000
+#define		L1BLKRST		0x02000000
+#define		L0BLKRST		0x01000000
+#define		LmBLKRST		0xFF000000
+#define LmBLKRST_COMBIST(phyid)		(1 << (24 + phyid))
+
+#define		OCMBLKRST		0x00400000
+#define		CTXMEMBLKRST		0x00200000
+#define		CSEQBLKRST		0x00100000
+#define		EXSIBLKRST		0x00040000
+#define		DPIBLKRST		0x00020000
+#define		DFIFBLKRST		0x00010000
+#define		HARDRST			0x00000200
+#define		COMBLKRST		0x00000100
+#define		FRCDFPERR		0x00000080
+#define		FRCCIOPERR		0x00000020
+#define		FRCBISTERR		0x00000010
+#define		COMBISTEN		0x00000004
+#define		COMBISTDONE		0x00000002	/* ro */
+#define 	COMBISTFAIL		0x00000001	/* ro */
+
+#define COMSTAT		(REG_BASE_ADDR + 0x04)
+
+#define		REQMBXREAD		0x00000040
+#define 	RSPMBXAVAIL		0x00000020
+#define 	CSBUFPERR		0x00000008
+#define		OVLYERR			0x00000004
+#define 	CSERR			0x00000002
+#define		OVLYDMADONE		0x00000001
+
+#define		COMSTAT_MASK		(REQMBXREAD | RSPMBXAVAIL | \
+					 CSBUFPERR | OVLYERR | CSERR |\
+					 OVLYDMADONE)
+
+#define COMSTATEN	(REG_BASE_ADDR + 0x08)
+
+#define		EN_REQMBXREAD		0x00000040
+#define		EN_RSPMBXAVAIL		0x00000020
+#define		EN_CSBUFPERR		0x00000008
+#define		EN_OVLYERR		0x00000004
+#define		EN_CSERR		0x00000002
+#define		EN_OVLYDONE		0x00000001
+
+#define SCBPRO		(REG_BASE_ADDR + 0x0C)
+
+#define		SCBCONS_MASK		0xFFFF0000
+#define		SCBPRO_MASK		0x0000FFFF
+
+#define CHIMREQMBX	(REG_BASE_ADDR + 0x10)
+
+#define CHIMRSPMBX	(REG_BASE_ADDR + 0x14)
+
+#define CHIMINT		(REG_BASE_ADDR + 0x18)
+
+#define		EXT_INT0		0x00000800
+#define		EXT_INT1		0x00000400
+#define		PORRSTDET		0x00000200
+#define		HARDRSTDET		0x00000100
+#define		DLAVAILQ		0x00000080	/* ro */
+#define		HOSTERR			0x00000040
+#define		INITERR			0x00000020
+#define		DEVINT			0x00000010
+#define		COMINT			0x00000008
+#define		DEVTIMER2		0x00000004
+#define		DEVTIMER1		0x00000002
+#define		DLAVAIL			0x00000001
+
+#define		CHIMINT_MASK		(HOSTERR | INITERR | DEVINT | COMINT |\
+					 DEVTIMER2 | DEVTIMER1 | DLAVAIL)
+
+#define 	DEVEXCEPT_MASK		(HOSTERR | INITERR | DEVINT | COMINT)
+
+#define CHIMINTEN	(REG_BASE_ADDR + 0x1C)
+
+#define		RST_EN_EXT_INT1		0x01000000
+#define		RST_EN_EXT_INT0		0x00800000
+#define		RST_EN_HOSTERR		0x00400000
+#define		RST_EN_INITERR		0x00200000
+#define		RST_EN_DEVINT		0x00100000
+#define		RST_EN_COMINT		0x00080000
+#define		RST_EN_DEVTIMER2	0x00040000
+#define		RST_EN_DEVTIMER1	0x00020000
+#define		RST_EN_DLAVAIL		0x00010000
+#define		SET_EN_EXT_INT1		0x00000100
+#define		SET_EN_EXT_INT0		0x00000080
+#define		SET_EN_HOSTERR		0x00000040
+#define		SET_EN_INITERR		0x00000020
+#define		SET_EN_DEVINT		0x00000010
+#define		SET_EN_COMINT		0x00000008
+#define		SET_EN_DEVTIMER2	0x00000004
+#define		SET_EN_DEVTIMER1	0x00000002
+#define		SET_EN_DLAVAIL		0x00000001
+
+#define		RST_CHIMINTEN		(RST_EN_HOSTERR | RST_EN_INITERR | \
+					 RST_EN_DEVINT | RST_EN_COMINT | \
+					 RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\
+					 RST_EN_DLAVAIL)
+
+#define		SET_CHIMINTEN		(SET_EN_HOSTERR | SET_EN_INITERR |\
+					 SET_EN_DEVINT | SET_EN_COMINT |\
+					 SET_EN_DLAVAIL)
+
+#define OVLYDMACTL	(REG_BASE_ADDR + 0x20)
+
+#define		OVLYADR_MASK		0x07FF0000
+#define		OVLYLSEQ_MASK		0x0000FF00
+#define		OVLYCSEQ		0x00000080
+#define		OVLYHALTERR		0x00000040
+#define		PIOCMODE		0x00000020
+#define		RESETOVLYDMA		0x00000008	/* wo */
+#define		STARTOVLYDMA		0x00000004
+#define		STOPOVLYDMA		0x00000002	/* wo */
+#define		OVLYDMAACT		0x00000001	/* ro */
+
+#define OVLYDMACNT	(REG_BASE_ADDR + 0x24)
+
+#define		OVLYDOMAIN1		0x20000000	/* ro */
+#define		OVLYDOMAIN0		0x10000000
+#define		OVLYBUFADR_MASK		0x007F0000
+#define		OVLYDMACNT_MASK		0x00003FFF
+
+#define OVLYDMAADR	(REG_BASE_ADDR + 0x28)
+
+#define DMAERR		(REG_BASE_ADDR + 0x30)
+
+#define		OVLYERRSTAT_MASK	0x0000FF00	/* ro */
+#define		CSERRSTAT_MASK		0x000000FF	/* ro */
+
+#define SPIODATA	(REG_BASE_ADDR + 0x34)
+
+/* 0x38 - 0x3C are reserved  */
+
+#define T1CNTRLR	(REG_BASE_ADDR + 0x40)
+
+#define		T1DONE			0x00010000	/* ro */
+#define		TIMER64			0x00000400
+#define		T1ENABLE		0x00000200
+#define		T1RELOAD		0x00000100
+#define		T1PRESCALER_MASK	0x00000003
+
+#define	T1CMPR		(REG_BASE_ADDR + 0x44)
+
+#define T1CNTR		(REG_BASE_ADDR + 0x48)
+
+#define T2CNTRLR	(REG_BASE_ADDR + 0x4C)
+
+#define		T2DONE			0x00010000	/* ro */
+#define		T2ENABLE		0x00000200
+#define		T2RELOAD		0x00000100
+#define		T2PRESCALER_MASK	0x00000003
+
+#define	T2CMPR		(REG_BASE_ADDR + 0x50)
+
+#define T2CNTR		(REG_BASE_ADDR + 0x54)
+
+/* 0x58h - 0xFCh are reserved */
+
+/*
+ * DCH_SAS Registers, Address Range : (0x800-0xFFF)
+ */
+#define CMDCTXBASE	(REG_BASE_ADDR + 0x800)
+
+#define DEVCTXBASE	(REG_BASE_ADDR + 0x808)
+
+#define CTXDOMAIN	(REG_BASE_ADDR + 0x810)
+
+#define		DEVCTXDOMAIN1		0x00000008	/* ro */
+#define		DEVCTXDOMAIN0		0x00000004
+#define		CMDCTXDOMAIN1		0x00000002	/* ro */
+#define		CMDCTXDOMAIN0		0x00000001
+
+#define DCHCTL		(REG_BASE_ADDR + 0x814)
+
+#define		OCMBISTREPAIR		0x00080000
+#define		OCMBISTEN		0x00040000
+#define		OCMBISTDN		0x00020000	/* ro */
+#define		OCMBISTFAIL		0x00010000	/* ro */
+#define		DDBBISTEN		0x00004000
+#define		DDBBISTDN		0x00002000	/* ro */
+#define		DDBBISTFAIL		0x00001000	/* ro */
+#define		SCBBISTEN		0x00000400
+#define		SCBBISTDN		0x00000200	/* ro */
+#define		SCBBISTFAIL		0x00000100	/* ro */
+
+#define		MEMSEL_MASK		0x000000E0
+#define		MEMSEL_CCM_LSEQ		0x00000000
+#define		MEMSEL_CCM_IOP		0x00000020
+#define		MEMSEL_CCM_SASCTL	0x00000040
+#define		MEMSEL_DCM_LSEQ		0x00000060
+#define		MEMSEL_DCM_IOP		0x00000080
+#define		MEMSEL_OCM		0x000000A0
+
+#define		FRCERR			0x00000010
+#define		AUTORLS			0x00000001
+
+#define DCHREVISION	(REG_BASE_ADDR + 0x818)
+
+#define		DCHREVISION_MASK	0x000000FF
+
+#define DCHSTATUS	(REG_BASE_ADDR + 0x81C)
+
+#define		EN_CFIFTOERR		0x00020000
+#define		CFIFTOERR		0x00000200
+#define		CSEQINT			0x00000100	/* ro */
+#define		LSEQ7INT		0x00000080	/* ro */
+#define		LSEQ6INT		0x00000040	/* ro */
+#define		LSEQ5INT		0x00000020	/* ro */
+#define		LSEQ4INT		0x00000010	/* ro */
+#define		LSEQ3INT		0x00000008	/* ro */
+#define		LSEQ2INT		0x00000004	/* ro */
+#define		LSEQ1INT		0x00000002	/* ro */
+#define		LSEQ0INT		0x00000001	/* ro */
+
+#define		LSEQINT_MASK		(LSEQ7INT | LSEQ6INT | LSEQ5INT |\
+					 LSEQ4INT | LSEQ3INT | LSEQ2INT	|\
+					 LSEQ1INT | LSEQ0INT)
+
+#define DCHDFIFDEBUG	(REG_BASE_ADDR + 0x820)
+#define		ENFAIRMST		0x00FF0000
+#define		DISWRMST9		0x00000200
+#define		DISWRMST8		0x00000100
+#define		DISRDMST		0x000000FF
+
+#define ATOMICSTATCTL	(REG_BASE_ADDR + 0x824)
+/* 8 bit wide */
+#define		AUTOINC			0x80
+#define		ATOMICERR		0x04
+#define		ATOMICWIN		0x02
+#define		ATOMICDONE		0x01
+
+
+#define ALTCIOADR	(REG_BASE_ADDR + 0x828)
+/* 16 bit; bits 8:0 define CIO addr space of CSEQ */
+
+#define ASCBPTR		(REG_BASE_ADDR + 0x82C)
+/* 16 bit wide */
+
+#define ADDBPTR		(REG_BASE_ADDR + 0x82E)
+/* 16 bit wide */
+
+#define ANEWDATA	(REG_BASE_ADDR + 0x830)
+/* 16 bit */
+
+#define AOLDDATA	(REG_BASE_ADDR + 0x834)
+/* 16 bit */
+
+#define CTXACCESS	(REG_BASE_ADDR + 0x838)
+/* 32 bit */
+
+/* 0x83Ch - 0xFFCh are reserved */
+
+/*
+ * ARP2 External Processor Registers, Address Range : (0x00-0x1F)
+ */
+#define ARP2CTL		0x00
+
+#define		FRCSCRPERR		0x00040000
+#define		FRCARP2PERR		0x00020000
+#define		FRCARP2ILLOPC		0x00010000
+#define		ENWAITTO		0x00008000
+#define		PERRORDIS		0x00004000
+#define		FAILDIS			0x00002000
+#define		CIOPERRDIS		0x00001000
+#define		BREAKEN3		0x00000800
+#define		BREAKEN2		0x00000400
+#define		BREAKEN1		0x00000200
+#define		BREAKEN0		0x00000100
+#define		EPAUSE			0x00000008
+#define		PAUSED			0x00000004	/* ro */
+#define		STEP			0x00000002
+#define		ARP2RESET		0x00000001	/* wo */
+
+#define ARP2INT		0x04
+
+#define		HALTCODE_MASK		0x00FF0000	/* ro */
+#define		ARP2WAITTO		0x00000100
+#define		ARP2HALTC		0x00000080
+#define		ARP2ILLOPC		0x00000040
+#define		ARP2PERR		0x00000020
+#define		ARP2CIOPERR		0x00000010
+#define		ARP2BREAK3		0x00000008
+#define		ARP2BREAK2		0x00000004
+#define		ARP2BREAK1		0x00000002
+#define		ARP2BREAK0		0x00000001
+
+#define ARP2INTEN	0x08
+
+#define		EN_ARP2WAITTO		0x00000100
+#define		EN_ARP2HALTC		0x00000080
+#define		EN_ARP2ILLOPC		0x00000040
+#define		EN_ARP2PERR		0x00000020
+#define		EN_ARP2CIOPERR		0x00000010
+#define		EN_ARP2BREAK3		0x00000008
+#define		EN_ARP2BREAK2		0x00000004
+#define		EN_ARP2BREAK1		0x00000002
+#define		EN_ARP2BREAK0		0x00000001
+
+#define ARP2BREAKADR01	0x0C
+
+#define		BREAKADR1_MASK		0x0FFF0000
+#define		BREAKADR0_MASK		0x00000FFF
+
+#define	ARP2BREAKADR23	0x10
+
+#define		BREAKADR3_MASK		0x0FFF0000
+#define		BREAKADR2_MASK		0x00000FFF
+
+/* 0x14h - 0x1Ch are reserved */
+
+/*
+ * ARP2 Registers, Address Range : (0x00-0x1F)
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MODEPTR		0x00
+
+#define		DSTMODE			0xF0
+#define		SRCMODE			0x0F
+
+#define ALTMODE		0x01
+
+#define		ALTDMODE		0xF0
+#define		ALTSMODE		0x0F
+
+#define ATOMICXCHG	0x02
+
+#define FLAG		0x04
+
+#define		INTCODE_MASK		0xF0
+#define		ALTMODEV2		0x04
+#define		CARRY_INT		0x02
+#define		CARRY			0x01
+
+#define ARP2INTCTL	0x05
+
+#define 	PAUSEDIS		0x80
+#define		RSTINTCTL		0x40
+#define		POPALTMODE		0x08
+#define		ALTMODEV		0x04
+#define		INTMASK			0x02
+#define		IRET			0x01
+
+#define STACK		0x06
+
+#define FUNCTION1	0x07
+
+#define PRGMCNT		0x08
+
+#define ACCUM		0x0A
+
+#define SINDEX		0x0C
+
+#define DINDEX		0x0E
+
+#define ALLONES		0x10
+
+#define ALLZEROS	0x11
+
+#define SINDIR		0x12
+
+#define DINDIR		0x13
+
+#define JUMLDIR		0x14
+
+#define ARP2HALTCODE	0x15
+
+#define CURRADDR	0x16
+
+#define LASTADDR	0x18
+
+#define NXTLADDR	0x1A
+
+#define DBGPORTPTR	0x1C
+
+#define DBGPORT		0x1D
+
+/*
+ * CIO Registers.
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MnSCBPTR      	0x20
+
+#define MnDDBPTR      	0x22
+
+#define SCRATCHPAGE	0x24
+
+#define MnSCRATCHPAGE	0x25
+
+#define SCRATCHPAGESV	0x26
+
+#define MnSCRATCHPAGESV	0x27
+
+#define MnDMAERRS	0x46
+
+#define MnSGDMAERRS	0x47
+
+#define MnSGBUF		0x53
+
+#define MnSGDMASTAT	0x5b
+
+#define MnDDMACTL	0x5c	/* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMASTAT	0x5d	/* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMAMODE	0x5e	/* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDMAENG	0x60
+
+#define MnPIPECTL	0x61
+
+#define MnSGBADR	0x65
+
+#define MnSCB_SITE	0x100
+
+#define MnDDB_SITE	0x180
+
+/*
+ * The common definitions below have the same address offset for both
+ * CSEQ and LmSEQ.
+ */
+#define BISTCTL0	0x4C
+
+#define BISTCTL1	0x50
+
+#define MAPPEDSCR	0x800
+
+/*
+ * CSEQ Host Register, Address Range : (0x000-0xFFC)
+ */
+#define CSEQ_HOST_REG_BASE_ADR		0xB8001000
+
+#define CARP2CTL			(CSEQ_HOST_REG_BASE_ADR	+ ARP2CTL)
+
+#define CARP2INT			(CSEQ_HOST_REG_BASE_ADR	+ ARP2INT)
+
+#define CARP2INTEN			(CSEQ_HOST_REG_BASE_ADR	+ ARP2INTEN)
+
+#define CARP2BREAKADR01			(CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01)
+
+#define CARP2BREAKADR23			(CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23)
+
+#define CBISTCTL			(CSEQ_HOST_REG_BASE_ADR	+ BISTCTL1)
+
+#define		CSEQRAMBISTEN		0x00000040
+#define		CSEQRAMBISTDN		0x00000020	/* ro */
+#define		CSEQRAMBISTFAIL		0x00000010	/* ro */
+#define		CSEQSCRBISTEN		0x00000004
+#define		CSEQSCRBISTDN		0x00000002	/* ro */
+#define		CSEQSCRBISTFAIL		0x00000001	/* ro */
+
+#define CMAPPEDSCR			(CSEQ_HOST_REG_BASE_ADR	+ MAPPEDSCR)
+
+/*
+ * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC)
+ * 16 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define CSEQ_CIO_REG_BASE_ADR		REG_BASE_ADDR_CSEQCIO
+
+#define CSEQm_CIO_REG(Mode, Reg) \
+		(CSEQ_CIO_REG_BASE_ADR  + \
+		((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg))
+
+#define CMODEPTR	(CSEQ_CIO_REG_BASE_ADR + MODEPTR)
+
+#define CALTMODE	(CSEQ_CIO_REG_BASE_ADR + ALTMODE)
+
+#define CATOMICXCHG	(CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG)
+
+#define CFLAG		(CSEQ_CIO_REG_BASE_ADR + FLAG)
+
+#define CARP2INTCTL	(CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL)
+
+#define CSTACK		(CSEQ_CIO_REG_BASE_ADR + STACK)
+
+#define CFUNCTION1	(CSEQ_CIO_REG_BASE_ADR + FUNCTION1)
+
+#define CPRGMCNT	(CSEQ_CIO_REG_BASE_ADR + PRGMCNT)
+
+#define CACCUM		(CSEQ_CIO_REG_BASE_ADR + ACCUM)
+
+#define CSINDEX		(CSEQ_CIO_REG_BASE_ADR + SINDEX)
+
+#define CDINDEX		(CSEQ_CIO_REG_BASE_ADR + DINDEX)
+
+#define CALLONES	(CSEQ_CIO_REG_BASE_ADR + ALLONES)
+
+#define CALLZEROS	(CSEQ_CIO_REG_BASE_ADR + ALLZEROS)
+
+#define CSINDIR		(CSEQ_CIO_REG_BASE_ADR + SINDIR)
+
+#define CDINDIR		(CSEQ_CIO_REG_BASE_ADR + DINDIR)
+
+#define CJUMLDIR	(CSEQ_CIO_REG_BASE_ADR + JUMLDIR)
+
+#define CARP2HALTCODE	(CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE)
+
+#define CCURRADDR	(CSEQ_CIO_REG_BASE_ADR + CURRADDR)
+
+#define CLASTADDR	(CSEQ_CIO_REG_BASE_ADR + LASTADDR)
+
+#define CNXTLADDR	(CSEQ_CIO_REG_BASE_ADR + NXTLADDR)
+
+#define CDBGPORTPTR	(CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR)
+
+#define CDBGPORT	(CSEQ_CIO_REG_BASE_ADR + DBGPORT)
+
+#define CSCRATCHPAGE	(CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE)
+
+#define CMnSCBPTR(Mode)       CSEQm_CIO_REG(Mode, MnSCBPTR)
+
+#define CMnDDBPTR(Mode)       CSEQm_CIO_REG(Mode, MnDDBPTR)
+
+#define CMnSCRATCHPAGE(Mode)		CSEQm_CIO_REG(Mode, MnSCRATCHPAGE)
+
+#define CLINKCON	(CSEQ_CIO_REG_BASE_ADR + 0x28)
+
+#define	CCIOAACESS	(CSEQ_CIO_REG_BASE_ADR + 0x2C)
+
+/* mode 0-7 */
+#define MnREQMBX 0x30
+#define CMnREQMBX(Mode)			CSEQm_CIO_REG(Mode, 0x30)
+
+/* mode 8 */
+#define CSEQCON				CSEQm_CIO_REG(8, 0x30)
+
+/* mode 0-7 */
+#define MnRSPMBX 0x34
+#define CMnRSPMBX(Mode)			CSEQm_CIO_REG(Mode, 0x34)
+
+/* mode 8 */
+#define CSEQCOMCTL			CSEQm_CIO_REG(8, 0x34)
+
+/* mode 8 */
+#define CSEQCOMSTAT			CSEQm_CIO_REG(8, 0x35)
+
+/* mode 8 */
+#define CSEQCOMINTEN			CSEQm_CIO_REG(8, 0x36)
+
+/* mode 8 */
+#define CSEQCOMDMACTL			CSEQm_CIO_REG(8, 0x37)
+
+#define		CSHALTERR		0x10
+#define		RESETCSDMA		0x08		/* wo */
+#define		STARTCSDMA		0x04
+#define		STOPCSDMA		0x02		/* wo */
+#define		CSDMAACT		0x01		/* ro */
+
+/* mode 0-7 */
+#define MnINT 0x38
+#define CMnINT(Mode)			CSEQm_CIO_REG(Mode, 0x38)
+
+#define		CMnREQMBXE		0x02
+#define		CMnRSPMBXF		0x01
+#define		CMnINT_MASK		0x00000003
+
+/* mode 8 */
+#define CSEQREQMBX			CSEQm_CIO_REG(8, 0x38)
+
+/* mode 0-7 */
+#define MnINTEN 0x3C
+#define CMnINTEN(Mode)			CSEQm_CIO_REG(Mode, 0x3C)
+
+#define		EN_CMnRSPMBXF		0x01
+
+/* mode 8 */
+#define CSEQRSPMBX			CSEQm_CIO_REG(8, 0x3C)
+
+/* mode 8 */
+#define CSDMAADR			CSEQm_CIO_REG(8, 0x40)
+
+/* mode 8 */
+#define CSDMACNT			CSEQm_CIO_REG(8, 0x48)
+
+/* mode 8 */
+#define CSEQDLCTL			CSEQm_CIO_REG(8, 0x4D)
+
+#define		DONELISTEND		0x10
+#define 	DONELISTSIZE_MASK	0x0F
+#define		DONELISTSIZE_8ELEM	0x01
+#define		DONELISTSIZE_16ELEM	0x02
+#define		DONELISTSIZE_32ELEM	0x03
+#define		DONELISTSIZE_64ELEM	0x04
+#define		DONELISTSIZE_128ELEM	0x05
+#define		DONELISTSIZE_256ELEM	0x06
+#define		DONELISTSIZE_512ELEM	0x07
+#define		DONELISTSIZE_1024ELEM	0x08
+#define		DONELISTSIZE_2048ELEM	0x09
+#define		DONELISTSIZE_4096ELEM	0x0A
+#define		DONELISTSIZE_8192ELEM	0x0B
+#define		DONELISTSIZE_16384ELEM	0x0C
+
+/* mode 8 */
+#define CSEQDLOFFS			CSEQm_CIO_REG(8, 0x4E)
+
+/* mode 11 */
+#define CM11INTVEC0			CSEQm_CIO_REG(11, 0x50)
+
+/* mode 11 */
+#define CM11INTVEC1			CSEQm_CIO_REG(11, 0x52)
+
+/* mode 11 */
+#define CM11INTVEC2			CSEQm_CIO_REG(11, 0x54)
+
+#define	CCONMSK	  			(CSEQ_CIO_REG_BASE_ADR + 0x60)
+
+#define	CCONEXIST			(CSEQ_CIO_REG_BASE_ADR + 0x61)
+
+#define	CCONMODE			(CSEQ_CIO_REG_BASE_ADR + 0x62)
+
+#define CTIMERCALC			(CSEQ_CIO_REG_BASE_ADR + 0x64)
+
+#define CINTDIS				(CSEQ_CIO_REG_BASE_ADR + 0x68)
+
+/* mode 8, 32x32 bits, 128 bytes of mapped buffer */
+#define CSBUFFER			CSEQm_CIO_REG(8, 0x80)
+
+#define	CSCRATCH			(CSEQ_CIO_REG_BASE_ADR + 0x1C0)
+
+/* mode 0-8 */
+#define CMnSCRATCH(Mode)		CSEQm_CIO_REG(Mode, 0x1E0)
+
+/*
+ * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC)
+ */
+#define CSEQ_RAM_REG_BASE_ADR		0xB8004000
+
+/*
+ * The common definitions below have the same address offset for all the Link
+ * sequencers.
+ */
+#define MODECTL		0x40
+
+#define DBGMODE		0x44
+
+#define CONTROL		0x48
+#define LEDTIMER		0x00010000
+#define LEDTIMERS_10us		0x00000000
+#define LEDTIMERS_1ms		0x00000800
+#define LEDTIMERS_100ms		0x00001000
+#define LEDMODE_TXRX		0x00000000
+#define LEDMODE_CONNECTED	0x00000200
+#define LEDPOL			0x00000100
+
+#define LSEQRAM		0x1000
+
+/*
+ * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC)
+ */
+#define LSEQ0_HOST_REG_BASE_ADR		0xB8020000
+#define LSEQ1_HOST_REG_BASE_ADR		0xB8024000
+#define LSEQ2_HOST_REG_BASE_ADR		0xB8028000
+#define LSEQ3_HOST_REG_BASE_ADR		0xB802C000
+#define LSEQ4_HOST_REG_BASE_ADR		0xB8030000
+#define LSEQ5_HOST_REG_BASE_ADR		0xB8034000
+#define LSEQ6_HOST_REG_BASE_ADR		0xB8038000
+#define LSEQ7_HOST_REG_BASE_ADR		0xB803C000
+
+#define LmARP2CTL(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					ARP2CTL)
+
+#define LmARP2INT(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					ARP2INT)
+
+#define LmARP2INTEN(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					ARP2INTEN)
+
+#define LmDBGMODE(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					DBGMODE)
+
+#define LmCONTROL(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					CONTROL)
+
+#define LmARP2BREAKADR01(LinkNum)	(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					ARP2BREAKADR01)
+
+#define LmARP2BREAKADR23(LinkNum)	(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					ARP2BREAKADR23)
+
+#define LmMODECTL(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					MODECTL)
+
+#define		LmAUTODISCI		0x08000000
+#define		LmDSBLBITLT		0x04000000
+#define		LmDSBLANTT		0x02000000
+#define		LmDSBLCRTT		0x01000000
+#define		LmDSBLCONT		0x00000100
+#define		LmPRIMODE		0x00000080
+#define		LmDSBLHOLD		0x00000040
+#define		LmDISACK		0x00000020
+#define		LmBLIND48		0x00000010
+#define		LmRCVMODE_MASK		0x0000000C
+#define		LmRCVMODE_PLD		0x00000000
+#define		LmRCVMODE_HPC		0x00000004
+
+#define LmDBGMODE(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					DBGMODE)
+
+#define		LmFRCPERR		0x80000000
+#define		LmMEMSEL_MASK		0x30000000
+#define		LmFRCRBPERR		0x00000000
+#define		LmFRCTBPERR		0x10000000
+#define		LmFRCSGBPERR		0x20000000
+#define		LmFRCARBPERR		0x30000000
+#define		LmRCVIDW		0x00080000
+#define		LmINVDWERR		0x00040000
+#define		LmRCVDISP		0x00004000
+#define		LmDISPERR		0x00002000
+#define		LmDSBLDSCR		0x00000800
+#define		LmDSBLSCR		0x00000400
+#define		LmFRCNAK		0x00000200
+#define		LmFRCROFS		0x00000100
+#define		LmFRCCRC		0x00000080
+#define		LmFRMTYPE_MASK		0x00000070
+#define		LmSG_DATA		0x00000000
+#define		LmSG_COMMAND		0x00000010
+#define		LmSG_TASK		0x00000020
+#define		LmSG_TGTXFER		0x00000030
+#define		LmSG_RESPONSE		0x00000040
+#define		LmSG_IDENADDR		0x00000050
+#define		LmSG_OPENADDR		0x00000060
+#define		LmDISCRCGEN		0x00000008
+#define		LmDISCRCCHK		0x00000004
+#define		LmSSXMTFRM		0x00000002
+#define		LmSSRCVFRM		0x00000001
+
+#define LmCONTROL(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					CONTROL)
+
+#define		LmSTEPXMTFRM		0x00000002
+#define		LmSTEPRCVFRM		0x00000001
+
+#define LmBISTCTL0(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	  \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+					BISTCTL0)
+
+#define		ARBBISTEN		0x40000000
+#define		ARBBISTDN		0x20000000	/* ro */
+#define		ARBBISTFAIL		0x10000000	/* ro */
+#define		TBBISTEN		0x00000400
+#define		TBBISTDN		0x00000200	/* ro */
+#define		TBBISTFAIL		0x00000100	/* ro */
+#define		RBBISTEN		0x00000040
+#define		RBBISTDN		0x00000020	/* ro */
+#define		RBBISTFAIL		0x00000010	/* ro */
+#define		SGBISTEN		0x00000004
+#define		SGBISTDN		0x00000002	/* ro */
+#define		SGBISTFAIL		0x00000001	/* ro */
+
+#define LmBISTCTL1(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	 \
+					((LinkNum)*LmSEQ_HOST_REG_SIZE) +\
+					BISTCTL1)
+
+#define		LmRAMPAGE1		0x00000200
+#define		LmRAMPAGE0		0x00000100
+#define		LmIMEMBISTEN		0x00000040
+#define		LmIMEMBISTDN		0x00000020	/* ro */
+#define		LmIMEMBISTFAIL		0x00000010	/* ro */
+#define		LmSCRBISTEN		0x00000004
+#define		LmSCRBISTDN		0x00000002	/* ro */
+#define		LmSCRBISTFAIL		0x00000001	/* ro */
+#define		LmRAMPAGE		(LmRAMPAGE1 + LmRAMPAGE0)
+#define		LmRAMPAGE_LSHIFT	0x8
+
+#define LmSCRATCH(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	   \
+					((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+					MAPPEDSCR)
+
+#define LmSEQRAM(LinkNum)		(LSEQ0_HOST_REG_BASE_ADR +	   \
+					((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+					LSEQRAM)
+
+/*
+ * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC)
+ * 8 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define LmSEQ_CIOBUS_REG_BASE		0x2000
+
+#define  LmSEQ_PHY_BASE(Mode, LinkNum) \
+		(LSEQ0_HOST_REG_BASE_ADR + \
+		(LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \
+		LmSEQ_CIOBUS_REG_BASE + \
+		((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE))
+
+#define  LmSEQ_PHY_REG(Mode, LinkNum, Reg) \
+                 (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg))
+
+#define LmMODEPTR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, MODEPTR)
+
+#define LmALTMODE(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ALTMODE)
+
+#define LmATOMICXCHG(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG)
+
+#define LmFLAG(LinkNum)			LmSEQ_PHY_REG(0, LinkNum, FLAG)
+
+#define LmARP2INTCTL(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL)
+
+#define LmSTACK(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, STACK)
+
+#define LmFUNCTION1(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, FUNCTION1)
+
+#define LmPRGMCNT(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, PRGMCNT)
+
+#define LmACCUM(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ACCUM)
+
+#define LmSINDEX(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, SINDEX)
+
+#define LmDINDEX(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, DINDEX)
+
+#define LmALLONES(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ALLONES)
+
+#define LmALLZEROS(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ALLZEROS)
+
+#define LmSINDIR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, SINDIR)
+
+#define LmDINDIR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, DINDIR)
+
+#define LmJUMLDIR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, JUMLDIR)
+
+#define LmARP2HALTCODE(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE)
+
+#define LmCURRADDR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, CURRADDR)
+
+#define LmLASTADDR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, LASTADDR)
+
+#define LmNXTLADDR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, NXTLADDR)
+
+#define LmDBGPORTPTR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR)
+
+#define LmDBGPORT(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, DBGPORT)
+
+#define LmSCRATCHPAGE(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE)
+
+#define LmMnSCRATCHPAGE(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 	\
+						      MnSCRATCHPAGE)
+
+#define LmTIMERCALC(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x28)
+
+#define LmREQMBX(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x30)
+
+#define LmRSPMBX(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x34)
+
+#define LmMnINT(LinkNum, Mode)		LmSEQ_PHY_REG(Mode, LinkNum, 0x38)
+
+#define		CTXMEMSIZE		0x80000000	/* ro */
+#define		LmACKREQ		0x08000000
+#define		LmNAKREQ		0x04000000
+#define		LmMnXMTERR		0x02000000
+#define		LmM5OOBSVC		0x01000000
+#define		LmHWTINT		0x00800000
+#define		LmMnCTXDONE		0x00100000
+#define		LmM2REQMBXF		0x00080000
+#define		LmM2RSPMBXE		0x00040000
+#define		LmMnDMAERR		0x00020000
+#define		LmRCVPRIM		0x00010000
+#define		LmRCVERR		0x00008000
+#define		LmADDRRCV		0x00004000
+#define		LmMnHDRMISS		0x00002000
+#define		LmMnWAITSCB		0x00001000
+#define		LmMnRLSSCB		0x00000800
+#define		LmMnSAVECTX		0x00000400
+#define		LmMnFETCHSG		0x00000200
+#define		LmMnLOADCTX		0x00000100
+#define		LmMnCFGICL		0x00000080
+#define		LmMnCFGSATA		0x00000040
+#define		LmMnCFGEXPSATA		0x00000020
+#define		LmMnCFGCMPLT		0x00000010
+#define		LmMnCFGRBUF		0x00000008
+#define		LmMnSAVETTR		0x00000004
+#define		LmMnCFGRDAT		0x00000002
+#define		LmMnCFGHDR		0x00000001
+
+#define LmMnINTEN(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x3C)
+
+#define		EN_LmACKREQ		0x08000000
+#define		EN_LmNAKREQ		0x04000000
+#define		EN_LmMnXMTERR		0x02000000
+#define		EN_LmM5OOBSVC		0x01000000
+#define		EN_LmHWTINT		0x00800000
+#define		EN_LmMnCTXDONE		0x00100000
+#define		EN_LmM2REQMBXF		0x00080000
+#define		EN_LmM2RSPMBXE		0x00040000
+#define		EN_LmMnDMAERR		0x00020000
+#define		EN_LmRCVPRIM		0x00010000
+#define		EN_LmRCVERR		0x00008000
+#define		EN_LmADDRRCV		0x00004000
+#define		EN_LmMnHDRMISS		0x00002000
+#define		EN_LmMnWAITSCB		0x00001000
+#define		EN_LmMnRLSSCB		0x00000800
+#define		EN_LmMnSAVECTX		0x00000400
+#define		EN_LmMnFETCHSG		0x00000200
+#define		EN_LmMnLOADCTX		0x00000100
+#define		EN_LmMnCFGICL		0x00000080
+#define		EN_LmMnCFGSATA		0x00000040
+#define		EN_LmMnCFGEXPSATA	0x00000020
+#define		EN_LmMnCFGCMPLT		0x00000010
+#define		EN_LmMnCFGRBUF		0x00000008
+#define		EN_LmMnSAVETTR		0x00000004
+#define		EN_LmMnCFGRDAT		0x00000002
+#define		EN_LmMnCFGHDR		0x00000001
+
+#define		LmM0INTEN_MASK		(EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \
+					 EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \
+					 EN_LmMnCFGHDR | EN_LmRCVERR | \
+					 EN_LmADDRRCV | EN_LmMnHDRMISS | \
+					 EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+					 EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+					 EN_LmHWTINT | EN_LmMnCTXDONE | \
+					 EN_LmRCVPRIM | EN_LmMnCFGSATA | \
+					 EN_LmMnCFGEXPSATA | EN_LmMnDMAERR)
+
+#define		LmM1INTEN_MASK		(EN_LmMnCFGCMPLT | EN_LmADDRRCV | \
+					 EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+					 EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+					 EN_LmMnXMTERR | EN_LmHWTINT | \
+					 EN_LmMnCTXDONE | EN_LmRCVPRIM | \
+					 EN_LmRCVERR | EN_LmMnDMAERR)
+
+#define		LmM2INTEN_MASK		(EN_LmADDRRCV | EN_LmHWTINT | \
+					 EN_LmM2REQMBXF | EN_LmRCVPRIM | \
+					 EN_LmRCVERR)
+
+#define		LmM5INTEN_MASK		(EN_LmADDRRCV | EN_LmM5OOBSVC | \
+					 EN_LmHWTINT | EN_LmRCVPRIM | \
+					 EN_LmRCVERR)
+
+#define LmXMTPRIMD(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x40)
+
+#define LmXMTPRIMCS(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x44)
+
+#define LmCONSTAT(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x45)
+
+#define LmMnDMAERRS(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x46)
+
+#define LmMnSGDMAERRS(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x47)
+
+#define LmM0EXPHDRP(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x48)
+
+#define LmM1SASALIGN(LinkNum)		LmSEQ_PHY_REG(1, LinkNum, 0x48)
+#define SAS_ALIGN_DEFAULT		0xFF
+
+#define LmM0MSKHDRP(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x49)
+
+#define LmM1STPALIGN(LinkNum)		LmSEQ_PHY_REG(1, LinkNum, 0x49)
+#define STP_ALIGN_DEFAULT		0x1F
+
+#define LmM0RCVHDRP(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x4A)
+
+#define LmM1XMTHDRP(LinkNum)		LmSEQ_PHY_REG(1, LinkNum, 0x4A)
+
+#define LmM0ICLADR(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x4B)
+
+#define LmM1ALIGNMODE(LinkNum)		LmSEQ_PHY_REG(1, LinkNum, 0x4B)
+
+#define		LmDISALIGN		0x20
+#define		LmROTSTPALIGN		0x10
+#define		LmSTPALIGN		0x08
+#define		LmROTNOTIFY		0x04
+#define		LmDUALALIGN		0x02
+#define		LmROTALIGN		0x01
+
+#define LmM0EXPRCVNT(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x4C)
+
+#define LmM1XMTCNT(LinkNum)		LmSEQ_PHY_REG(1, LinkNum, 0x4C)
+
+#define LmMnBUFSTAT(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x4E)
+
+#define		LmMnBUFPERR		0x01
+
+/* mode 0-1 */
+#define LmMnXFRLVL(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x59)
+
+#define		LmMnXFRLVL_128		0x05
+#define		LmMnXFRLVL_256		0x04
+#define		LmMnXFRLVL_512		0x03
+#define		LmMnXFRLVL_1024		0x02
+#define		LmMnXFRLVL_1536		0x01
+#define		LmMnXFRLVL_2048		0x00
+
+ /* mode 0-1 */
+#define LmMnSGDMACTL(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x5A)
+
+#define 	LmMnRESETSG		0x04
+#define 	LmMnSTOPSG		0x02
+#define 	LmMnSTARTSG		0x01
+
+/* mode 0-1 */
+#define LmMnSGDMASTAT(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x5B)
+
+/* mode 0-1 */
+#define LmMnDDMACTL(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x5C)
+
+#define 	LmMnFLUSH		0x40		/* wo */
+#define 	LmMnRLSRTRY		0x20		/* wo */
+#define 	LmMnDISCARD		0x10		/* wo */
+#define 	LmMnRESETDAT		0x08		/* wo */
+#define 	LmMnSUSDAT		0x04		/* wo */
+#define 	LmMnSTOPDAT		0x02		/* wo */
+#define 	LmMnSTARTDAT		0x01		/* wo */
+
+/* mode 0-1 */
+#define LmMnDDMASTAT(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x5D)
+
+#define		LmMnDPEMPTY		0x80
+#define		LmMnFLUSHING		0x40
+#define		LmMnDDMAREQ		0x20
+#define		LmMnHDMAREQ		0x10
+#define		LmMnDATFREE		0x08
+#define		LmMnDATSUS		0x04
+#define		LmMnDATACT		0x02
+#define		LmMnDATEN		0x01
+
+/* mode 0-1 */
+#define LmMnDDMAMODE(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x5E)
+
+#define 	LmMnDMATYPE_NORMAL		0x0000
+#define 	LmMnDMATYPE_HOST_ONLY_TX	0x0001
+#define 	LmMnDMATYPE_DEVICE_ONLY_TX	0x0002
+#define 	LmMnDMATYPE_INVALID		0x0003
+#define 	LmMnDMATYPE_MASK	0x0003
+
+#define 	LmMnDMAWRAP		0x0004
+#define 	LmMnBITBUCKET		0x0008
+#define 	LmMnDISHDR		0x0010
+#define 	LmMnSTPCRC		0x0020
+#define 	LmXTEST			0x0040
+#define 	LmMnDISCRC		0x0080
+#define 	LmMnENINTLK		0x0100
+#define 	LmMnADDRFRM		0x0400
+#define 	LmMnENXMTCRC		0x0800
+
+/* mode 0-1 */
+#define LmMnXFRCNT(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x70)
+
+/* mode 0-1 */
+#define LmMnDPSEL(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x7B)
+#define 	LmMnDPSEL_MASK		0x07
+#define 	LmMnEOLPRE		0x40
+#define 	LmMnEOSPRE		0x80
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Receive Mode n = 0 */
+#define LmMnHRADDR			0x00
+#define LmMnHBYTECNT			0x01
+#define LmMnHREWIND			0x02
+#define LmMnDWADDR			0x03
+#define LmMnDSPACECNT			0x04
+#define LmMnDFRMSIZE			0x05
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Transmit Mode n = 1 */
+#define LmMnHWADDR			0x00
+#define LmMnHSPACECNT			0x01
+/* #define LmMnHREWIND			0x02 */
+#define LmMnDRADDR			0x03
+#define LmMnDBYTECNT			0x04
+/* #define LmMnDFRMSIZE			0x05 */
+
+/* mode 0-1 */
+#define LmMnDPACC(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x78)
+#define 	LmMnDPACC_MASK		0x00FFFFFF
+
+/* mode 0-1 */
+#define LmMnHOLDLVL(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x7D)
+
+#define LmPRMSTAT0(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x80)
+#define LmPRMSTAT0BYTE0			0x80
+#define LmPRMSTAT0BYTE1			0x81
+#define LmPRMSTAT0BYTE2			0x82
+#define LmPRMSTAT0BYTE3			0x83
+
+#define		LmFRAMERCVD		0x80000000
+#define		LmXFRRDYRCVD		0x40000000
+#define		LmUNKNOWNP		0x20000000
+#define		LmBREAK			0x10000000
+#define		LmDONE			0x08000000
+#define		LmOPENACPT		0x04000000
+#define		LmOPENRJCT		0x02000000
+#define		LmOPENRTRY		0x01000000
+#define		LmCLOSERV1		0x00800000
+#define		LmCLOSERV0		0x00400000
+#define		LmCLOSENORM		0x00200000
+#define		LmCLOSECLAF		0x00100000
+#define		LmNOTIFYRV2		0x00080000
+#define		LmNOTIFYRV1		0x00040000
+#define		LmNOTIFYRV0		0x00020000
+#define		LmNOTIFYSPIN		0x00010000
+#define		LmBROADRV4		0x00008000
+#define		LmBROADRV3		0x00004000
+#define		LmBROADRV2		0x00002000
+#define		LmBROADRV1		0x00001000
+#define		LmBROADSES		0x00000800
+#define		LmBROADRVCH1		0x00000400
+#define		LmBROADRVCH0		0x00000200
+#define		LmBROADCH		0x00000100
+#define		LmAIPRVWP		0x00000080
+#define		LmAIPWP			0x00000040
+#define		LmAIPWD			0x00000020
+#define		LmAIPWC			0x00000010
+#define		LmAIPRV2		0x00000008
+#define		LmAIPRV1		0x00000004
+#define		LmAIPRV0		0x00000002
+#define		LmAIPNRML		0x00000001
+
+#define		LmBROADCAST_MASK	(LmBROADCH | LmBROADRVCH0 | \
+					 LmBROADRVCH1)
+
+#define LmPRMSTAT1(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0x84)
+#define LmPRMSTAT1BYTE0			0x84
+#define LmPRMSTAT1BYTE1			0x85
+#define LmPRMSTAT1BYTE2			0x86
+#define LmPRMSTAT1BYTE3			0x87
+
+#define		LmFRMRCVDSTAT		0x80000000
+#define		LmBREAK_DET		0x04000000
+#define		LmCLOSE_DET		0x02000000
+#define		LmDONE_DET		0x01000000
+#define		LmXRDY			0x00040000
+#define 	LmSYNCSRST		0x00020000
+#define 	LmSYNC			0x00010000
+#define 	LmXHOLD			0x00008000
+#define 	LmRRDY			0x00004000
+#define 	LmHOLD			0x00002000
+#define 	LmROK			0x00001000
+#define 	LmRIP			0x00000800
+#define 	LmCRBLK			0x00000400
+#define 	LmACK			0x00000200
+#define 	LmNAK			0x00000100
+#define 	LmHARDRST		0x00000080
+#define 	LmERROR			0x00000040
+#define 	LmRERR			0x00000020
+#define 	LmPMREQP		0x00000010
+#define 	LmPMREQS		0x00000008
+#define 	LmPMACK			0x00000004
+#define 	LmPMNAK			0x00000002
+#define 	LmDMAT			0x00000001
+
+/* mode 1 */
+#define	LmMnSATAFS(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x7E)
+#define	LmMnXMTSIZE(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0x93)
+
+/* mode 0 */
+#define LmMnFRMERR(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0xB0)
+
+#define		LmACRCERR		0x00000800
+#define		LmPHYOVRN		0x00000400
+#define		LmOBOVRN		0x00000200
+#define 	LmMnZERODATA		0x00000100
+#define		LmSATAINTLK		0x00000080
+#define		LmMnCRCERR		0x00000020
+#define		LmRRDYOVRN		0x00000010
+#define		LmMISSSOAF		0x00000008
+#define		LmMISSSOF		0x00000004
+#define		LmMISSEOAF		0x00000002
+#define		LmMISSEOF		0x00000001
+
+#define LmFRMERREN(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0xB4)
+
+#define 	EN_LmACRCERR		0x00000800
+#define 	EN_LmPHYOVRN		0x00000400
+#define 	EN_LmOBOVRN		0x00000200
+#define 	EN_LmMnZERODATA		0x00000100
+#define 	EN_LmSATAINTLK		0x00000080
+#define 	EN_LmFRMBAD		0x00000040
+#define 	EN_LmMnCRCERR		0x00000020
+#define 	EN_LmRRDYOVRN		0x00000010
+#define 	EN_LmMISSSOAF		0x00000008
+#define 	EN_LmMISSSOF		0x00000004
+#define 	EN_LmMISSEOAF		0x00000002
+#define 	EN_LmMISSEOF		0x00000001
+
+#define 	LmFRMERREN_MASK  	(EN_LmSATAINTLK | EN_LmMnCRCERR | \
+					 EN_LmRRDYOVRN | EN_LmMISSSOF | \
+					 EN_LmMISSEOAF | EN_LmMISSEOF | \
+					 EN_LmACRCERR | LmPHYOVRN | \
+					 EN_LmOBOVRN | EN_LmMnZERODATA)
+
+#define LmHWTSTATEN(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0xC5)
+
+#define		EN_LmDONETO		0x80
+#define		EN_LmINVDISP		0x40
+#define		EN_LmINVDW		0x20
+#define		EN_LmDWSEVENT		0x08
+#define		EN_LmCRTTTO		0x04
+#define		EN_LmANTTTO		0x02
+#define		EN_LmBITLTTO		0x01
+
+#define		LmHWTSTATEN_MASK	(EN_LmINVDISP | EN_LmINVDW | \
+					 EN_LmDWSEVENT | EN_LmCRTTTO | \
+					 EN_LmANTTTO | EN_LmDONETO | \
+					 EN_LmBITLTTO)
+
+#define LmHWTSTAT(LinkNum) 		LmSEQ_PHY_REG(0, LinkNum, 0xC7)
+
+#define		LmDONETO		0x80
+#define		LmINVDISP		0x40
+#define		LmINVDW			0x20
+#define		LmDWSEVENT		0x08
+#define		LmCRTTTO		0x04
+#define		LmANTTTO		0x02
+#define		LmBITLTTO		0x01
+
+#define LmMnDATABUFADR(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0xC8)
+#define		LmDATABUFADR_MASK	0x0FFF
+
+#define LmMnDATABUF(LinkNum, Mode)	LmSEQ_PHY_REG(Mode, LinkNum, 0xCA)
+
+#define	LmPRIMSTAT0EN(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0xE0)
+
+#define 	EN_LmUNKNOWNP 		0x20000000
+#define 	EN_LmBREAK		0x10000000
+#define 	EN_LmDONE		0x08000000
+#define 	EN_LmOPENACPT		0x04000000
+#define 	EN_LmOPENRJCT		0x02000000
+#define 	EN_LmOPENRTRY		0x01000000
+#define 	EN_LmCLOSERV1		0x00800000
+#define 	EN_LmCLOSERV0		0x00400000
+#define 	EN_LmCLOSENORM		0x00200000
+#define 	EN_LmCLOSECLAF		0x00100000
+#define 	EN_LmNOTIFYRV2		0x00080000
+#define 	EN_LmNOTIFYRV1		0x00040000
+#define 	EN_LmNOTIFYRV0		0x00020000
+#define 	EN_LmNOTIFYSPIN		0x00010000
+#define 	EN_LmBROADRV4		0x00008000
+#define 	EN_LmBROADRV3		0x00004000
+#define 	EN_LmBROADRV2		0x00002000
+#define 	EN_LmBROADRV1		0x00001000
+#define 	EN_LmBROADRV0		0x00000800
+#define 	EN_LmBROADRVCH1		0x00000400
+#define 	EN_LmBROADRVCH0		0x00000200
+#define 	EN_LmBROADCH		0x00000100
+#define 	EN_LmAIPRVWP		0x00000080
+#define 	EN_LmAIPWP		0x00000040
+#define 	EN_LmAIPWD		0x00000020
+#define 	EN_LmAIPWC		0x00000010
+#define 	EN_LmAIPRV2		0x00000008
+#define 	EN_LmAIPRV1		0x00000004
+#define 	EN_LmAIPRV0		0x00000002
+#define 	EN_LmAIPNRML		0x00000001
+
+#define		LmPRIMSTAT0EN_MASK	(EN_LmBREAK | \
+					 EN_LmDONE | EN_LmOPENACPT | \
+					 EN_LmOPENRJCT | EN_LmOPENRTRY | \
+					 EN_LmCLOSERV1 | EN_LmCLOSERV0 | \
+					 EN_LmCLOSENORM | EN_LmCLOSECLAF | \
+					 EN_LmBROADRV4 | EN_LmBROADRV3 | \
+					 EN_LmBROADRV2 | EN_LmBROADRV1 | \
+					 EN_LmBROADRV0 | EN_LmBROADRVCH1 | \
+					 EN_LmBROADRVCH0 | EN_LmBROADCH | \
+					 EN_LmAIPRVWP | EN_LmAIPWP | \
+					 EN_LmAIPWD | EN_LmAIPWC | \
+					 EN_LmAIPRV2 | EN_LmAIPRV1 | \
+					 EN_LmAIPRV0 | EN_LmAIPNRML)
+
+#define LmPRIMSTAT1EN(LinkNum)		LmSEQ_PHY_REG(0, LinkNum, 0xE4)
+
+#define		EN_LmXRDY		0x00040000
+#define		EN_LmSYNCSRST		0x00020000
+#define		EN_LmSYNC		0x00010000
+#define 	EN_LmXHOLD		0x00008000
+#define 	EN_LmRRDY		0x00004000
+#define 	EN_LmHOLD		0x00002000
+#define 	EN_LmROK		0x00001000
+#define 	EN_LmRIP		0x00000800
+#define 	EN_LmCRBLK		0x00000400
+#define 	EN_LmACK		0x00000200
+#define 	EN_LmNAK		0x00000100
+#define 	EN_LmHARDRST		0x00000080
+#define 	EN_LmERROR		0x00000040
+#define 	EN_LmRERR		0x00000020
+#define 	EN_LmPMREQP		0x00000010
+#define 	EN_LmPMREQS		0x00000008
+#define 	EN_LmPMACK		0x00000004
+#define 	EN_LmPMNAK		0x00000002
+#define 	EN_LmDMAT		0x00000001
+
+#define LmPRIMSTAT1EN_MASK		(EN_LmHARDRST | \
+					 EN_LmSYNCSRST | \
+					 EN_LmPMREQP | EN_LmPMREQS | \
+					 EN_LmPMACK | EN_LmPMNAK)
+
+#define LmSMSTATE(LinkNum) 		LmSEQ_PHY_REG(0, LinkNum, 0xE8)
+
+#define LmSMSTATEBRK(LinkNum) 		LmSEQ_PHY_REG(0, LinkNum, 0xEC)
+
+#define LmSMDBGCTL(LinkNum) 		LmSEQ_PHY_REG(0, LinkNum, 0xF0)
+
+
+/*
+ * LmSEQ CIO Bus Mode 3 Register.
+ * Mode 3: Configuration and Setup, IOP Context SCB.
+ */
+#define LmM3SATATIMER(LinkNum) 		LmSEQ_PHY_REG(3, LinkNum, 0x48)
+
+#define LmM3INTVEC0(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x90)
+
+#define LmM3INTVEC1(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x92)
+
+#define LmM3INTVEC2(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x94)
+
+#define LmM3INTVEC3(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x96)
+
+#define LmM3INTVEC4(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x98)
+
+#define LmM3INTVEC5(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x9A)
+
+#define LmM3INTVEC6(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x9C)
+
+#define LmM3INTVEC7(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0x9E)
+
+#define LmM3INTVEC8(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0xA4)
+
+#define LmM3INTVEC9(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0xA6)
+
+#define LmM3INTVEC10(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0xB0)
+
+#define LmM3FRMGAP(LinkNum)		LmSEQ_PHY_REG(3, LinkNum, 0xB4)
+
+#define LmBITL_TIMER(LinkNum) 		LmSEQ_PHY_REG(0, LinkNum, 0xA2)
+
+#define LmWWN(LinkNum) 			LmSEQ_PHY_REG(0, LinkNum, 0xA8)
+
+
+/*
+ * LmSEQ CIO Bus Mode 5 Registers.
+ * Mode 5: Phy/OOB Control and Status.
+ */
+#define LmSEQ_OOB_REG(phy_id, reg)	LmSEQ_PHY_REG(5, (phy_id), (reg))
+
+#define OOB_BFLTR	0x100
+
+#define		BFLTR_THR_MASK		0xF0
+#define		BFLTR_TC_MASK		0x0F
+
+#define OOB_INIT_MIN	0x102
+
+#define OOB_INIT_MAX	0x104
+
+#define OOB_INIT_NEG	0x106
+
+#define	OOB_SAS_MIN	0x108
+
+#define OOB_SAS_MAX	0x10A
+
+#define OOB_SAS_NEG	0x10C
+
+#define OOB_WAKE_MIN	0x10E
+
+#define OOB_WAKE_MAX	0x110
+
+#define OOB_WAKE_NEG	0x112
+
+#define OOB_IDLE_MAX	0x114
+
+#define OOB_BURST_MAX	0x116
+
+#define OOB_DATA_KBITS	0x126
+
+#define OOB_ALIGN_0_DATA	0x12C
+
+#define OOB_ALIGN_1_DATA	0x130
+
+#define D10_2_DATA_k		0x00
+#define SYNC_DATA_k		0x02
+#define ALIGN_1_DATA_k		0x04
+#define ALIGN_0_DATA_k		0x08
+#define BURST_DATA_k		0x10
+
+#define OOB_PHY_RESET_COUNT	0x13C
+
+#define OOB_SIG_GEN	0x140
+
+#define		START_OOB		0x80
+#define		START_DWS		0x40
+#define		ALIGN_CNT3		0x30
+#define 	ALIGN_CNT2		0x20
+#define 	ALIGN_CNT1		0x10
+#define 	ALIGN_CNT4		0x00
+#define		STOP_DWS		0x08
+#define		SEND_COMSAS		0x04
+#define		SEND_COMINIT		0x02
+#define		SEND_COMWAKE		0x01
+
+#define OOB_XMIT	0x141
+
+#define		TX_ENABLE		0x80
+#define		XMIT_OOB_BURST		0x10
+#define		XMIT_D10_2		0x08
+#define		XMIT_SYNC		0x04
+#define		XMIT_ALIGN_1		0x02
+#define		XMIT_ALIGN_0		0x01
+
+#define FUNCTION_MASK	0x142
+
+#define		SAS_MODE_DIS		0x80
+#define		SATA_MODE_DIS		0x40
+#define		SPINUP_HOLD_DIS		0x20
+#define		HOT_PLUG_DIS		0x10
+#define		SATA_PS_DIS		0x08
+#define		FUNCTION_MASK_DEFAULT	(SPINUP_HOLD_DIS | SATA_PS_DIS)
+
+#define OOB_MODE	0x143
+
+#define		SAS_MODE		0x80
+#define		SATA_MODE		0x40
+#define		SLOW_CLK		0x20
+#define		FORCE_XMIT_15		0x08
+#define		PHY_SPEED_60		0x04
+#define		PHY_SPEED_30		0x02
+#define		PHY_SPEED_15		0x01
+
+#define	CURRENT_STATUS	0x144
+
+#define		CURRENT_OOB_DONE	0x80
+#define		CURRENT_LOSS_OF_SIGNAL	0x40
+#define		CURRENT_SPINUP_HOLD	0x20
+#define		CURRENT_HOT_PLUG_CNCT	0x10
+#define		CURRENT_GTO_TIMEOUT	0x08
+#define		CURRENT_OOB_TIMEOUT	0x04
+#define		CURRENT_DEVICE_PRESENT	0x02
+#define		CURRENT_OOB_ERROR	0x01
+
+#define 	CURRENT_OOB1_ERROR	(CURRENT_HOT_PLUG_CNCT | \
+					 CURRENT_GTO_TIMEOUT)
+
+#define 	CURRENT_OOB2_ERROR	(CURRENT_HOT_PLUG_CNCT | \
+					 CURRENT_OOB_ERROR)
+
+#define		DEVICE_ADDED_W_CNT	(CURRENT_OOB_DONE | \
+					 CURRENT_HOT_PLUG_CNCT | \
+					 CURRENT_DEVICE_PRESENT)
+
+#define		DEVICE_ADDED_WO_CNT	(CURRENT_OOB_DONE | \
+					 CURRENT_DEVICE_PRESENT)
+
+#define 	DEVICE_REMOVED		CURRENT_LOSS_OF_SIGNAL
+
+#define		CURRENT_PHY_MASK	(CURRENT_OOB_DONE | \
+					 CURRENT_LOSS_OF_SIGNAL | \
+					 CURRENT_SPINUP_HOLD | \
+					 CURRENT_HOT_PLUG_CNCT | \
+					 CURRENT_GTO_TIMEOUT | \
+					 CURRENT_DEVICE_PRESENT | \
+					 CURRENT_OOB_ERROR )
+
+#define		CURRENT_ERR_MASK	(CURRENT_LOSS_OF_SIGNAL | \
+					 CURRENT_GTO_TIMEOUT | \
+					 CURRENT_OOB_TIMEOUT | \
+					 CURRENT_OOB_ERROR )
+
+#define SPEED_MASK	0x145
+
+#define		SATA_SPEED_30_DIS	0x10
+#define		SATA_SPEED_15_DIS	0x08
+#define		SAS_SPEED_60_DIS	0x04
+#define		SAS_SPEED_30_DIS	0x02
+#define		SAS_SPEED_15_DIS	0x01
+#define		SAS_SPEED_MASK_DEFAULT	0x00
+
+#define OOB_TIMER_ENABLE	0x14D
+
+#define		HOT_PLUG_EN		0x80
+#define		RCD_EN			0x40
+#define 	COMTIMER_EN		0x20
+#define		SNTT_EN			0x10
+#define		SNLT_EN			0x04
+#define		SNWT_EN			0x02
+#define		ALIGN_EN		0x01
+
+#define OOB_STATUS		0x14E
+
+#define		OOB_DONE		0x80
+#define		LOSS_OF_SIGNAL		0x40		/* ro */
+#define		SPINUP_HOLD		0x20
+#define		HOT_PLUG_CNCT		0x10		/* ro */
+#define		GTO_TIMEOUT		0x08		/* ro */
+#define		OOB_TIMEOUT		0x04		/* ro */
+#define		DEVICE_PRESENT		0x02		/* ro */
+#define		OOB_ERROR		0x01		/* ro */
+
+#define		OOB_STATUS_ERROR_MASK	(LOSS_OF_SIGNAL | GTO_TIMEOUT | \
+					 OOB_TIMEOUT | OOB_ERROR)
+
+#define OOB_STATUS_CLEAR	0x14F
+
+#define		OOB_DONE_CLR		0x80
+#define		LOSS_OF_SIGNAL_CLR 	0x40
+#define		SPINUP_HOLD_CLR		0x20
+#define		HOT_PLUG_CNCT_CLR     	0x10
+#define		GTO_TIMEOUT_CLR		0x08
+#define		OOB_TIMEOUT_CLR		0x04
+#define		OOB_ERROR_CLR		0x01
+
+#define HOT_PLUG_DELAY		0x150
+/* In 5 ms units. 20 = 100 ms. */
+#define	HOTPLUG_DELAY_TIMEOUT		20
+
+
+#define INT_ENABLE_2		0x15A
+
+#define		OOB_DONE_EN		0x80
+#define		LOSS_OF_SIGNAL_EN	0x40
+#define		SPINUP_HOLD_EN		0x20
+#define		HOT_PLUG_CNCT_EN	0x10
+#define		GTO_TIMEOUT_EN		0x08
+#define		OOB_TIMEOUT_EN		0x04
+#define		DEVICE_PRESENT_EN	0x02
+#define		OOB_ERROR_EN		0x01
+
+#define PHY_CONTROL_0		0x160
+
+#define		PHY_LOWPWREN_TX		0x80
+#define		PHY_LOWPWREN_RX		0x40
+#define		SPARE_REG_160_B5	0x20
+#define		OFFSET_CANCEL_RX	0x10
+
+/* bits 3:2 */
+#define		PHY_RXCOMCENTER_60V	0x00
+#define		PHY_RXCOMCENTER_70V	0x04
+#define		PHY_RXCOMCENTER_80V	0x08
+#define		PHY_RXCOMCENTER_90V	0x0C
+#define 	PHY_RXCOMCENTER_MASK	0x0C
+
+#define		PHY_RESET		0x02
+#define		SAS_DEFAULT_SEL		0x01
+
+#define PHY_CONTROL_1		0x161
+
+/* bits 2:0 */
+#define		SATA_PHY_DETLEVEL_50mv	0x00
+#define		SATA_PHY_DETLEVEL_75mv	0x01
+#define		SATA_PHY_DETLEVEL_100mv	0x02
+#define		SATA_PHY_DETLEVEL_125mv	0x03
+#define		SATA_PHY_DETLEVEL_150mv	0x04
+#define		SATA_PHY_DETLEVEL_175mv	0x05
+#define		SATA_PHY_DETLEVEL_200mv	0x06
+#define		SATA_PHY_DETLEVEL_225mv	0x07
+#define		SATA_PHY_DETLEVEL_MASK	0x07
+
+/* bits 5:3 */
+#define		SAS_PHY_DETLEVEL_50mv	0x00
+#define		SAS_PHY_DETLEVEL_75mv	0x08
+#define		SAS_PHY_DETLEVEL_100mv	0x10
+#define		SAS_PHY_DETLEVEL_125mv	0x11
+#define		SAS_PHY_DETLEVEL_150mv	0x20
+#define		SAS_PHY_DETLEVEL_175mv	0x21
+#define		SAS_PHY_DETLEVEL_200mv	0x30
+#define		SAS_PHY_DETLEVEL_225mv	0x31
+#define		SAS_PHY_DETLEVEL_MASK	0x38
+
+#define PHY_CONTROL_2		0x162
+
+/* bits 7:5 */
+#define 	SATA_PHY_DRV_400mv	0x00
+#define 	SATA_PHY_DRV_450mv	0x20
+#define 	SATA_PHY_DRV_500mv	0x40
+#define 	SATA_PHY_DRV_550mv	0x60
+#define 	SATA_PHY_DRV_600mv	0x80
+#define 	SATA_PHY_DRV_650mv	0xA0
+#define 	SATA_PHY_DRV_725mv	0xC0
+#define 	SATA_PHY_DRV_800mv	0xE0
+#define		SATA_PHY_DRV_MASK	0xE0
+
+/* bits 4:3 */
+#define 	SATA_PREEMP_0		0x00
+#define 	SATA_PREEMP_1		0x08
+#define 	SATA_PREEMP_2		0x10
+#define 	SATA_PREEMP_3		0x18
+#define 	SATA_PREEMP_MASK	0x18
+
+#define 	SATA_CMSH1P5		0x04
+
+/* bits 1:0 */
+#define 	SATA_SLEW_0		0x00
+#define 	SATA_SLEW_1		0x01
+#define 	SATA_SLEW_2		0x02
+#define 	SATA_SLEW_3		0x03
+#define 	SATA_SLEW_MASK		0x03
+
+#define PHY_CONTROL_3		0x163
+
+/* bits 7:5 */
+#define 	SAS_PHY_DRV_400mv	0x00
+#define 	SAS_PHY_DRV_450mv	0x20
+#define 	SAS_PHY_DRV_500mv	0x40
+#define 	SAS_PHY_DRV_550mv	0x60
+#define 	SAS_PHY_DRV_600mv	0x80
+#define 	SAS_PHY_DRV_650mv	0xA0
+#define 	SAS_PHY_DRV_725mv	0xC0
+#define 	SAS_PHY_DRV_800mv	0xE0
+#define		SAS_PHY_DRV_MASK	0xE0
+
+/* bits 4:3 */
+#define 	SAS_PREEMP_0		0x00
+#define 	SAS_PREEMP_1		0x08
+#define 	SAS_PREEMP_2		0x10
+#define 	SAS_PREEMP_3		0x18
+#define 	SAS_PREEMP_MASK		0x18
+
+#define 	SAS_CMSH1P5		0x04
+
+/* bits 1:0 */
+#define 	SAS_SLEW_0		0x00
+#define 	SAS_SLEW_1		0x01
+#define 	SAS_SLEW_2		0x02
+#define 	SAS_SLEW_3		0x03
+#define 	SAS_SLEW_MASK		0x03
+
+#define PHY_CONTROL_4		0x168
+
+#define		PHY_DONE_CAL_TX		0x80
+#define		PHY_DONE_CAL_RX		0x40
+#define		RX_TERM_LOAD_DIS	0x20
+#define		TX_TERM_LOAD_DIS	0x10
+#define		AUTO_TERM_CAL_DIS	0x08
+#define		PHY_SIGDET_FLTR_EN	0x04
+#define		OSC_FREQ		0x02
+#define		PHY_START_CAL		0x01
+
+/*
+ * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
+ */
+#define PCIX_REG_BASE_ADR		0xB8040000
+
+#define PCIC_VENDOR_ID	0x00
+
+#define PCIC_DEVICE_ID	0x02
+
+#define PCIC_COMMAND	0x04
+
+#define		INT_DIS			0x0400
+#define		FBB_EN			0x0200		/* ro */
+#define		SERR_EN			0x0100
+#define		STEP_EN			0x0080		/* ro */
+#define		PERR_EN			0x0040
+#define		VGA_EN			0x0020		/* ro */
+#define		MWI_EN			0x0010
+#define		SPC_EN			0x0008
+#define		MST_EN			0x0004
+#define		MEM_EN			0x0002
+#define		IO_EN			0x0001
+
+#define	PCIC_STATUS	0x06
+
+#define		PERR_DET		0x8000
+#define		SERR_GEN		0x4000
+#define		MABT_DET		0x2000
+#define		TABT_DET		0x1000
+#define		TABT_GEN		0x0800
+#define		DPERR_DET		0x0100
+#define		CAP_LIST		0x0010
+#define		INT_STAT		0x0008
+
+#define	PCIC_DEVREV_ID	0x08
+
+#define	PCIC_CLASS_CODE	0x09
+
+#define	PCIC_CACHELINE_SIZE	0x0C
+
+#define	PCIC_MBAR0	0x10
+
+#define 	PCIC_MBAR0_OFFSET	0
+
+#define	PCIC_MBAR1	0x18
+
+#define 	PCIC_MBAR1_OFFSET	2
+
+#define	PCIC_IOBAR	0x20
+
+#define 	PCIC_IOBAR_OFFSET	4
+
+#define	PCIC_SUBVENDOR_ID	0x2C
+
+#define PCIC_SUBSYTEM_ID	0x2E
+
+#define PCIX_STATUS		0x44
+#define 	RCV_SCE		0x20000000
+#define 	UNEXP_SC	0x00080000
+#define 	SC_DISCARD	0x00040000
+
+#define ECC_CTRL_STAT		0x48
+#define 	UNCOR_ECCERR	0x00000008
+
+#define PCIC_PM_CSR		0x5C
+
+#define		PWR_STATE_D0		0
+#define		PWR_STATE_D1		1	/* not supported */
+#define		PWR_STATE_D2		2 	/* not supported */
+#define		PWR_STATE_D3		3
+
+#define PCIC_BASE1	0x6C	/* internal use only */
+
+#define		BASE1_RSVD		0xFFFFFFF8
+
+#define PCIC_BASEA	0x70	/* internal use only */
+
+#define		BASEA_RSVD		0xFFFFFFC0
+#define 	BASEA_START		0
+
+#define PCIC_BASEB	0x74	/* internal use only */
+
+#define		BASEB_RSVD		0xFFFFFF80
+#define		BASEB_IOMAP_MASK	0x7F
+#define 	BASEB_START		0x80
+
+#define PCIC_BASEC	0x78	/* internal use only */
+
+#define		BASEC_RSVD		0xFFFFFFFC
+#define 	BASEC_MASK		0x03
+#define 	BASEC_START		0x58
+
+#define PCIC_MBAR_KEY	0x7C	/* internal use only */
+
+#define 	MBAR_KEY_MASK		0xFFFFFFFF
+
+#define PCIC_HSTPCIX_CNTRL	0xA0
+
+#define 	REWIND_DIS		0x0800
+
+#define PCIC_MBAR0_MASK	0xA8
+#define		PCIC_MBAR0_SIZE_MASK 	0x1FFFE000
+#define		PCIC_MBAR0_SIZE_SHIFT 	13
+#define		PCIC_MBAR0_SIZE(val)	\
+		    (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT)
+
+#define PCIC_FLASH_MBAR	0xB8
+
+#define PCIC_INTRPT_STAT 0xD4
+
+#define PCIC_TP_CTRL	0xFC
+
+/*
+ * EXSI Registers, Addresss Range: (0x00-0xFC)
+ */
+#define EXSI_REG_BASE_ADR		REG_BASE_ADDR_EXSI
+
+#define	EXSICNFGR	(EXSI_REG_BASE_ADR + 0x00)
+
+#define		OCMINITIALIZED		0x80000000
+#define		ASIEN			0x00400000
+#define		HCMODE			0x00200000
+#define		PCIDEF			0x00100000
+#define		COMSTOCK		0x00080000
+#define		SEEPROMEND		0x00040000
+#define		MSTTIMEN		0x00020000
+#define		XREGEX			0x00000200
+#define		NVRAMW			0x00000100
+#define		NVRAMEX			0x00000080
+#define		SRAMW			0x00000040
+#define		SRAMEX			0x00000020
+#define		FLASHW			0x00000010
+#define		FLASHEX			0x00000008
+#define		SEEPROMCFG		0x00000004
+#define		SEEPROMTYP		0x00000002
+#define		SEEPROMEX		0x00000001
+
+
+#define EXSICNTRLR	(EXSI_REG_BASE_ADR + 0x04)
+
+#define		MODINT_EN		0x00000001
+
+
+#define PMSTATR		(EXSI_REG_BASE_ADR + 0x10)
+
+#define		FLASHRST		0x00000002
+#define		FLASHRDY		0x00000001
+
+
+#define FLCNFGR		(EXSI_REG_BASE_ADR + 0x14)
+
+#define		FLWEH_MASK		0x30000000
+#define		FLWESU_MASK		0x0C000000
+#define		FLWEPW_MASK		0x03F00000
+#define		FLOEH_MASK		0x000C0000
+#define 	FLOESU_MASK		0x00030000
+#define 	FLOEPW_MASK		0x0000FC00
+#define 	FLCSH_MASK		0x00000300
+#define 	FLCSSU_MASK		0x000000C0
+#define 	FLCSPW_MASK		0x0000003F
+
+#define SRCNFGR		(EXSI_REG_BASE_ADR + 0x18)
+
+#define		SRWEH_MASK		0x30000000
+#define		SRWESU_MASK		0x0C000000
+#define		SRWEPW_MASK		0x03F00000
+
+#define		SROEH_MASK		0x000C0000
+#define 	SROESU_MASK		0x00030000
+#define 	SROEPW_MASK		0x0000FC00
+#define		SRCSH_MASK		0x00000300
+#define		SRCSSU_MASK		0x000000C0
+#define		SRCSPW_MASK		0x0000003F
+
+#define NVCNFGR		(EXSI_REG_BASE_ADR + 0x1C)
+
+#define 	NVWEH_MASK		0x30000000
+#define 	NVWESU_MASK		0x0C000000
+#define 	NVWEPW_MASK		0x03F00000
+#define 	NVOEH_MASK		0x000C0000
+#define 	NVOESU_MASK		0x00030000
+#define 	NVOEPW_MASK		0x0000FC00
+#define 	NVCSH_MASK		0x00000300
+#define 	NVCSSU_MASK		0x000000C0
+#define 	NVCSPW_MASK		0x0000003F
+
+#define XRCNFGR		(EXSI_REG_BASE_ADR + 0x20)
+
+#define 	XRWEH_MASK		0x30000000
+#define 	XRWESU_MASK		0x0C000000
+#define 	XRWEPW_MASK		0x03F00000
+#define 	XROEH_MASK		0x000C0000
+#define 	XROESU_MASK		0x00030000
+#define 	XROEPW_MASK		0x0000FC00
+#define 	XRCSH_MASK		0x00000300
+#define 	XRCSSU_MASK		0x000000C0
+#define		XRCSPW_MASK		0x0000003F
+
+#define XREGADDR	(EXSI_REG_BASE_ADR + 0x24)
+
+#define 	XRADDRINCEN		0x80000000
+#define 	XREGADD_MASK		0x007FFFFF
+
+
+#define XREGDATAR	(EXSI_REG_BASE_ADR + 0x28)
+
+#define		XREGDATA_MASK 		0x0000FFFF
+
+#define GPIOOER		(EXSI_REG_BASE_ADR + 0x40)
+
+#define GPIOODENR	(EXSI_REG_BASE_ADR + 0x44)
+
+#define GPIOINVR	(EXSI_REG_BASE_ADR + 0x48)
+
+#define GPIODATAOR	(EXSI_REG_BASE_ADR + 0x4C)
+
+#define GPIODATAIR	(EXSI_REG_BASE_ADR + 0x50)
+
+#define GPIOCNFGR	(EXSI_REG_BASE_ADR + 0x54)
+
+#define		GPIO_EXTSRC		0x00000001
+
+#define SCNTRLR		(EXSI_REG_BASE_ADR + 0xA0)
+
+#define 	SXFERDONE		0x00000100
+#define 	SXFERCNT_MASK		0x000000E0
+#define 	SCMDTYP_MASK		0x0000001C
+#define 	SXFERSTART		0x00000002
+#define 	SXFEREN			0x00000001
+
+#define	SRATER		(EXSI_REG_BASE_ADR + 0xA4)
+
+#define	SADDRR		(EXSI_REG_BASE_ADR + 0xA8)
+
+#define 	SADDR_MASK		0x0000FFFF
+
+#define SDATAOR		(EXSI_REG_BASE_ADR + 0xAC)
+
+#define	SDATAOR0	(EXSI_REG_BASE_ADR + 0xAC)
+#define SDATAOR1	(EXSI_REG_BASE_ADR + 0xAD)
+#define SDATAOR2	(EXSI_REG_BASE_ADR + 0xAE)
+#define SDATAOR3	(EXSI_REG_BASE_ADR + 0xAF)
+
+#define SDATAIR		(EXSI_REG_BASE_ADR + 0xB0)
+
+#define SDATAIR0	(EXSI_REG_BASE_ADR + 0xB0)
+#define SDATAIR1	(EXSI_REG_BASE_ADR + 0xB1)
+#define SDATAIR2	(EXSI_REG_BASE_ADR + 0xB2)
+#define SDATAIR3	(EXSI_REG_BASE_ADR + 0xB3)
+
+#define ASISTAT0R	(EXSI_REG_BASE_ADR + 0xD0)
+#define 	ASIFMTERR		0x00000400
+#define 	ASISEECHKERR		0x00000200
+#define 	ASIERR			0x00000100
+
+#define ASISTAT1R	(EXSI_REG_BASE_ADR + 0xD4)
+#define 	CHECKSUM_MASK		0x0000FFFF
+
+#define ASIERRADDR	(EXSI_REG_BASE_ADR + 0xD8)
+#define ASIERRDATAR	(EXSI_REG_BASE_ADR + 0xDC)
+#define ASIERRSTATR	(EXSI_REG_BASE_ADR + 0xE0)
+#define 	CPI2ASIBYTECNT_MASK	0x00070000
+#define 	CPI2ASIBYTEEN_MASK      0x0000F000
+#define 	CPI2ASITARGERR_MASK	0x00000F00
+#define 	CPI2ASITARGMID_MASK	0x000000F0
+#define 	CPI2ASIMSTERR_MASK	0x0000000F
+
+/*
+ * XSRAM, External SRAM (DWord and any BE pattern accessible)
+ */
+#define XSRAM_REG_BASE_ADDR             0xB8100000
+#define XSRAM_SIZE                        0x100000
+
+/*
+ * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF).
+ */
+#define		NVRAM_REG_BASE_ADR	0xBF800000
+#define		NVRAM_MAX_BASE_ADR	0x003FFFFF
+
+/* OCM base address */
+#define		OCM_BASE_ADDR		0xA0000000
+#define		OCM_MAX_SIZE		0x20000
+
+/*
+ * Sequencers (Central and Link) Scratch RAM page definitions.
+ */
+
+/*
+ * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024
+ * byte memory.  It is dword accessible and has byte parity
+ * protection. The CSEQ accesses it in 32 byte windows, either as mode
+ * dependent or mode independent memory. Each mode has 96 bytes,
+ * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of
+ * Mode Independent memory (four 32 byte pages 3-7). Note that mode
+ * dependent scratch memory, Mode 8, page 0-3 overlaps mode
+ * independent scratch memory, pages 0-3.
+ * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and
+ * 128 bytes in mode 8,
+ * - 259 bytes of mode independent scratch, common to modes 0-15.
+ *
+ * Sequencer scratch RAM is 1024 bytes.  This scratch memory is
+ * divided into mode dependent and mode independent scratch with this
+ * memory further subdivided into pages of size 32 bytes. There are 5
+ * pages (160 bytes) of mode independent scratch and 3 pages of
+ * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages
+ * 0-2 dependent scratch overlap with pages 0-2 of mode independent
+ * scratch memory.
+ *
+ * The host accesses this scratch in a different manner from the
+ * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE
+ * and CMnSCRPAGE to access the scratch memory. A flat mapping of the
+ * scratch memory is avaliable for software convenience and to prevent
+ * corruption while the sequencer is running. This memory is mapped
+ * onto addresses 800h - BFFh, total of 400h bytes.
+ *
+ * These addresses are mapped as follows:
+ *
+ *        800h-83Fh   Mode Dependent Scratch Mode 0 Pages 0-1
+ *        840h-87Fh   Mode Dependent Scratch Mode 1 Pages 0-1
+ *        880h-8BFh   Mode Dependent Scratch Mode 2 Pages 0-1
+ *        8C0h-8FFh   Mode Dependent Scratch Mode 3 Pages 0-1
+ *        900h-93Fh   Mode Dependent Scratch Mode 4 Pages 0-1
+ *        940h-97Fh   Mode Dependent Scratch Mode 5 Pages 0-1
+ *        980h-9BFh   Mode Dependent Scratch Mode 6 Pages 0-1
+ *        9C0h-9FFh   Mode Dependent Scratch Mode 7 Pages 0-1
+ *        A00h-A5Fh   Mode Dependent Scratch Mode 8 Pages 0-2
+ *                    Mode Independent Scratch Pages 0-2
+ *        A60h-A7Fh   Mode Dependent Scratch Mode 8 Page 3
+ *                    Mode Independent Scratch Page 3
+ *        A80h-AFFh   Mode Independent Scratch Pages 4-7
+ *        B00h-B1Fh   Mode Dependent Scratch Mode 0 Page 2
+ *        B20h-B3Fh   Mode Dependent Scratch Mode 1 Page 2
+ *        B40h-B5Fh   Mode Dependent Scratch Mode 2 Page 2
+ *        B60h-B7Fh   Mode Dependent Scratch Mode 3 Page 2
+ *        B80h-B9Fh   Mode Dependent Scratch Mode 4 Page 2
+ *        BA0h-BBFh   Mode Dependent Scratch Mode 5 Page 2
+ *        BC0h-BDFh   Mode Dependent Scratch Mode 6 Page 2
+ *        BE0h-BFFh   Mode Dependent Scratch Mode 7 Page 2
+ */
+
+/* General macros */
+#define CSEQ_PAGE_SIZE			32  /* Scratch page size (in bytes) */
+
+/* All macros start with offsets from base + 0x800 (CMAPPEDSCR).
+ * Mode dependent scratch page 0, mode 0.
+ * For modes 1-7 you have to do arithmetic. */
+#define CSEQ_LRM_SAVE_SINDEX		(CMAPPEDSCR + 0x0000)
+#define CSEQ_LRM_SAVE_SCBPTR		(CMAPPEDSCR + 0x0002)
+#define CSEQ_Q_LINK_HEAD		(CMAPPEDSCR + 0x0004)
+#define CSEQ_Q_LINK_TAIL		(CMAPPEDSCR + 0x0006)
+#define CSEQ_LRM_SAVE_SCRPAGE		(CMAPPEDSCR + 0x0008)
+
+/* Mode dependent scratch page 0 mode 8 macros. */
+#define CSEQ_RET_ADDR			(CMAPPEDSCR + 0x0200)
+#define CSEQ_RET_SCBPTR			(CMAPPEDSCR + 0x0202)
+#define CSEQ_SAVE_SCBPTR		(CMAPPEDSCR + 0x0204)
+#define CSEQ_EMPTY_TRANS_CTX		(CMAPPEDSCR + 0x0206)
+#define CSEQ_RESP_LEN			(CMAPPEDSCR + 0x0208)
+#define CSEQ_TMF_SCBPTR			(CMAPPEDSCR + 0x020A)
+#define CSEQ_GLOBAL_PREV_SCB		(CMAPPEDSCR + 0x020C)
+#define CSEQ_GLOBAL_HEAD		(CMAPPEDSCR + 0x020E)
+#define CSEQ_CLEAR_LU_HEAD		(CMAPPEDSCR + 0x0210)
+#define CSEQ_TMF_OPCODE			(CMAPPEDSCR + 0x0212)
+#define CSEQ_SCRATCH_FLAGS		(CMAPPEDSCR + 0x0213)
+#define CSEQ_HSB_SITE                   (CMAPPEDSCR + 0x021A)
+#define CSEQ_FIRST_INV_SCB_SITE		(CMAPPEDSCR + 0x021C)
+#define CSEQ_FIRST_INV_DDB_SITE		(CMAPPEDSCR + 0x021E)
+
+/* Mode dependent scratch page 1 mode 8 macros. */
+#define CSEQ_LUN_TO_CLEAR		(CMAPPEDSCR + 0x0220)
+#define CSEQ_LUN_TO_CHECK		(CMAPPEDSCR + 0x0228)
+
+/* Mode dependent scratch page 2 mode 8 macros */
+#define CSEQ_HQ_NEW_POINTER		(CMAPPEDSCR + 0x0240)
+#define CSEQ_HQ_DONE_BASE		(CMAPPEDSCR + 0x0248)
+#define CSEQ_HQ_DONE_POINTER		(CMAPPEDSCR + 0x0250)
+#define CSEQ_HQ_DONE_PASS		(CMAPPEDSCR + 0x0254)
+
+/* Mode independent scratch page 4 macros. */
+#define CSEQ_Q_EXE_HEAD			(CMAPPEDSCR + 0x0280)
+#define CSEQ_Q_EXE_TAIL			(CMAPPEDSCR + 0x0282)
+#define CSEQ_Q_DONE_HEAD                (CMAPPEDSCR + 0x0284)
+#define CSEQ_Q_DONE_TAIL                (CMAPPEDSCR + 0x0286)
+#define CSEQ_Q_SEND_HEAD		(CMAPPEDSCR + 0x0288)
+#define CSEQ_Q_SEND_TAIL		(CMAPPEDSCR + 0x028A)
+#define CSEQ_Q_DMA2CHIM_HEAD		(CMAPPEDSCR + 0x028C)
+#define CSEQ_Q_DMA2CHIM_TAIL		(CMAPPEDSCR + 0x028E)
+#define CSEQ_Q_COPY_HEAD		(CMAPPEDSCR + 0x0290)
+#define CSEQ_Q_COPY_TAIL		(CMAPPEDSCR + 0x0292)
+#define CSEQ_REG0			(CMAPPEDSCR + 0x0294)
+#define CSEQ_REG1			(CMAPPEDSCR + 0x0296)
+#define CSEQ_REG2			(CMAPPEDSCR + 0x0298)
+#define CSEQ_LINK_CTL_Q_MAP		(CMAPPEDSCR + 0x029C)
+#define CSEQ_MAX_CSEQ_MODE		(CMAPPEDSCR + 0x029D)
+#define CSEQ_FREE_LIST_HACK_COUNT	(CMAPPEDSCR + 0x029E)
+
+/* Mode independent scratch page 5 macros. */
+#define CSEQ_EST_NEXUS_REQ_QUEUE	(CMAPPEDSCR + 0x02A0)
+#define CSEQ_EST_NEXUS_REQ_COUNT	(CMAPPEDSCR + 0x02A8)
+#define CSEQ_Q_EST_NEXUS_HEAD		(CMAPPEDSCR + 0x02B0)
+#define CSEQ_Q_EST_NEXUS_TAIL		(CMAPPEDSCR + 0x02B2)
+#define CSEQ_NEED_EST_NEXUS_SCB		(CMAPPEDSCR + 0x02B4)
+#define CSEQ_EST_NEXUS_REQ_HEAD		(CMAPPEDSCR + 0x02B6)
+#define CSEQ_EST_NEXUS_REQ_TAIL		(CMAPPEDSCR + 0x02B7)
+#define CSEQ_EST_NEXUS_SCB_OFFSET	(CMAPPEDSCR + 0x02B8)
+
+/* Mode independent scratch page 6 macros. */
+#define CSEQ_INT_ROUT_RET_ADDR0		(CMAPPEDSCR + 0x02C0)
+#define CSEQ_INT_ROUT_RET_ADDR1		(CMAPPEDSCR + 0x02C2)
+#define CSEQ_INT_ROUT_SCBPTR		(CMAPPEDSCR + 0x02C4)
+#define CSEQ_INT_ROUT_MODE		(CMAPPEDSCR + 0x02C6)
+#define CSEQ_ISR_SCRATCH_FLAGS		(CMAPPEDSCR + 0x02C7)
+#define CSEQ_ISR_SAVE_SINDEX		(CMAPPEDSCR + 0x02C8)
+#define CSEQ_ISR_SAVE_DINDEX		(CMAPPEDSCR + 0x02CA)
+#define CSEQ_SLS_SAVE_ACCUM		(CMAPPEDSCR + 0x02CC)
+#define CSEQ_SLS_SAVE_SINDEX		(CMAPPEDSCR + 0x02CE)
+#define CSEQ_Q_MONIRTT_HEAD		(CMAPPEDSCR + 0x02D0)
+#define CSEQ_Q_MONIRTT_TAIL		(CMAPPEDSCR + 0x02D2)
+#define CSEQ_FREE_SCB_MASK		(CMAPPEDSCR + 0x02D5)
+#define CSEQ_BUILTIN_FREE_SCB_HEAD	(CMAPPEDSCR + 0x02D6)
+#define CSEQ_BUILTIN_FREE_SCB_TAIL	(CMAPPEDSCR + 0x02D8)
+#define CSEQ_EXTENDED_FREE_SCB_HEAD	(CMAPPEDSCR + 0x02DA)
+#define CSEQ_EXTENDED_FREE_SCB_TAIL	(CMAPPEDSCR + 0x02DC)
+
+/* Mode independent scratch page 7 macros. */
+#define CSEQ_EMPTY_REQ_QUEUE		(CMAPPEDSCR + 0x02E0)
+#define CSEQ_EMPTY_REQ_COUNT		(CMAPPEDSCR + 0x02E8)
+#define CSEQ_Q_EMPTY_HEAD		(CMAPPEDSCR + 0x02F0)
+#define CSEQ_Q_EMPTY_TAIL		(CMAPPEDSCR + 0x02F2)
+#define CSEQ_NEED_EMPTY_SCB		(CMAPPEDSCR + 0x02F4)
+#define CSEQ_EMPTY_REQ_HEAD		(CMAPPEDSCR + 0x02F6)
+#define CSEQ_EMPTY_REQ_TAIL		(CMAPPEDSCR + 0x02F7)
+#define CSEQ_EMPTY_SCB_OFFSET		(CMAPPEDSCR + 0x02F8)
+#define CSEQ_PRIMITIVE_DATA		(CMAPPEDSCR + 0x02FA)
+#define CSEQ_TIMEOUT_CONST		(CMAPPEDSCR + 0x02FC)
+
+/***************************************************************************
+* Link m Sequencer scratch RAM is 512 bytes.
+* This scratch memory is divided into mode dependent and mode
+* independent scratch with this memory further subdivided into
+* pages of size 32 bytes. There are 4 pages (128 bytes) of
+* mode independent scratch and 4 pages of dependent scratch
+* memory for modes 0-2 (384 bytes).
+*
+* The host accesses this scratch in a different manner from the
+* link sequencer. The sequencer has to use LSEQ registers
+* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat
+* mapping of the scratch memory is avaliable for software
+* convenience and to prevent corruption while the sequencer is
+* running. This memory is mapped onto addresses 800h - 9FFh.
+*
+* These addresses are mapped as follows:
+*
+*        800h-85Fh   Mode Dependent Scratch Mode 0 Pages 0-2
+*        860h-87Fh   Mode Dependent Scratch Mode 0 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 0
+*        880h-8DFh   Mode Dependent Scratch Mode 1 Pages 0-2
+*        8E0h-8FFh   Mode Dependent Scratch Mode 1 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 1
+*        900h-95Fh   Mode Dependent Scratch Mode 2 Pages 0-2
+*        960h-97Fh   Mode Dependent Scratch Mode 2 Page 3
+*                    Mode Dependent Scratch Mode 5 Page 2
+*        980h-9DFh   Mode Independent Scratch Pages 0-3
+*        9E0h-9FFh   Mode Independent Scratch Page 3
+*                    Mode Dependent Scratch Mode 5 Page 3
+*
+****************************************************************************/
+/* General macros */
+#define LSEQ_MODE_SCRATCH_SIZE		0x80 /* Size of scratch RAM per mode */
+#define LSEQ_PAGE_SIZE			0x20 /* Scratch page size (in bytes) */
+#define LSEQ_MODE5_PAGE0_OFFSET 	0x60
+
+/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */
+/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */
+#define LmSEQ_RET_ADDR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0000)
+#define LmSEQ_REG0_MODE(LinkNum)	(LmSCRATCH(LinkNum) + 0x0002)
+#define LmSEQ_MODE_FLAGS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0004)
+
+/* Mode flag macros (byte 0) */
+#define		SAS_SAVECTX_OCCURRED		0x80
+#define		SAS_OOBSVC_OCCURRED		0x40
+#define		SAS_OOB_DEVICE_PRESENT		0x20
+#define		SAS_CFGHDR_OCCURRED		0x10
+#define		SAS_RCV_INTS_ARE_DISABLED	0x08
+#define		SAS_OOB_HOT_PLUG_CNCT		0x04
+#define		SAS_AWAIT_OPEN_CONNECTION	0x02
+#define		SAS_CFGCMPLT_OCCURRED		0x01
+
+/* Mode flag macros (byte 1) */
+#define		SAS_RLSSCB_OCCURRED		0x80
+#define		SAS_FORCED_HEADER_MISS		0x40
+
+#define LmSEQ_RET_ADDR2(LinkNum)	(LmSCRATCH(LinkNum) + 0x0006)
+#define LmSEQ_RET_ADDR1(LinkNum)	(LmSCRATCH(LinkNum) + 0x0008)
+#define LmSEQ_OPCODE_TO_CSEQ(LinkNum)	(LmSCRATCH(LinkNum) + 0x000B)
+#define LmSEQ_DATA_TO_CSEQ(LinkNum)	(LmSCRATCH(LinkNum) + 0x000C)
+
+/* Mode dependent scratch page 0 macros for mode 0 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum)	(LmSCRATCH(LinkNum) + 0x000E)
+#define LmSEQ_EMPTY_TRANS_CTX(LinkNum)		(LmSCRATCH(LinkNum) + 0x0010)
+#define LmSEQ_RESP_LEN(LinkNum)			(LmSCRATCH(LinkNum) + 0x0012)
+#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum)	(LmSCRATCH(LinkNum) + 0x0014)
+#define LmSEQ_INTEN_SAVE(LinkNum)		(LmSCRATCH(LinkNum) + 0x0016)
+#define LmSEQ_LINK_RST_FRM_LEN(LinkNum)		(LmSCRATCH(LinkNum) + 0x001A)
+#define LmSEQ_LINK_RST_PROTOCOL(LinkNum)	(LmSCRATCH(LinkNum) + 0x001B)
+#define LmSEQ_RESP_STATUS(LinkNum)		(LmSCRATCH(LinkNum) + 0x001C)
+#define LmSEQ_LAST_LOADED_SGE(LinkNum)		(LmSCRATCH(LinkNum) + 0x001D)
+#define LmSEQ_SAVE_SCBPTR(LinkNum)		(LmSCRATCH(LinkNum) + 0x001E)
+
+/* Mode dependent scratch page 0 macros for mode 1 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_Q_XMIT_HEAD(LinkNum)		(LmSCRATCH(LinkNum) + 0x008E)
+#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum)	(LmSCRATCH(LinkNum) + 0x0090)
+#define LmSEQ_INI_CONN_TAG(LinkNum)		(LmSCRATCH(LinkNum) + 0x0092)
+#define LmSEQ_FAILED_OPEN_STATUS(LinkNum)	(LmSCRATCH(LinkNum) + 0x009A)
+#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum)	(LmSCRATCH(LinkNum) + 0x009B)
+#define LmSEQ_M1_RESP_STATUS(LinkNum)		(LmSCRATCH(LinkNum) + 0x009C)
+#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum)	(LmSCRATCH(LinkNum) + 0x009D)
+#define LmSEQ_M1_SAVE_SCBPTR(LinkNum)		(LmSCRATCH(LinkNum) + 0x009E)
+
+/* Mode dependent scratch page 0 macros for mode 2 (non-common) */
+#define LmSEQ_PORT_COUNTER(LinkNum)		(LmSCRATCH(LinkNum) + 0x010E)
+#define LmSEQ_PM_TABLE_PTR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0110)
+#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum)	(LmSCRATCH(LinkNum) + 0x0112)
+#define LmSEQ_IP_BITL(LinkNum)			(LmSCRATCH(LinkNum) + 0x0114)
+#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum)	(LmSCRATCH(LinkNum) + 0x0116)
+#define LmSEQ_P0M2_OFFS1AH(LinkNum)		(LmSCRATCH(LinkNum) + 0x011A)
+
+/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_SAVED_OOB_STATUS(LinkNum)		(LmSCRATCH(LinkNum) + 0x006E)
+#define LmSEQ_SAVED_OOB_MODE(LinkNum)		(LmSCRATCH(LinkNum) + 0x006F)
+#define LmSEQ_Q_LINK_HEAD(LinkNum)		(LmSCRATCH(LinkNum) + 0x0070)
+#define LmSEQ_LINK_RST_ERR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0072)
+#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0073)
+#define LmSEQ_SAS_RESET_MODE(LinkNum)		(LmSCRATCH(LinkNum) + 0x0074)
+#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum)	(LmSCRATCH(LinkNum) + 0x0075)
+#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum)	(LmSCRATCH(LinkNum) + 0x0076)
+#define LmSEQ_OOB_INT_ENABLES(LinkNum)		(LmSCRATCH(LinkNum) + 0x007A)
+#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x007C)
+#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum)	(LmSCRATCH(LinkNum) + 0x007E)
+
+/* Mode dependent scratch page 1, mode 0 and mode 1 */
+#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum)        (LmSCRATCH(LinkNum) + 0x0020)
+#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum)        (LmSCRATCH(LinkNum) + 0x0030)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum)     (LmSCRATCH(LinkNum) + 0x00A0)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum)     (LmSCRATCH(LinkNum) + 0x00B0)
+
+/* Mode dependent scratch page 1 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_INVALID_DWORD_COUNT(LinkNum)	(LmSCRATCH(LinkNum) + 0x0120)
+#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) 	(LmSCRATCH(LinkNum) + 0x0124)
+#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum)	(LmSCRATCH(LinkNum) + 0x0128)
+
+/* Mode dependent scratch page 1 macros for mode 4/5 */
+#define LmSEQ_FRAME_TYPE_MASK(LinkNum)	      (LmSCRATCH(LinkNum) + 0x00E0)
+#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum)  (LmSCRATCH(LinkNum) + 0x00E1)
+#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4)
+#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum)   (LmSCRATCH(LinkNum) + 0x00E5)
+#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum)    (LmSCRATCH(LinkNum) + 0x00EB)
+#define LmSEQ_TAG_MASK(LinkNum)		      (LmSCRATCH(LinkNum) + 0x00F0)
+#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum)   (LmSCRATCH(LinkNum) + 0x00F2)
+#define LmSEQ_DATA_OFFSET(LinkNum)	      (LmSCRATCH(LinkNum) + 0x00F4)
+
+/* Mode dependent scratch page 2 macros for mode 0 */
+/* Absolute offsets */
+#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0040)
+#define LmSEQ_DEVICE_BITS(LinkNum)		(LmSCRATCH(LinkNum) + 0x005B)
+#define LmSEQ_SDB_DDB(LinkNum)			(LmSCRATCH(LinkNum) + 0x005C)
+#define LmSEQ_SDB_NUM_TAGS(LinkNum)		(LmSCRATCH(LinkNum) + 0x005E)
+#define LmSEQ_SDB_CURR_TAG(LinkNum)		(LmSCRATCH(LinkNum) + 0x005F)
+
+/* Mode dependent scratch page 2 macros for mode 1 */
+/* Absolute offsets */
+/* byte 0 bits 1-0 are domain select. */
+#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum)		(LmSCRATCH(LinkNum) + 0x00C0)
+#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x00C8)
+#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x00CC)
+#define LmSEQ_LAST_LOADED_SG_EL(LinkNum)	(LmSCRATCH(LinkNum) + 0x00D4)
+
+/* Mode dependent scratch page 2 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140)
+#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0144)
+#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0148)
+#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x014C)
+#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \
+						(LmSCRATCH(LinkNum) + 0x0150)
+#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0154)
+
+/* Mode dependent scratch page 2 macros for mode 5 */
+#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0160)
+#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0164)
+#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0168)
+#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum)	(LmSCRATCH(LinkNum) + 0x016C)
+
+/* Mode dependent scratch page 3 macros for modes 0 and 1 */
+/* None defined */
+
+/* Mode dependent scratch page 3 macros for modes 2 and 5 */
+/* None defined */
+
+/* Mode Independent Scratch page 0 macros. */
+#define LmSEQ_Q_TGTXFR_HEAD(LinkNum)	(LmSCRATCH(LinkNum) + 0x0180)
+#define LmSEQ_Q_TGTXFR_TAIL(LinkNum)	(LmSCRATCH(LinkNum) + 0x0182)
+#define LmSEQ_LINK_NUMBER(LinkNum)	(LmSCRATCH(LinkNum) + 0x0186)
+#define LmSEQ_SCRATCH_FLAGS(LinkNum)	(LmSCRATCH(LinkNum) + 0x0187)
+/*
+ * Currently only bit 0, SAS_DWSAQD, is used.
+ */
+#define		SAS_DWSAQD			0x01  /*
+						       * DWSSTATUS: DWSAQD
+						       * bit las read in ISR.
+						       */
+#define  LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188)
+/* Connection states (byte 0) */
+#define		SAS_WE_OPENED_CS		0x01
+#define		SAS_DEVICE_OPENED_CS		0x02
+#define		SAS_WE_SENT_DONE_CS		0x04
+#define		SAS_DEVICE_SENT_DONE_CS		0x08
+#define		SAS_WE_SENT_CLOSE_CS		0x10
+#define		SAS_DEVICE_SENT_CLOSE_CS	0x20
+#define		SAS_WE_SENT_BREAK_CS		0x40
+#define		SAS_DEVICE_SENT_BREAK_CS	0x80
+/* Connection states (byte 1) */
+#define		SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS	0x01
+#define		SAS_AIP_RECEIVED_CS		0x02
+#define		SAS_CREDIT_TIMEOUT_OCCURRED_CS	0x04
+#define		SAS_ACKNAK_TIMEOUT_OCCURRED_CS	0x08
+#define		SAS_SMPRSP_TIMEOUT_OCCURRED_CS	0x10
+#define		SAS_DONE_TIMEOUT_OCCURRED_CS	0x20
+/* Connection states (byte 2) */
+#define		SAS_SMP_RESPONSE_RECEIVED_CS	0x01
+#define		SAS_INTLK_TIMEOUT_OCCURRED_CS	0x02
+#define		SAS_DEVICE_SENT_DMAT_CS		0x04
+#define		SAS_DEVICE_SENT_SYNCSRST_CS	0x08
+#define		SAS_CLEARING_AFFILIATION_CS	0x20
+#define		SAS_RXTASK_ACTIVE_CS		0x40
+#define		SAS_TXTASK_ACTIVE_CS		0x80
+/* Connection states (byte 3) */
+#define		SAS_PHY_LOSS_OF_SIGNAL_CS	0x01
+#define		SAS_DWS_TIMER_EXPIRED_CS	0x02
+#define		SAS_LINK_RESET_NOT_COMPLETE_CS	0x04
+#define		SAS_PHY_DISABLED_CS		0x08
+#define		SAS_LINK_CTL_TASK_ACTIVE_CS	0x10
+#define		SAS_PHY_EVENT_TASK_ACTIVE_CS	0x20
+#define		SAS_DEVICE_SENT_ID_FRAME_CS	0x40
+#define		SAS_DEVICE_SENT_REG_FIS_CS	0x40
+#define		SAS_DEVICE_SENT_HARD_RESET_CS	0x80
+#define  	SAS_PHY_IS_DOWN_FLAGS	(SAS_PHY_LOSS_OF_SIGNAL_CS|\
+					 SAS_DWS_TIMER_EXPIRED_CS |\
+					 SAS_LINK_RESET_NOT_COMPLETE_CS|\
+					 SAS_PHY_DISABLED_CS)
+
+#define		SAS_LINK_CTL_PHY_EVENT_FLAGS   (SAS_LINK_CTL_TASK_ACTIVE_CS |\
+						SAS_PHY_EVENT_TASK_ACTIVE_CS |\
+						SAS_DEVICE_SENT_ID_FRAME_CS  |\
+						SAS_DEVICE_SENT_HARD_RESET_CS)
+
+#define LmSEQ_CONCTL(LinkNum)		(LmSCRATCH(LinkNum) + 0x018C)
+#define LmSEQ_CONSTAT(LinkNum)		(LmSCRATCH(LinkNum) + 0x018E)
+#define LmSEQ_CONNECTION_MODES(LinkNum)	(LmSCRATCH(LinkNum) + 0x018F)
+#define LmSEQ_REG1_ISR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0192)
+#define LmSEQ_REG2_ISR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0194)
+#define LmSEQ_REG3_ISR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0196)
+#define LmSEQ_REG0_ISR(LinkNum)		(LmSCRATCH(LinkNum) + 0x0198)
+
+/* Mode independent scratch page 1 macros. */
+#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A0)
+#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A2)
+#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A4)
+#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A6)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A8)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum)	(LmSCRATCH(LinkNum) + 0x01A9)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum)	(LmSCRATCH(LinkNum) + 0x01AA)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum)	(LmSCRATCH(LinkNum) + 0x01AB)
+#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum)	(LmSCRATCH(LinkNum) + 0x01AC)
+#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum)	(LmSCRATCH(LinkNum) + 0x01AD)
+#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum)	(LmSCRATCH(LinkNum) + 0x01AE)
+#define LmSEQ_TIMEOUT_CONST(LinkNum)		(LmSCRATCH(LinkNum) + 0x01B8)
+#define LmSEQ_ISR_SAVE_SINDEX(LinkNum)	        (LmSCRATCH(LinkNum) + 0x01BC)
+#define LmSEQ_ISR_SAVE_DINDEX(LinkNum)	        (LmSCRATCH(LinkNum) + 0x01BE)
+
+/* Mode independent scratch page 2 macros. */
+#define LmSEQ_EMPTY_SCB_PTR0(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C0)
+#define LmSEQ_EMPTY_SCB_PTR1(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C2)
+#define LmSEQ_EMPTY_SCB_PTR2(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C4)
+#define LmSEQ_EMPTY_SCB_PTR3(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C6)
+#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C8)
+#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum)	(LmSCRATCH(LinkNum) + 0x01C9)
+#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum)	(LmSCRATCH(LinkNum) + 0x01CA)
+#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum)	(LmSCRATCH(LinkNum) + 0x01CB)
+#define LmSEQ_EMPTY_SCB_HEAD(LinkNum)	(LmSCRATCH(LinkNum) + 0x01CC)
+#define LmSEQ_EMPTY_SCB_TAIL(LinkNum)	(LmSCRATCH(LinkNum) + 0x01CD)
+#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum)	(LmSCRATCH(LinkNum) + 0x01CE)
+#define LmSEQ_ATA_SCR_REGS(LinkNum)	(LmSCRATCH(LinkNum) + 0x01D4)
+
+/* Mode independent scratch page 3 macros. */
+#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum)	(LmSCRATCH(LinkNum) + 0x01E0)
+#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x01E4)
+#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x01E8)
+#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x01EC)
+#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum)		(LmSCRATCH(LinkNum) + 0x01F0)
+#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x01F4)
+#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum)	(LmSCRATCH(LinkNum) + 0x01F8)
+#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum)		(LmSCRATCH(LinkNum) + 0x01FC)
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_sas.h newtree/drivers/scsi/aic94xx/aic94xx_sas.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_sas.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_sas.h	2006-04-01 05:35:45.907489000 -0500
@@ -0,0 +1,788 @@
+/*
+ * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_sas.h#62 $
+ */
+
+#ifndef _AIC94XX_SAS_H_
+#define _AIC94XX_SAS_H_
+
+#include <scsi/sas/sas_class.h>
+#include <scsi/sas/sas_discover.h>
+
+/* ---------- DDBs ---------- */
+/* DDBs are device descriptor blocks which describe a device in the
+ * domain that this sequencer can maintain low-level connections for
+ * us.  They are be 64 bytes.
+ */
+
+struct asd_ddb_ssp_smp_target_port {
+	u8     conn_type;	  /* byte 0 */
+#define DDB_TP_CONN_TYPE 0x81	  /* Initiator port and addr frame type 0x01 */
+
+	u8     conn_rate;
+	__be16 init_conn_tag;
+	u8     dest_sas_addr[8];  /* bytes 4-11 */
+
+	__le16 send_queue_head;
+	u8     sq_suspended;
+	u8     ddb_type;	  /* DDB_TYPE_TARGET */
+#define DDB_TYPE_UNUSED    0xFF
+#define DDB_TYPE_TARGET    0xFE
+#define DDB_TYPE_INITIATOR 0xFD
+#define DDB_TYPE_PM_PORT   0xFC
+
+	__le16 _r_a;
+	__be16 awt_def;
+
+	u8     compat_features;	  /* byte 20 */
+	u8     pathway_blocked_count;
+	__be16 arb_wait_time;
+	__be32 more_compat_features; /* byte 24 */
+
+	u8     conn_mask;
+	u8     flags;	  /* concurrent conn:2,2 and open:0(1) */
+#define CONCURRENT_CONN_SUPP 0x04
+#define OPEN_REQUIRED        0x01
+
+	u16    _r_b;
+	__le16 exec_queue_tail;
+	__le16 send_queue_tail;
+	__le16 sister_ddb;
+
+	__le16 _r_c;
+
+	u8     max_concurrent_conn;
+	u8     num_concurrent_conn;
+	u8     num_contexts;
+
+	u8     _r_d;
+
+	__le16 active_task_count;
+
+	u8     _r_e[9];
+
+	u8     itnl_reason;	  /* I_T nexus loss reason */
+
+	__le16 _r_f;
+
+	__le16 itnl_timeout;
+#define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */
+
+	__le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+struct asd_ddb_stp_sata_target_port {
+	u8     conn_type;	  /* byte 0 */
+	u8     conn_rate;
+	__be16 init_conn_tag;
+	u8     dest_sas_addr[8];  /* bytes 4-11 */
+
+	__le16 send_queue_head;
+	u8     sq_suspended;
+	u8     ddb_type;	  /* DDB_TYPE_TARGET */
+
+	__le16 _r_a;
+
+	__be16 awt_def;
+	u8     compat_features;	  /* byte 20 */
+	u8     pathway_blocked_count;
+	__be16 arb_wait_time;
+	__be32 more_compat_features; /* byte 24 */
+
+	u8     conn_mask;
+	u8     flags;	  /* concurrent conn:2,2 and open:0(1) */
+#define SATA_MULTIPORT     0x80
+#define SUPPORTS_AFFIL     0x40
+#define STP_AFFIL_POL      0x20
+
+	u8     _r_b;
+	u8     flags2;		  /* STP close policy:0 */
+#define STP_CL_POL_NO_TX    0x00
+#define STP_CL_POL_BTW_CMDS 0x01
+
+	__le16 exec_queue_tail;
+	__le16 send_queue_tail;
+	__le16 sister_ddb;
+	__le16 ata_cmd_scbptr;
+	__le32 sata_tag_alloc_mask;
+	__le16 active_task_count;
+	__le16 _r_c;
+	__le32 sata_sactive;
+	u8     num_sata_tags;
+	u8     sata_status;
+	u8     sata_ending_status;
+	u8     itnl_reason;	  /* I_T nexus loss reason */
+	__le16 ncq_data_scb_ptr;
+	__le16 itnl_timeout;
+	__le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_init_port, describes the device descriptor block
+ * of an initiator port (when the sequencer is operating in target mode).
+ * Bytes [0,11] and [20,27] are from the OPEN address frame.
+ * The sequencer allocates an initiator port DDB entry.
+ */
+struct asd_ddb_init_port {
+	u8     conn_type;	  /* byte 0 */
+	u8     conn_rate;
+	__be16 init_conn_tag;     /* BE */
+	u8     dest_sas_addr[8];
+	__le16 send_queue_head;   /* LE, byte 12 */
+	u8     sq_suspended;
+	u8     ddb_type;	  /* DDB_TYPE_INITIATOR */
+	__le16 _r_a;
+	__be16 awt_def;		  /* BE */
+	u8     compat_features;
+	u8     pathway_blocked_count;
+	__be16 arb_wait_time;	  /* BE */
+	__be32 more_compat_features; /* BE */
+	u8     conn_mask;
+	u8     flags;		  /* == 5 */
+	u16    _r_b;
+	__le16 exec_queue_tail;	  /* execution queue tail */
+	__le16 send_queue_tail;
+	__le16 sister_ddb;
+	__le16 init_resp_timeout; /* initiator response timeout */
+	__le32 _r_c;
+	__le16 active_tasks;	  /* active task count */
+	__le16 init_list;	  /* initiator list link pointer */
+	__le32 _r_d;
+	u8     max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */
+	u8     itnl_reason;	  /* I_T nexus loss reason */
+	__le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */
+	__le16 itnl_to;		  /* from the Protocol Specific Port Ctrl MP */
+	__le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_tag, describes a look-up table to be used
+ * by the sequencers.  SATA II, IDENTIFY DEVICE data, word 76, bit 8:
+ * NCQ support.  This table is used by the sequencers to find the
+ * corresponding SCB, given a SATA II tag value.
+ */
+struct asd_ddb_sata_tag {
+	__le16 scb_pointer[32];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_table, describes a port number to
+ * connection handle look-up table.  SATA targets attached to a port
+ * multiplier require a 4-bit port number value.  There is one DDB
+ * entry of this type for each SATA port multiplier (sister DDB).
+ * Given a SATA PM port number, this table gives us the SATA PM Port
+ * DDB of the SATA port multiplier port (i.e. the SATA target
+ * discovered on the port).
+ */
+struct asd_ddb_sata_pm_table {
+	__le16 ddb_pointer[16];
+	__le16 _r_a[16];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier
+ * port format DDB.
+ */
+struct asd_ddb_sata_pm_port {
+	u8     _r_a[15];
+	u8     ddb_type;
+	u8     _r_b[13];
+	u8     pm_port_flags;
+#define PM_PORT_MASK  0xF0
+#define PM_PORT_SET   0x02
+	u8     _r_c[6];
+	__le16 sister_ddb;
+	__le16 ata_cmd_scbptr;
+	__le32 sata_tag_alloc_mask;
+	__le16 active_task_count;
+	__le16 parent_ddb;
+	__le32 sata_sactive;
+	u8     num_sata_tags;
+	u8     sata_status;
+	u8     sata_ending_status;
+	u8     _r_d[9];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_seq_shared, describes a DDB shared by the
+ * central and link sequencers.  port_map_by_links is indexed phy
+ * number [0,7]; each byte is a bit mask of all the phys that are in
+ * the same port as the indexed phy.
+ */
+struct asd_ddb_seq_shared {
+	__le16 q_free_ddb_head;
+	__le16 q_free_ddb_tail;
+	__le16 q_free_ddb_cnt;
+	__le16 q_used_ddb_head;
+	__le16 q_used_ddb_tail;
+	__le16 shared_mem_lock;
+	__le16 smp_conn_tag;
+	__le16 est_nexus_buf_cnt;
+	__le16 est_nexus_buf_thresh;
+	u32    _r_a;
+	u8     settable_max_contexts;
+	u8     _r_b[23];
+	u8     conn_not_active;
+	u8     phy_is_up;
+	u8     _r_c[8];
+	u8     port_map_by_links[8];
+} __attribute__ ((packed));
+
+/* ---------- SG Element ---------- */
+
+/* This struct sg_el, describes the hardware scatter gather buffer
+ * element.  All entries are little endian.  In an SCB, there are 2 of
+ * this, plus one more, called a link element of this indicating a
+ * sublist if needed.
+ *
+ * A link element has only the bus address set and the flags (DS) bit
+ * valid.  The bus address points to the start of the sublist.
+ *
+ * If a sublist is needed, then that sublist should also include the 2
+ * sg_el embedded in the SCB, in which case next_sg_offset is 32,
+ * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case.
+ */
+struct sg_el {
+	__le64 bus_addr;
+	__le32 size;
+	__le16 _r;
+	u8     next_sg_offs;
+	u8     flags;
+#define ASD_SG_EL_DS_MASK   0x30
+#define ASD_SG_EL_DS_OCM    0x10
+#define ASD_SG_EL_DS_HM     0x00
+#define ASD_SG_EL_LIST_MASK 0xC0
+#define ASD_SG_EL_LIST_EOL  0x40
+#define ASD_SG_EL_LIST_EOS  0x80
+} __attribute__ ((packed));
+
+/* ---------- SCBs ---------- */
+
+/* An SCB (sequencer control block) is comprised of a common header
+ * and a task part, for a total of 128 bytes.  All fields are in LE
+ * order, unless otherwise noted.
+ */
+
+/* This struct scb_header, defines the SCB header format.
+ */
+struct scb_header {
+	__le64 next_scb;
+	__le16 index;		  /* transaction context */
+	u8     opcode;
+} __attribute__ ((packed));
+
+/* SCB opcodes: Execution queue
+ */
+#define INITIATE_SSP_TASK       0x00
+#define INITIATE_LONG_SSP_TASK  0x01
+#define INITIATE_BIDIR_SSP_TASK 0x02
+#define ABORT_TASK              0x03
+#define INITIATE_SSP_TMF        0x04
+#define SSP_TARG_GET_DATA       0x05
+#define SSP_TARG_GET_DATA_GOOD  0x06
+#define SSP_TARG_SEND_RESP      0x07
+#define QUERY_SSP_TASK          0x08
+#define INITIATE_ATA_TASK       0x09
+#define INITIATE_ATAPI_TASK     0x0a
+#define CONTROL_ATA_DEV         0x0b
+#define INITIATE_SMP_TASK       0x0c
+#define SMP_TARG_SEND_RESP      0x0f
+
+/* SCB opcodes: Send Queue
+ */
+#define SSP_TARG_SEND_DATA      0x40
+#define SSP_TARG_SEND_DATA_GOOD 0x41
+
+/* SCB opcodes: Link Queue
+ */
+#define CONTROL_PHY             0x80
+#define SEND_PRIMITIVE          0x81
+#define INITIATE_LINK_ADM_TASK  0x82
+
+/* SCB opcodes: other
+ */
+#define EMPTY_SCB               0xc0
+#define INITIATE_SEQ_ADM_TASK   0xc1
+#define EST_ICL_TARG_WINDOW     0xc2
+#define COPY_MEM                0xc3
+#define CLEAR_NEXUS             0xc4
+#define DELIVER_FREE_I_PORT_DDB 0xc5
+#define INITIATE_DDB_ADM_TASK   0xc6
+#define ESTABLISH_NEXUS_ESCB    0xd0
+
+#define LUN_SIZE                8
+
+/* See SAS spec, task IU
+ */
+struct ssp_task_iu {
+	u8     lun[LUN_SIZE];	  /* BE */
+	u16    _r_a;
+	u8     tmf;
+	u8     _r_b;
+	__be16 tag;		  /* BE */
+	u8     _r_c[14];
+} __attribute__ ((packed));
+
+/* See SAS spec, command IU
+ */
+struct ssp_command_iu {
+	u8     lun[LUN_SIZE];
+	u8     _r_a;
+	u8     efb_prio_attr;	  /* enable first burst, task prio & attr */
+#define EFB_MASK        0x80
+#define TASK_PRIO_MASK	0x78
+#define TASK_ATTR_MASK  0x07
+
+	u8    _r_b;
+	u8     add_cdb_len;	  /* in dwords, since bit 0,1 are reserved */
+	union {
+		u8     cdb[16];
+		struct {
+			__le64 long_cdb_addr;	  /* bus address, LE */
+			__le32 long_cdb_size;	  /* LE */
+			u8     _r_c[3];
+			u8     eol_ds;		  /* eol:6,6, ds:5,4 */
+		} long_cdb;	  /* sequencer extension */
+	};
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+	__be32 requested_offset;  /* BE */
+	__be32 write_data_len;	  /* BE */
+	__be32 _r_a;
+} __attribute__ ((packed));
+
+/* ---------- SCB tasks ---------- */
+
+/* This is both ssp_task and long_ssp_task
+ */
+struct initiate_ssp_task {
+	u8     proto_conn_rate;	  /* proto:6,4, conn_rate:3,0 */
+	__le32 total_xfer_len;
+	struct ssp_frame_hdr  ssp_frame;
+	struct ssp_command_iu ssp_cmd;
+	__le16 sister_scb;	  /* 0xFFFF */
+	__le16 conn_handle;	  /* index to DDB for the intended target */
+	u8     data_dir;	  /* :1,0 */
+#define DATA_DIR_NONE   0x00
+#define DATA_DIR_IN     0x01
+#define DATA_DIR_OUT    0x02
+#define DATA_DIR_BYRECIPIENT 0x03
+
+	u8     _r_a;
+	u8     retry_count;
+	u8     _r_b[5];
+	struct sg_el sg_element[3]; /* 2 real and 1 link */
+} __attribute__ ((packed));
+
+/* This defines both ata_task and atapi_task.
+ * ata: C bit of FIS should be 1,
+ * atapi: C bit of FIS should be 1, and command register should be 0xA0,
+ * to indicate a packet command.
+ */
+struct initiate_ata_task {
+	u8     proto_conn_rate;
+	__le32 total_xfer_len;
+	struct host_to_dev_fis fis;
+	__le32 data_offs;
+	u8     atapi_packet[16];
+	u8     _r_a[12];
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     ata_flags;	  /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */
+#define CSMI_TASK           0x40
+#define DATA_XFER_MODE_DMA  0x10
+#define ATA_Q_TYPE_MASK     0x08
+#define	ATA_Q_TYPE_UNTAGGED 0x00
+#define ATA_Q_TYPE_NCQ      0x08
+
+	u8     _r_b;
+	u8     retry_count;
+	u8     _r_c;
+	u8     flags;
+#define STP_AFFIL_POLICY   0x20
+#define SET_AFFIL_POLICY   0x10
+#define RET_PARTIAL_SGLIST 0x02
+
+	u8     _r_d[3];
+	struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+struct initiate_smp_task {
+	u8     proto_conn_rate;
+	u8     _r_a[40];
+	struct sg_el smp_req;
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     _r_c[8];
+	struct sg_el smp_resp;
+	u8     _r_d[32];
+} __attribute__ ((packed));
+
+struct control_phy {
+	u8     phy_id;
+	u8     sub_func;
+#define DISABLE_PHY            0x00
+#define ENABLE_PHY             0x01
+#define RELEASE_SPINUP_HOLD    0x02
+#define ENABLE_PHY_NO_SAS_OOB  0x03
+#define ENABLE_PHY_NO_SATA_OOB 0x04
+#define PHY_NO_OP              0x05
+#define EXECUTE_HARD_RESET     0x81
+
+	u8     func_mask;
+	u8     speed_mask;
+	u8     hot_plug_delay;
+	u8     port_type;
+	u8     flags;
+#define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01
+#define DISABLE_PHY_IF_OOB_FAILS       0x02
+
+	__le32 timeout_override;
+	u8     link_reset_retries;
+	u8     _r_a[47];
+	__le16 conn_handle;
+	u8     _r_b[56];
+} __attribute__ ((packed));
+
+struct control_ata_dev {
+	u8     proto_conn_rate;
+	__le32 _r_a;
+	struct host_to_dev_fis fis;
+	u8     _r_b[32];
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     ata_flags;	  /* 0 */
+	u8     _r_c[55];
+} __attribute__ ((packed));
+
+struct empty_scb {
+	u8     num_valid;
+	__le32 _r_a;
+#define ASD_EDBS_PER_SCB 7
+/* header+data+CRC+DMA suffix data */
+#define ASD_EDB_SIZE (24+1024+4+16)
+	struct sg_el eb[ASD_EDBS_PER_SCB];
+#define ELEMENT_NOT_VALID  0xC0
+} __attribute__ ((packed));
+
+struct initiate_link_adm {
+	u8     phy_id;
+	u8     sub_func;
+#define GET_LINK_ERROR_COUNT      0x00
+#define RESET_LINK_ERROR_COUNT    0x01
+#define ENABLE_NOTIFY_SPINUP_INTS 0x02
+
+	u8     _r_a[57];
+	__le16 conn_handle;
+	u8     _r_b[56];
+} __attribute__ ((packed));
+
+struct copy_memory {
+	u8     _r_a;
+	__le16 xfer_len;
+	__le16 _r_b;
+	__le64 src_busaddr;
+	u8     src_ds;		  /* See definition of sg_el */
+	u8     _r_c[45];
+	__le16 conn_handle;
+	__le64 _r_d;
+	__le64 dest_busaddr;
+	u8     dest_ds;		  /* See definition of sg_el */
+	u8     _r_e[39];
+} __attribute__ ((packed));
+
+struct abort_task {
+	u8     proto_conn_rate;
+	__le32 _r_a;
+	struct ssp_frame_hdr ssp_frame;
+	struct ssp_task_iu ssp_task;
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     flags;	  /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
+#define SUSPEND_DATA_TRANS 0x04
+
+	u8     _r_b;
+	u8     retry_count;
+	u8     _r_c[5];
+	__le16 index;  /* Transaction context of task to be queried */
+	__le16 itnl_to;
+	u8     _r_d[44];
+} __attribute__ ((packed));
+
+struct clear_nexus {
+	u8     nexus;
+#define NEXUS_ADAPTER  0x00
+#define NEXUS_PORT     0x01
+#define NEXUS_I_T      0x02
+#define NEXUS_I_T_L    0x03
+#define NEXUS_TAG      0x04
+#define NEXUS_TRANS_CX 0x05
+#define NEXUS_SATA_TAG 0x06
+#define NEXUS_T_L      0x07
+#define NEXUS_L        0x08
+#define NEXUS_T_TAG    0x09
+
+	__le32 _r_a;
+	u8     flags;
+#define SUSPEND_TX     0x80
+#define RESUME_TX      0x40
+#define SEND_Q         0x04
+#define EXEC_Q         0x02
+#define NOTINQ         0x01
+
+	u8     _r_b[3];
+	u8     conn_mask;
+	u8     _r_c[19];
+	struct ssp_task_iu ssp_task; /* LUN and TAG */
+	__le16 _r_d;
+	__le16 conn_handle;
+	__le64 _r_e;
+	__le16 index;  /* Transaction context of task to be cleared */
+	__le16 context;		  /* Clear nexus context */
+	u8     _r_f[44];
+} __attribute__ ((packed));
+
+struct initiate_ssp_tmf {
+	u8     proto_conn_rate;
+	__le32 _r_a;
+	struct ssp_frame_hdr ssp_frame;
+	struct ssp_task_iu ssp_task;
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     flags;	  /* itnl override and suspend data tx */
+#define OVERRIDE_ITNL_TIMER  8
+
+	u8     _r_b;
+	u8     retry_count;
+	u8     _r_c[5];
+	__le16 index;  /* Transaction context of task to be queried */
+	__le16 itnl_to;
+	u8     _r_d[44];
+} __attribute__ ((packed));
+
+/* Transmits an arbitrary primitive on the link.
+ * Used for NOTIFY and BROADCAST.
+ */
+struct send_prim {
+	u8     phy_id;
+	u8     wait_transmit; 	  /* :0,0 */
+	u8     xmit_flags;
+#define XMTPSIZE_MASK      0xF0
+#define XMTPSIZE_SINGLE    0x10
+#define XMTPSIZE_REPEATED  0x20
+#define XMTPSIZE_CONT      0x20
+#define XMTPSIZE_TRIPLE    0x30
+#define XMTPSIZE_REDUNDANT 0x60
+#define XMTPSIZE_INF       0
+
+#define XMTCONTEN          0x04
+#define XMTPFRM            0x02	  /* Transmit at the next frame boundary */
+#define XMTPIMM            0x01	  /* Transmit immediately */
+
+	__le16 _r_a;
+	u8     prim[4];		  /* K, D0, D1, D2 */
+	u8     _r_b[50];
+	__le16 conn_handle;
+	u8     _r_c[56];
+} __attribute__ ((packed));
+
+/* This describes both SSP Target Get Data and SSP Target Get Data And
+ * Send Good Response SCBs.  Used when the sequencer is operating in
+ * target mode...
+ */
+struct ssp_targ_get_data {
+	u8     proto_conn_rate;
+	__le32 total_xfer_len;
+	struct ssp_frame_hdr ssp_frame;
+	struct xfer_rdy_iu  xfer_rdy;
+	u8     lun[LUN_SIZE];
+	__le64 _r_a;
+	__le16 sister_scb;
+	__le16 conn_handle;
+	u8     data_dir;	  /* 01b */
+	u8     _r_b;
+	u8     retry_count;
+	u8     _r_c[5];
+	struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+/* ---------- The actual SCB struct ---------- */
+
+struct scb {
+	struct scb_header header;
+	union {
+		struct initiate_ssp_task ssp_task;
+		struct initiate_ata_task ata_task;
+		struct initiate_smp_task smp_task;
+		struct control_phy       control_phy;
+		struct control_ata_dev   control_ata_dev;
+		struct empty_scb         escb;
+		struct initiate_link_adm link_adm;
+		struct copy_memory       cp_mem;
+		struct abort_task        abort_task;
+		struct clear_nexus       clear_nexus;
+		struct initiate_ssp_tmf  ssp_tmf;
+	};
+} __attribute__ ((packed));
+
+/* ---------- Done List ---------- */
+/* The done list entry opcode field is defined below.
+ * The mnemonic encoding and meaning is as follows:
+ * TC - Task Complete, status was received and acknowledged
+ * TF - Task Failed, indicates an error prior to receiving acknowledgment
+ *   for the command:
+ *   - no conn,
+ *   - NACK or R_ERR received in response to this command,
+ *   - credit blocked or not available, or in the case of SMP request,
+ *   - no SMP response was received.
+ *   In these four cases it is known that the target didn't receive the
+ *   command.
+ * TI - Task Interrupted, error after the command was acknowledged.  It is
+ *   known that the command was received by the target.
+ * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK
+ *   (R_ERR) was received due to loss of signal, broken connection, loss of
+ *   dword sync or other reason.  The application client should send the
+ *   appropriate task query.
+ * TA - Task Aborted, see TF.
+ * _RESP - The completion includes an empty buffer containing status.
+ * TO - Timeout.
+ */
+#define TC_NO_ERROR             0x00
+#define TC_UNDERRUN             0x01
+#define TC_OVERRUN              0x02
+#define TF_OPEN_TO              0x03
+#define TF_OPEN_REJECT          0x04
+#define TI_BREAK                0x05
+#define TI_PROTO_ERR            0x06
+#define TC_SSP_RESP             0x07
+#define TI_PHY_DOWN             0x08
+#define TF_PHY_DOWN             0x09
+#define TC_LINK_ADM_RESP        0x0a
+#define TC_CSMI                 0x0b
+#define TC_ATA_RESP             0x0c
+#define TU_PHY_DOWN             0x0d
+#define TU_BREAK                0x0e
+#define TI_SATA_TO              0x0f
+#define TI_NAK                  0x10
+#define TC_CONTROL_PHY          0x11
+#define TF_BREAK                0x12
+#define TC_RESUME               0x13
+#define TI_ACK_NAK_TO           0x14
+#define TF_SMPRSP_TO            0x15
+#define TF_SMP_XMIT_RCV_ERR     0x16
+#define TC_PARTIAL_SG_LIST      0x17
+#define TU_ACK_NAK_TO           0x18
+#define TU_SATA_TO              0x19
+#define TF_NAK_RECV             0x1a
+#define TA_I_T_NEXUS_LOSS       0x1b
+#define TC_ATA_R_ERR_RECV       0x1c
+#define TF_TMF_NO_CTX           0x1d
+#define TA_ON_REQ               0x1e
+#define TF_TMF_NO_TAG           0x1f
+#define TF_TMF_TAG_FREE         0x20
+#define TF_TMF_TASK_DONE        0x21
+#define TF_TMF_NO_CONN_HANDLE   0x22
+#define TC_TASK_CLEARED         0x23
+#define TI_SYNCS_RECV           0x24
+#define TU_SYNCS_RECV           0x25
+#define TF_IRTT_TO              0x26
+#define TF_NO_SMP_CONN          0x27
+#define TF_IU_SHORT             0x28
+#define TF_DATA_OFFS_ERR        0x29
+#define TF_INV_CONN_HANDLE      0x2a
+#define TF_REQUESTED_N_PENDING  0x2b
+
+/* 0xc1 - 0xc7: empty buffer received,
+   0xd1 - 0xd7: establish nexus empty buffer received
+*/
+/* This is the ESCB mask */
+#define ESCB_RECVD              0xC0
+
+
+/* This struct done_list_struct defines the done list entry.
+ * All fields are LE.
+ */
+struct done_list_struct {
+	__le16 index;		  /* aka transaction context */
+	u8     opcode;
+	u8     status_block[4];
+	u8     toggle;		  /* bit 0 */
+#define DL_TOGGLE_MASK     0x01
+} __attribute__ ((packed));
+
+/* ---------- PHYS ---------- */
+
+struct asd_phy {
+	struct sas_phy        sas_phy;
+	struct asd_phy_desc   *phy_desc; /* hw profile */
+
+	struct sas_identify_frame *identify_frame;
+	struct asd_dma_tok  *id_frm_tok;
+
+	u8         frame_rcvd[ASD_EDB_SIZE];
+};
+
+
+#define ASD_SCB_SIZE sizeof(struct scb)
+#define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port)
+
+/* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent.
+ * Default: 0x10 (it's a mask)
+ */
+#define ASD_NOTIFY_ENABLE_SPINUP  0x10
+
+/* If enabled, set this to the interval between transmission
+ * of NOTIFY (ENABLE SPINUP). In units of 200 us.
+ */
+#define ASD_NOTIFY_TIMEOUT        2500
+
+/* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP).
+ * If 0, transmit immediately. In milliseconds.
+ */
+#define ASD_NOTIFY_DOWN_COUNT     0
+
+/* Device present timer timeout constant, 10 ms. */
+#define ASD_DEV_PRESENT_TIMEOUT   0x2710
+
+#define ASD_SATA_INTERLOCK_TIMEOUT 0
+
+/* How long to wait before shutting down an STP connection, unless
+ * an STP target sent frame(s). 50 usec.
+ * IGNORED by the sequencer (i.e. value 0 always).
+ */
+#define ASD_STP_SHUTDOWN_TIMEOUT  0x0
+
+/* ATA soft reset timer timeout. 5 usec. */
+#define ASD_SRST_ASSERT_TIMEOUT   0x05
+
+/* 31 sec */
+#define ASD_RCV_FIS_TIMEOUT       0x01D905C0
+
+#define ASD_ONE_MILLISEC_TIMEOUT  0x03e8
+
+/* COMINIT timer */
+#define ASD_TEN_MILLISEC_TIMEOUT  0x2710
+#define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT
+
+/* 1 sec */
+#define ASD_SMP_RCV_TIMEOUT       0x000F4240
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_scb.c newtree/drivers/scsi/aic94xx/aic94xx_scb.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_scb.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_scb.c	2006-04-01 05:35:45.907489000 -0500
@@ -0,0 +1,726 @@
+/*
+ * Aic94xx SAS/SATA driver SCB management.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_scb.c#71 $
+ */
+
+#include <linux/pci.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+#include "aic94xx_dump.h"
+
+/* ---------- EMPTY SCB ---------- */
+
+#define DL_PHY_MASK      7
+#define BYTES_DMAED      0
+#define PRIMITIVE_RECVD  0x08
+#define PHY_EVENT        0x10
+#define LINK_RESET_ERROR 0x18
+#define TIMER_EVENT      0x20
+#define REQ_TASK_ABORT   0xF0
+#define REQ_DEVICE_RESET 0xF1
+#define SIGNAL_NCQ_ERROR 0xF2
+#define CLEAR_NCQ_ERROR  0xF3
+
+#define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE   \
+			   | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+			   | CURRENT_OOB_ERROR)
+
+static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
+{
+	switch (oob_mode & 7) {
+	case PHY_SPEED_60:
+		phy->sas_phy.linkrate = PHY_LINKRATE_6;
+		break;
+	case PHY_SPEED_30:
+		phy->sas_phy.linkrate = PHY_LINKRATE_3;
+		break;
+	case PHY_SPEED_15:
+		phy->sas_phy.linkrate = PHY_LINKRATE_1_5;
+		break;
+	}
+	if (oob_mode & SAS_MODE)
+		phy->sas_phy.oob_mode = SAS_OOB_MODE;
+	else if (oob_mode & SATA_MODE)
+		phy->sas_phy.oob_mode = SATA_OOB_MODE;
+}
+
+static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
+					 struct done_list_struct *dl)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+	int phy_id = dl->status_block[0] & DL_PHY_MASK;
+	struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+	u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS;
+	u8 oob_mode   = dl->status_block[2];
+
+	switch (oob_status) {
+	case CURRENT_LOSS_OF_SIGNAL:
+		/* directly attached device was removed */
+		ASD_DPRINTK("phy%d: device unplugged\n", phy_id);
+		asd_turn_led(asd_ha, phy_id, 0);
+		sas_phy_disconnected(&phy->sas_phy);
+		sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL);
+		break;
+	case CURRENT_OOB_DONE:
+		/* hot plugged device */
+		asd_turn_led(asd_ha, phy_id, 1);
+		get_lrate_mode(phy, oob_mode);
+		ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n",
+			    phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto);
+		sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
+		break;
+	case CURRENT_SPINUP_HOLD:
+		/* hot plug SATA, no COMWAKE sent */
+		asd_turn_led(asd_ha, phy_id, 1);
+		sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD);
+		break;
+	case CURRENT_GTO_TIMEOUT:
+	case CURRENT_OOB_ERROR:
+		ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id,
+			    dl->status_block[1]);
+		asd_turn_led(asd_ha, phy_id, 0);
+		sas_phy_disconnected(&phy->sas_phy);
+		sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR);
+		break;
+	}
+}
+
+/* If phys are enabled sparsely, this will do the right thing. */
+static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
+			       struct asd_phy *phy)
+{
+	u8 enabled_mask = asd_ha->hw_prof.enabled_phys;
+	int i, k = 0;
+
+	for_each_phy(enabled_mask, enabled_mask, i) {
+		if (&asd_ha->phys[i] == phy)
+			return k;
+		k++;
+	}
+}
+
+/**
+ * asd_get_attached_sas_addr -- extract/generate attached SAS address
+ * phy: pointer to asd_phy
+ * sas_addr: pointer to buffer where the SAS address is to be written
+ *
+ * This function extracts the SAS address from an IDENTIFY frame
+ * received.  If OOB is SATA, then a SAS address is generated from the
+ * HA tables.
+ *
+ * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
+ * buffer.
+ */
+static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
+{
+	if (phy->sas_phy.frame_rcvd[0] == 0x34
+	    && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
+		struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+		/* FIS device-to-host */
+		u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr);
+
+		addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy);
+		*(__be64 *)sas_addr = cpu_to_be64(addr);
+	} else {
+		struct sas_identify_frame *idframe =
+			(void *) phy->sas_phy.frame_rcvd;
+		memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
+	}
+}
+
+static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
+					   struct done_list_struct *dl,
+					   int edb_id, int phy_id)
+{
+	unsigned long flags;
+	int edb_el = edb_id + ascb->edb_index;
+	struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el];
+	struct asd_phy *phy = &ascb->ha->phys[phy_id];
+	struct sas_ha_struct *sas_ha = phy->sas_phy.ha;
+	u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2];
+
+	size = min(size, (u16) sizeof(phy->frame_rcvd));
+
+	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+	memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size);
+	phy->sas_phy.frame_rcvd_size = size;
+	asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
+	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+	asd_dump_frame_rcvd(phy, dl);
+	sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
+}
+
+static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
+					      struct done_list_struct *dl,
+					      int phy_id)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+	struct sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+	u8 lr_error = dl->status_block[1];
+	u8 retries_left = dl->status_block[2];
+
+	switch (lr_error) {
+	case 0:
+		ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id);
+		break;
+	case 1:
+		ASD_DPRINTK("phy%d: Loss of signal\n", phy_id);
+		break;
+	case 2:
+		ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id);
+		break;
+	case 3:
+		ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id);
+		break;
+	default:
+		ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n",
+			    phy_id, lr_error);
+		break;
+	}
+
+	asd_turn_led(asd_ha, phy_id, 0);
+	sas_phy_disconnected(sas_phy);
+	sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+
+	if (retries_left == 0) {
+		int num = 1;
+		struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
+							  GFP_ATOMIC);
+		if (!cp) {
+			asd_printk("%s: out of memory\n", __FUNCTION__);
+			goto out;
+		}
+		ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
+			    phy_id);
+		asd_build_control_phy(cp, phy_id, ENABLE_PHY);
+		if (asd_post_ascb_list(ascb->ha, cp, 1) != 0)
+			asd_ascb_free(cp);
+	}
+out:
+	;
+}
+
+static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
+					      struct done_list_struct *dl,
+					      int phy_id)
+{
+	unsigned long flags;
+	struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
+	struct sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+	u8  reg  = dl->status_block[1];
+	u32 cont = dl->status_block[2] << ((reg & 3)*8);
+
+	reg &= ~3;
+	switch (reg) {
+	case LmPRMSTAT0BYTE0:
+		switch (cont) {
+		case LmBROADCH:
+		case LmBROADRVCH0:
+		case LmBROADRVCH1:
+		case LmBROADSES:
+			ASD_DPRINTK("phy%d: BROADCAST change received:%d\n",
+				    phy_id, cont);
+			spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+			sas_phy->sas_prim = ffs(cont);
+			spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+			sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD);
+			break;
+
+		case LmUNKNOWNP:
+			ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id);
+			break;
+
+		default:
+			ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+				    phy_id, reg, cont);
+			break;
+		}
+		break;
+	case LmPRMSTAT1BYTE0:
+		switch (cont) {
+		case LmHARDRST:
+			ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n",
+				    phy_id);
+			/* The sequencer disables all phys on that port.
+			 * We have to re-enable the phys ourselves. */
+			sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
+			break;
+
+		default:
+			ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+				    phy_id, reg, cont);
+			break;
+		}
+		break;
+	default:
+		ASD_DPRINTK("unknown primitive register:0x%x\n",
+			    dl->status_block[1]);
+		break;
+	}
+}
+
+/**
+ * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB
+ * @ascb: pointer to Empty SCB
+ * @edb_id: index [0,6] to the empty data buffer which is to be invalidated
+ *
+ * After an EDB has been invalidated, if all EDBs in this ESCB have been
+ * invalidated, the ESCB is posted back to the sequencer.
+ * Context is tasklet/IRQ.
+ */
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
+{
+	struct asd_seq_data *seq = &ascb->ha->seq;
+	struct empty_scb *escb = &ascb->scb->escb;
+	struct sg_el     *eb   = &escb->eb[edb_id];
+	struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id];
+
+	memset(edb->vaddr, 0, ASD_EDB_SIZE);
+	eb->flags |= ELEMENT_NOT_VALID;
+	escb->num_valid--;
+
+	if (escb->num_valid == 0) {
+		int i;
+		/* ASD_DPRINTK("reposting escb: vaddr: 0x%p, "
+			    "dma_handle: 0x%08llx, next: 0x%08llx, "
+			    "index:%d, opcode:0x%02x\n",
+			    ascb->dma_scb.vaddr,
+			    (u64)ascb->dma_scb.dma_handle,
+			    le64_to_cpu(ascb->scb->header.next_scb),
+			    le16_to_cpu(ascb->scb->header.index),
+			    ascb->scb->header.opcode);
+		*/
+		escb->num_valid = ASD_EDBS_PER_SCB;
+		for (i = 0; i < ASD_EDBS_PER_SCB; i++)
+			escb->eb[i].flags = 0;
+		if (!list_empty(&ascb->list))
+			list_del_init(&ascb->list);
+		i = asd_post_escb_list(ascb->ha, ascb, 1);
+		if (i)
+			asd_printk("couldn't post escb, err:%d\n", i);
+	}
+}
+
+static void escb_tasklet_complete(struct asd_ascb *ascb,
+				  struct done_list_struct *dl)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+	int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */
+	u8  sb_opcode = dl->status_block[0];
+	int phy_id = sb_opcode & DL_PHY_MASK;
+	struct sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+
+	if (edb > 6 || edb < 0) {
+		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+			    edb, dl->opcode);
+		ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+			    sb_opcode, phy_id);
+		ASD_DPRINTK("escb: vaddr: 0x%p, "
+			    "dma_handle: 0x%08llx, next: 0x%08llx, "
+			    "index:%d, opcode:0x%02x\n",
+			    ascb->dma_scb.vaddr,
+			    (u64)ascb->dma_scb.dma_handle,
+			    le64_to_cpu(ascb->scb->header.next_scb),
+			    le16_to_cpu(ascb->scb->header.index),
+			    ascb->scb->header.opcode);
+	}
+
+	sb_opcode &= ~DL_PHY_MASK;
+
+	switch (sb_opcode) {
+	case BYTES_DMAED:
+		ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+		asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
+		break;
+	case PRIMITIVE_RECVD:
+		ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+			    phy_id);
+		asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
+		break;
+	case PHY_EVENT:
+		ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+		asd_phy_event_tasklet(ascb, dl);
+		break;
+	case LINK_RESET_ERROR:
+		ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+			    phy_id);
+		asd_link_reset_err_tasklet(ascb, dl, phy_id);
+		break;
+	case TIMER_EVENT:
+		ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
+			    __FUNCTION__, phy_id);
+		asd_turn_led(asd_ha, phy_id, 0);
+		/* the device is gone */
+		sas_phy_disconnected(sas_phy);
+		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
+		break;
+	case REQ_TASK_ABORT:
+		ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
+			    phy_id);
+		break;
+	case REQ_DEVICE_RESET:
+		ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
+			    phy_id);
+		break;
+	case SIGNAL_NCQ_ERROR:
+		ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
+			    phy_id);
+		break;
+	case CLEAR_NCQ_ERROR:
+		ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
+			    phy_id);
+		break;
+	default:
+		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
+			    phy_id, sb_opcode);
+		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+			    edb, dl->opcode);
+		ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+			    sb_opcode, phy_id);
+		ASD_DPRINTK("escb: vaddr: 0x%p, "
+			    "dma_handle: 0x%08llx, next: 0x%08llx, "
+			    "index:%d, opcode:0x%02x\n",
+			    ascb->dma_scb.vaddr,
+			    (u64)ascb->dma_scb.dma_handle,
+			    le64_to_cpu(ascb->scb->header.next_scb),
+			    le16_to_cpu(ascb->scb->header.index),
+			    ascb->scb->header.opcode);
+
+		break;
+	}
+
+	asd_invalidate_edb(ascb, edb);
+}
+
+int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
+{
+	struct asd_seq_data *seq = &asd_ha->seq;
+	int i;
+
+	for (i = 0; i < seq->num_escbs; i++)
+		seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
+
+	ASD_DPRINTK("posting %d escbs\n", i);
+	return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+#define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE   \
+			    | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+			    | CURRENT_OOB_ERROR)
+
+/**
+ * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
+ * @ascb: pointer to an ascb
+ * @dl: pointer to the done list entry
+ *
+ * This function completes a CONTROL PHY scb and frees the ascb.
+ * A note on LEDs:
+ *  - an LED blinks if there is IO though it,
+ *  - if a device is connected to the LED, it is lit,
+ *  - if no device is connected to the LED, is is dimmed (off).
+ */
+static void control_phy_tasklet_complete(struct asd_ascb *ascb,
+					 struct done_list_struct *dl)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct scb *scb = ascb->scb;
+	struct control_phy *control_phy = &scb->control_phy;
+	u8 phy_id = control_phy->phy_id;
+	struct asd_phy *phy = &ascb->ha->phys[phy_id];
+
+	u8 status     = dl->status_block[0];
+	u8 oob_status = dl->status_block[1];
+	u8 oob_mode   = dl->status_block[2];
+	/* u8 oob_signals= dl->status_block[3]; */
+
+	if (status != 0) {
+		ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
+			    __FUNCTION__, phy_id, status);
+		goto out;
+	}
+
+	switch (control_phy->sub_func) {
+	case DISABLE_PHY:
+		asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
+		asd_turn_led(asd_ha, phy_id, 0);
+		asd_control_led(asd_ha, phy_id, 0);
+		ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+		break;
+
+	case ENABLE_PHY:
+		asd_control_led(asd_ha, phy_id, 1);
+		if (oob_status & CURRENT_OOB_DONE) {
+			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+			get_lrate_mode(phy, oob_mode);
+			asd_turn_led(asd_ha, phy_id, 1);
+			ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
+				    __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+				    phy->sas_phy.iproto);
+		} else if (oob_status & CURRENT_SPINUP_HOLD) {
+			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+			asd_turn_led(asd_ha, phy_id, 1);
+			ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+				    phy_id);
+		} else if (oob_status & CURRENT_ERR_MASK) {
+			asd_turn_led(asd_ha, phy_id, 0);
+			ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
+				    __FUNCTION__, phy_id, oob_status);
+		} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
+					 | CURRENT_DEVICE_PRESENT))  {
+			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+			asd_turn_led(asd_ha, phy_id, 1);
+			ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
+				    __FUNCTION__, phy_id);
+		} else {
+			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+			asd_turn_led(asd_ha, phy_id, 0);
+			ASD_DPRINTK("%s: phy%d: no device present: "
+				    "oob_status:0x%x\n",
+				    __FUNCTION__, phy_id, oob_status);
+		}
+		break;
+	case RELEASE_SPINUP_HOLD:
+	case PHY_NO_OP:
+	case EXECUTE_HARD_RESET:
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+			    phy_id, control_phy->sub_func);
+		/* XXX finish */
+		break;
+	default:
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+			    phy_id, control_phy->sub_func);
+		break;
+	}
+out:
+	asd_ascb_free(ascb);
+}
+
+static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
+{
+	/* disable all speeds, then enable defaults */
+	*speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS
+		| SATA_SPEED_30_DIS | SATA_SPEED_15_DIS;
+
+	switch (pd->max_sas_lrate) {
+	case PHY_LINKRATE_6:
+		*speed_mask &= ~SAS_SPEED_60_DIS;
+	default:
+	case PHY_LINKRATE_3:
+		*speed_mask &= ~SAS_SPEED_30_DIS;
+	case PHY_LINKRATE_1_5:
+		*speed_mask &= ~SAS_SPEED_15_DIS;
+	}
+
+	switch (pd->min_sas_lrate) {
+	case PHY_LINKRATE_6:
+		*speed_mask |= SAS_SPEED_30_DIS;
+	case PHY_LINKRATE_3:
+		*speed_mask |= SAS_SPEED_15_DIS;
+	default:
+	case PHY_LINKRATE_1_5:
+		/* nothing to do */
+		;
+	}
+
+	switch (pd->max_sata_lrate) {
+	case PHY_LINKRATE_3:
+		*speed_mask &= ~SATA_SPEED_30_DIS;
+	default:
+	case PHY_LINKRATE_1_5:
+		*speed_mask &= ~SATA_SPEED_15_DIS;
+	}
+
+	switch (pd->min_sata_lrate) {
+	case PHY_LINKRATE_3:
+		*speed_mask |= SATA_SPEED_15_DIS;
+	default:
+	case PHY_LINKRATE_1_5:
+		/* nothing to do */
+		;
+	}
+}
+
+/**
+ * asd_build_control_phy -- build a CONTROL PHY SCB
+ * @ascb: pointer to an ascb
+ * @phy_id: phy id to control, integer
+ * @subfunc: subfunction, what to actually to do the phy
+ *
+ * This function builds a CONTROL PHY scb.  No allocation of any kind
+ * is performed. @ascb is allocated with the list function.
+ * The caller can override the ascb->tasklet_complete to point
+ * to its own callback function.  It must call asd_ascb_free()
+ * at its tasklet complete function.
+ * See the default implementation.
+ */
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
+{
+	struct asd_phy *phy = &ascb->ha->phys[phy_id];
+	struct scb *scb = ascb->scb;
+	struct control_phy *control_phy = &scb->control_phy;
+
+	scb->header.opcode = CONTROL_PHY;
+	control_phy->phy_id = (u8) phy_id;
+	control_phy->sub_func = subfunc;
+
+	switch (subfunc) {
+	case EXECUTE_HARD_RESET:  /* 0x81 */
+	case ENABLE_PHY:          /* 0x01 */
+		/* decide hot plug delay */
+		control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT;
+
+		/* decide speed mask */
+		set_speed_mask(&control_phy->speed_mask, phy->phy_desc);
+
+		/* initiator port settings are in the hi nibble */
+		if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
+			control_phy->port_type = SAS_PROTO_ALL << 4;
+		else if (phy->sas_phy.role == PHY_ROLE_TARGET)
+			control_phy->port_type = SAS_PROTO_ALL;
+		else
+			control_phy->port_type =
+				(SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+
+		/* link reset retries, this should be nominal */
+		control_phy->link_reset_retries = 10;
+
+	case RELEASE_SPINUP_HOLD: /* 0x02 */
+		/* decide the func_mask */
+		control_phy->func_mask = FUNCTION_MASK_DEFAULT;
+		if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD)
+			control_phy->func_mask &= ~SPINUP_HOLD_DIS;
+		else
+			control_phy->func_mask |= SPINUP_HOLD_DIS;
+	}
+
+	control_phy->conn_handle = cpu_to_le16(0xFFFF);
+
+	ascb->tasklet_complete = control_phy_tasklet_complete;
+}
+
+/* ---------- INITIATE LINK ADM TASK ---------- */
+
+static void link_adm_tasklet_complete(struct asd_ascb *ascb,
+				      struct done_list_struct *dl)
+{
+	u8 opcode = dl->opcode;
+	struct initiate_link_adm *link_adm = &ascb->scb->link_adm;
+	u8 phy_id = link_adm->phy_id;
+
+	if (opcode != TC_NO_ERROR) {
+		asd_printk("phy%d: link adm task 0x%x completed with error "
+			   "0x%x\n", phy_id, link_adm->sub_func, opcode);
+	}
+	ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n",
+		    phy_id, link_adm->sub_func, opcode);
+
+	asd_ascb_free(ascb);
+}
+
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+				      u8 subfunc)
+{
+	struct scb *scb = ascb->scb;
+	struct initiate_link_adm *link_adm = &scb->link_adm;
+
+	scb->header.opcode = INITIATE_LINK_ADM_TASK;
+
+	link_adm->phy_id = phy_id;
+	link_adm->sub_func = subfunc;
+	link_adm->conn_handle = cpu_to_le16(0xFFFF);
+
+	ascb->tasklet_complete = link_adm_tasklet_complete;
+}
+
+/* ---------- SCB timer ---------- */
+
+/**
+ * asd_ascb_timedout -- called when a pending SCB's timer has expired
+ * @data: unsigned long, a pointer to the ascb in question
+ *
+ * This is the default timeout function which does the most necessary.
+ * Upper layers can implement their own timeout function, say to free
+ * resources they have with this SCB, and then call this one at the
+ * end of their timeout function.  To do this, one should initialize
+ * the ascb->timer.{function, data, expires} prior to calling the post
+ * funcion.  The timer is started by the post function.
+ */
+void asd_ascb_timedout(unsigned long data)
+{
+	struct asd_ascb *ascb = (void *) data;
+	struct asd_seq_data *seq = &ascb->ha->seq;
+	unsigned long flags;
+
+	ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode);
+
+	spin_lock_irqsave(&seq->pend_q_lock, flags);
+	seq->pending--;
+	list_del_init(&ascb->list);
+	spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+
+	asd_ascb_free(ascb);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+/* Given the spec value, return a driver value. */
+static const int phy_func_table[] = {
+	[PHY_FUNC_NOP]        = PHY_NO_OP,
+	[PHY_FUNC_LINK_RESET] = ENABLE_PHY,
+	[PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET,
+	[PHY_FUNC_DISABLE]    = DISABLE_PHY,
+	[PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD,
+};
+
+int asd_control_phy(struct sas_phy *phy, enum phy_func func)
+{
+	struct asd_ha_struct *asd_ha = phy->ha->lldd_ha;
+	struct asd_ascb *ascb;
+	int res = 1;
+
+	if (func == PHY_FUNC_CLEAR_ERROR_LOG)
+		return -ENOSYS;
+
+	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+	if (!ascb)
+		return -ENOMEM;
+
+	asd_build_control_phy(ascb, phy->id, phy_func_table[func]);
+	res = asd_post_ascb_list(asd_ha, ascb , 1);
+	if (res)
+		asd_ascb_free(ascb);
+
+	return res;
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_sds.c newtree/drivers/scsi/aic94xx/aic94xx_sds.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_sds.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_sds.c	2006-04-01 05:35:45.907489000 -0500
@@ -0,0 +1,1137 @@
+/*
+ * Aic94xx SAS/SATA driver access to shared data structures and memory
+ * maps.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_sds.c#35 $
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+
+/* ---------- OCM stuff ---------- */
+
+struct asd_ocm_dir_ent {
+	u8 type;
+	u8 offs[3];
+	u8 _r1;
+	u8 size[3];
+} __attribute__ ((packed));
+
+struct asd_ocm_dir {
+	char sig[2];
+	u8   _r1[2];
+	u8   major;          /* 0 */
+	u8   minor;          /* 0 */
+	u8   _r2;
+	u8   num_de;
+	struct asd_ocm_dir_ent entry[15];
+} __attribute__ ((packed));
+
+#define	OCM_DE_OCM_DIR			0x00
+#define	OCM_DE_WIN_DRVR			0x01
+#define	OCM_DE_BIOS_CHIM		0x02
+#define	OCM_DE_RAID_ENGN		0x03
+#define	OCM_DE_BIOS_INTL		0x04
+#define	OCM_DE_BIOS_CHIM_OSM		0x05
+#define	OCM_DE_BIOS_CHIM_DYNAMIC	0x06
+#define	OCM_DE_ADDC2C_RES0		0x07
+#define	OCM_DE_ADDC2C_RES1		0x08
+#define	OCM_DE_ADDC2C_RES2		0x09
+#define	OCM_DE_ADDC2C_RES3		0x0A
+
+#define OCM_INIT_DIR_ENTRIES	5
+/***************************************************************************
+*  OCM dircetory default
+***************************************************************************/
+static struct asd_ocm_dir OCMDirInit =
+{
+	.sig = {0x4D, 0x4F},	/* signature */
+	.num_de = OCM_INIT_DIR_ENTRIES,	/* no. of directory entries */
+};
+
+/***************************************************************************
+*  OCM dircetory Entries default
+***************************************************************************/
+static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
+{
+	{
+		.type = (OCM_DE_ADDC2C_RES0),	/* Entry type  */
+		.offs = {128},			/* Offset */
+		.size = {0, 4},			/* size */
+	},
+	{
+		.type = (OCM_DE_ADDC2C_RES1),	/* Entry type  */
+		.offs = {128, 4},		/* Offset */
+		.size = {0, 4},			/* size */
+	},
+	{
+		.type = (OCM_DE_ADDC2C_RES2),	/* Entry type  */
+		.offs = {128, 8},		/* Offset */
+		.size = {0, 4},			/* size */
+	},
+	{
+		.type = (OCM_DE_ADDC2C_RES3),	/* Entry type  */
+		.offs = {128, 12},		/* Offset */
+		.size = {0, 4},			/* size */
+	},
+	{
+		.type = (OCM_DE_WIN_DRVR),	/* Entry type  */
+		.offs = {128, 16},		/* Offset */
+		.size = {128, 235, 1},		/* size */
+	},
+};
+
+struct asd_bios_chim_struct {
+	char sig[4];
+	u8   major;          /* 1 */
+	u8   minor;          /* 0 */
+	u8   bios_major;
+	u8   bios_minor;
+	__le32  bios_build;
+	u8   flags;
+	u8   pci_slot;
+	__le16  ue_num;
+	__le16  ue_size;
+	u8  _r[14];
+	/* The unit element array is right here.
+	 */
+} __attribute__ ((packed));
+
+/**
+ * asd_read_ocm_seg - read an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to write the read data
+ * @offs: offset into OCM where to read from
+ * @size: how many bytes to read
+ *
+ * Return the number of bytes not read. Return 0 on success.
+ */
+static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+			    u32 offs, int size)
+{
+	u8 *p = buffer;
+	if (unlikely(asd_ha->iospace))
+		asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+	else {
+		for ( ; size > 0; size--, offs++, p++)
+			*p = asd_read_ocm_byte(asd_ha, offs);
+	}
+	return size;
+}
+
+static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
+			    struct asd_ocm_dir *dir, u32 offs)
+{
+	int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
+	if (err) {
+		ASD_DPRINTK("couldn't read ocm segment\n");
+		return err;
+	}
+
+	if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
+		ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
+			    dir->sig[0], dir->sig[1]);
+		return -ENOENT;
+	}
+	if (dir->major != 0) {
+		asd_printk("unsupported major version of ocm dir:0x%x\n",
+			   dir->major);
+		return -ENOENT;
+	}
+	dir->num_de &= 0xf;
+	return 0;
+}
+
+/**
+ * asd_write_ocm_seg - write an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to read the write data
+ * @offs: offset into OCM to write to
+ * @size: how many bytes to write
+ *
+ * Return the number of bytes not written. Return 0 on success.
+ */
+static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+			    u32 offs, int size)
+{
+	u8 *p = buffer;
+	if (unlikely(asd_ha->iospace))
+		asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+	else {
+		for ( ; size > 0; size--, offs++, p++)
+			asd_write_ocm_byte(asd_ha, offs, *p);
+	}
+	return;
+}
+
+#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
+
+static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
+			      u32 *offs, u32 *size)
+{
+	int i;
+	struct asd_ocm_dir_ent *ent;
+
+	for (i = 0; i < dir->num_de; i++) {
+		if (dir->entry[i].type == type)
+			break;
+	}
+	if (i >= dir->num_de)
+		return -ENOENT;
+	ent = &dir->entry[i];
+	*offs = (u32) THREE_TO_NUM(ent->offs);
+	*size = (u32) THREE_TO_NUM(ent->size);
+	return 0;
+}
+
+#define OCM_BIOS_CHIM_DE  2
+#define BC_BIOS_PRESENT   1
+
+static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
+			     struct asd_ocm_dir *dir)
+{
+	int err;
+	struct asd_bios_chim_struct *bc_struct;
+	u32 offs, size;
+
+	err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
+	if (err) {
+		ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
+		goto out;
+	}
+	err = -ENOMEM;
+	bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
+	if (!bc_struct) {
+		asd_printk("no memory for bios_chim struct\n");
+		goto out;
+	}
+	err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
+			       sizeof(*bc_struct));
+	if (err) {
+		ASD_DPRINTK("couldn't read ocm segment\n");
+		goto out2;
+	}
+	if (strncmp(bc_struct->sig, "SOIB", 4)
+	    && strncmp(bc_struct->sig, "IPSA", 4)) {
+		ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
+			    bc_struct->sig[0], bc_struct->sig[1],
+			    bc_struct->sig[2], bc_struct->sig[3]);
+		err = -ENOENT;
+		goto out2;
+	}
+	if (bc_struct->major != 1) {
+		asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
+			   bc_struct->major);
+		err = -ENOENT;
+		goto out2;
+	}
+	if (bc_struct->flags & BC_BIOS_PRESENT) {
+		asd_ha->hw_prof.bios.present = 1;
+		asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
+		asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
+		asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
+		ASD_DPRINTK("BIOS present (%d,%d), %d\n",
+			    asd_ha->hw_prof.bios.maj,
+			    asd_ha->hw_prof.bios.min,
+			    asd_ha->hw_prof.bios.bld);
+	}
+	asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
+	asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
+	ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
+		    asd_ha->hw_prof.ue.size);
+	size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
+	if (size > 0) {
+		err = -ENOMEM;
+		asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
+		if (!asd_ha->hw_prof.ue.area)
+			goto out2;
+		err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
+				       offs + sizeof(*bc_struct), size);
+		if (err) {
+			kfree(asd_ha->hw_prof.ue.area);
+			asd_ha->hw_prof.ue.area = NULL;
+			asd_ha->hw_prof.ue.num  = 0;
+			asd_ha->hw_prof.ue.size = 0;
+			ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
+		}
+	}
+out2:
+	kfree(bc_struct);
+out:
+	return err;
+}
+
+static void
+asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
+{
+	int i;
+
+	/* Zero OCM */
+	for (i = 0; i < OCM_MAX_SIZE; i += 4)
+		asd_write_ocm_dword(asd_ha, i, 0);
+
+	/* Write Dir */
+	asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
+			  sizeof(struct asd_ocm_dir));
+
+	/* Write Dir Entries */
+	for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
+		asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
+				  sizeof(struct asd_ocm_dir) +
+				  (i * sizeof(struct asd_ocm_dir_ent))
+				  , sizeof(struct asd_ocm_dir_ent));
+
+}
+
+static int
+asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
+{
+	struct pci_dev *pcidev = asd_ha->pcidev;
+	u32 reg;
+	int err = 0;
+	u32 v;
+
+	/* check if OCM has been initialized by BIOS */
+	reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
+
+	if (!(reg & OCMINITIALIZED)) {
+		err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
+		if (err) {
+			asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
+					pci_name(pcidev));
+			goto out;
+		}
+
+		printk(KERN_INFO "OCM is not initialized by BIOS,"
+		       "reinitialize it and ignore it, current IntrptStatus"
+		       "is 0x%x\n", v);
+
+		if (v)
+			err = pci_write_config_dword(pcidev,
+						     PCIC_INTRPT_STAT, v);
+		if (err) {
+			asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
+					pci_name(pcidev));
+			goto out;
+		}
+
+		asd_hwi_initialize_ocm_dir(asd_ha);
+
+	}
+out:
+	return err;
+}
+
+/**
+ * asd_read_ocm - read on chip memory (OCM)
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_ocm(struct asd_ha_struct *asd_ha)
+{
+	int err;
+	struct asd_ocm_dir *dir;
+
+	if (asd_hwi_check_ocm_access(asd_ha))
+		return -1;
+
+	dir = kmalloc(sizeof(*dir), GFP_KERNEL);
+	if (!dir) {
+		asd_printk("no memory for ocm dir\n");
+		return -ENOMEM;
+	}
+
+	err = asd_read_ocm_dir(asd_ha, dir, 0);
+	if (err)
+		goto out;
+
+	err = asd_get_bios_chim(asd_ha, dir);
+out:
+	kfree(dir);
+	return err;
+}
+
+/* ---------- FLASH stuff ---------- */
+
+#define FLASH_RESET			0xF0
+#define FLASH_MANUF_AMD                 1
+
+#define FLASH_SIZE                      0x200000
+#define FLASH_DIR_COOKIE                "*** ADAPTEC FLASH DIRECTORY *** "
+#define FLASH_NEXT_ENTRY_OFFS		0x2000
+#define FLASH_MAX_DIR_ENTRIES		32
+
+#define FLASH_DE_TYPE_MASK              0x3FFFFFFF
+#define FLASH_DE_MS                     0x120
+#define FLASH_DE_CTRL_A_USER            0xE0
+
+struct asd_flash_de {
+	__le32   type;
+	__le32   offs;
+	__le32   pad_size;
+	__le32   image_size;
+	__le32   chksum;
+	u8       _r[12];
+	u8       version[32];
+} __attribute__ ((packed));
+
+struct asd_flash_dir {
+	u8    cookie[32];
+	__le32   rev;		  /* 2 */
+	__le32   chksum;
+	__le32   chksum_antidote;
+	__le32   bld;
+	u8    bld_id[32];	  /* build id data */
+	u8    ver_data[32];	  /* date and time of build */
+	__le32   ae_mask;
+	__le32   v_mask;
+	__le32   oc_mask;
+	u8    _r[20];
+	struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
+} __attribute__ ((packed));
+
+struct asd_manuf_sec {
+	char  sig[2];		  /* 'S', 'M' */
+	u16   offs_next;
+	u8    maj;           /* 0 */
+	u8    min;           /* 0 */
+	u16   chksum;
+	u16   size;
+	u8    _r[6];
+	u8    sas_addr[SAS_ADDR_SIZE];
+	u8    pcba_sn[ASD_PCBA_SN_SIZE];
+	/* Here start the other segments */
+	u8    linked_list[0];
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_desc {
+	u8    state;         /* low 4 bits */
+#define MS_PHY_STATE_ENABLEABLE 0
+#define MS_PHY_STATE_REPORTED   1
+#define MS_PHY_STATE_HIDDEN     2
+	u8    phy_id;
+	u16   _r;
+	u8    phy_control_0; /* mode 5 reg 0x160 */
+	u8    phy_control_1; /* mode 5 reg 0x161 */
+	u8    phy_control_2; /* mode 5 reg 0x162 */
+	u8    phy_control_3; /* mode 5 reg 0x163 */
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_param {
+	char  sig[2];		  /* 'P', 'M' */
+	u16   next;
+	u8    maj;           /* 0 */
+	u8    min;           /* 2 */
+	u8    num_phy_desc;  /* 8 */
+	u8    phy_desc_size; /* 8 */
+	u8    _r[3];
+	u8    usage_model_id;
+	u32   _r2;
+	struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_sb_type[] = {
+	"unknown",
+	"SGPIO",
+	[2 ... 0x7F] = "unknown",
+	[0x80] = "ADPT_I2C",
+	[0x81 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+#endif
+
+struct asd_ms_sb_desc {
+	u8    type;
+	u8    node_desc_index;
+	u8    conn_desc_index;
+	u8    _recvd[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_conn_type[] = {
+	[0 ... 7] = "unknown",
+	"SFF8470",
+	"SFF8482",
+	"SFF8484",
+	[0x80] = "PCIX_DAUGHTER0",
+	[0x81] = "SAS_DAUGHTER0",
+	[0x82 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+
+static const char *asd_conn_location[] = {
+	"unknown",
+	"internal",
+	"external",
+	"board_to_board",
+};
+#endif
+
+struct asd_ms_conn_desc {
+	u8    type;
+	u8    location;
+	u8    num_sideband_desc;
+	u8    size_sideband_desc;
+	u32   _resvd;
+	u8    name[16];
+	struct asd_ms_sb_desc sb_desc[0];
+} __attribute__ ((packed));
+
+struct asd_nd_phy_desc {
+	u8    vp_attch_type;
+	u8    attch_specific[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_node_type[] = {
+	"IOP",
+	"IO_CONTROLLER",
+	"EXPANDER",
+	"PORT_MULTIPLIER",
+	"PORT_MULTIPLEXER",
+	"MULTI_DROP_I2C_BUS",
+};
+#endif
+
+struct asd_ms_node_desc {
+	u8    type;
+	u8    num_phy_desc;
+	u8    size_phy_desc;
+	u8    _resvd;
+	u8    name[16];
+	struct asd_nd_phy_desc phy_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ms_conn_map {
+	char  sig[2];		  /* 'M', 'C' */
+	__le16 next;
+	u8    maj;		  /* 0 */
+	u8    min;		  /* 0 */
+	__le16 cm_size;		  /* size of this struct */
+	u8    num_conn;
+	u8    conn_size;
+	u8    num_nodes;
+	u8    usage_model_id;
+	u32   _resvd;
+	struct asd_ms_conn_desc conn_desc[0];
+	struct asd_ms_node_desc node_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_entry {
+	u8    sas_addr[SAS_ADDR_SIZE];
+	u8    sas_link_rates;  /* max in hi bits, min in low bits */
+	u8    flags;
+	u8    sata_link_rates;
+	u8    _r[5];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_settings {
+	u8    id0;		  /* P'h'y */
+	u8    _r;
+	u16   next;
+	u8    num_phys;	      /* number of PHYs in the PCI function */
+	u8    _r2[3];
+	struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+struct asd_ll_el {
+	u8   id0;
+	u8   id1;
+	__le16  next;
+	u8   something_here[0];
+} __attribute__ ((packed));
+
+static int asd_poll_flash(struct asd_ha_struct *asd_ha)
+{
+	int c;
+	u8 d;
+
+	for (c = 5000; c > 0; c--) {
+		d  = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+		d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+		if (!d)
+			return 0;
+		udelay(5);
+	}
+	return -ENOENT;
+}
+
+static int asd_reset_flash(struct asd_ha_struct *asd_ha)
+{
+	int err;
+
+	err = asd_poll_flash(asd_ha);
+	if (err)
+		return err;
+	asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
+	err = asd_poll_flash(asd_ha);
+
+	return err;
+}
+
+static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
+				     void *buffer, u32 offs, int size)
+{
+	asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
+			    size);
+	return 0;
+}
+
+/**
+ * asd_find_flash_dir - finds and reads the flash directory
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to flash directory structure
+ *
+ * If found, the flash directory segment will be copied to
+ * @flash_dir.  Return 1 if found, 0 if not.
+ */
+static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
+			      struct asd_flash_dir *flash_dir)
+{
+	u32 v;
+	for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
+		asd_read_flash_seg(asd_ha, flash_dir, v,
+				   sizeof(FLASH_DIR_COOKIE)-1);
+		if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
+			   sizeof(FLASH_DIR_COOKIE)-1) == 0) {
+			asd_ha->hw_prof.flash.dir_offs = v;
+			asd_read_flash_seg(asd_ha, flash_dir, v,
+					   sizeof(*flash_dir));
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int asd_flash_getid(struct asd_ha_struct *asd_ha)
+{
+	int err = 0;
+	u32 reg, inc;
+
+	reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
+
+	if (!(reg & FLASHEX)) {
+		ASD_DPRINTK("flash doesn't exist\n");
+		return -ENOENT;
+	}
+	if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
+				  &asd_ha->hw_prof.flash.bar)) {
+		asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
+			   pci_name(asd_ha->pcidev));
+		return -ENOENT;
+	}
+	asd_ha->hw_prof.flash.present = 1;
+	asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
+	err = asd_reset_flash(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+		return err;
+	}
+	/* Get flash info. This would most likely be AMD Am29LV family flash.
+	 * First try the sequence for word mode.  It is the same as for
+	 * 008B (byte mode only), 160B (word mode) and 800D (word mode).
+	 */
+	reg = asd_ha->hw_prof.flash.bar;
+	inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
+	asd_write_reg_byte(asd_ha, reg + 0x555, 0xAA);
+	asd_write_reg_byte(asd_ha, reg + 0x2AA, 0x55);
+	asd_write_reg_byte(asd_ha, reg + 0x555, 0x90);
+	asd_ha->hw_prof.flash.manuf = asd_read_reg_byte(asd_ha, reg);
+	asd_ha->hw_prof.flash.dev_id= asd_read_reg_byte(asd_ha,reg+inc);
+	asd_ha->hw_prof.flash.sec_prot = asd_read_reg_byte(asd_ha,reg+inc+inc);
+	/* Get out of autoselect mode. */
+	err = asd_reset_flash(asd_ha);
+
+	if (asd_ha->hw_prof.flash.manuf == FLASH_MANUF_AMD) {
+		ASD_DPRINTK("0Found FLASH(%d) manuf:%d, dev_id:0x%x, "
+			    "sec_prot:%d\n",
+			    asd_ha->hw_prof.flash.wide ? 16 : 8,
+			    asd_ha->hw_prof.flash.manuf,
+			    asd_ha->hw_prof.flash.dev_id,
+			    asd_ha->hw_prof.flash.sec_prot);
+		return 0;
+	}
+
+	/* Ok, try the sequence for byte mode of 160B and 800D.
+	 * We may actually never need this.
+	 */
+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
+	asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
+	asd_ha->hw_prof.flash.manuf = asd_read_reg_byte(asd_ha, reg);
+	asd_ha->hw_prof.flash.dev_id = asd_read_reg_byte(asd_ha, reg + 2);
+	asd_ha->hw_prof.flash.sec_prot = asd_read_reg_byte(asd_ha, reg + 4);
+	err = asd_reset_flash(asd_ha);
+
+	if (asd_ha->hw_prof.flash.manuf == FLASH_MANUF_AMD) {
+		ASD_DPRINTK("1Found FLASH(%d) manuf:%d, dev_id:0x%x, "
+			    "sec_prot:%d\n",
+			    asd_ha->hw_prof.flash.wide ? 16 : 8,
+			    asd_ha->hw_prof.flash.manuf,
+			    asd_ha->hw_prof.flash.dev_id,
+			    asd_ha->hw_prof.flash.sec_prot);
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static u16 asd_calc_flash_chksum(u16 *p, int size)
+{
+	u16 chksum = 0;
+
+	while (size-- > 0)
+		chksum += *p++;
+
+	return chksum;
+}
+
+
+static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
+			     u32 *offs, u32 *size)
+{
+	int i;
+	struct asd_flash_de *de;
+
+	for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
+		u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
+
+		type &= FLASH_DE_TYPE_MASK;
+		if (type == entry_type)
+			break;
+	}
+	if (i >= FLASH_MAX_DIR_ENTRIES)
+		return -ENOENT;
+	de = &flash_dir->dir_entry[i];
+	*offs = le32_to_cpu(de->offs);
+	*size = le32_to_cpu(de->pad_size);
+	return 0;
+}
+
+static int asd_validate_ms(struct asd_manuf_sec *ms)
+{
+	if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
+		ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
+			    ms->sig[0], ms->sig[1]);
+		return -ENOENT;
+	}
+	if (ms->maj != 0) {
+		asd_printk("unsupported manuf. sector. major version:%x\n",
+			   ms->maj);
+		return -ENOENT;
+	}
+	ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
+	ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
+	ms->size = le16_to_cpu((__force __le16) ms->size);
+
+	if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
+		asd_printk("failed manuf sector checksum\n");
+	}
+
+	return 0;
+}
+
+static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
+			       struct asd_manuf_sec *ms)
+{
+	memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
+	return 0;
+}
+
+static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
+			      struct asd_manuf_sec *ms)
+{
+	memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
+	asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
+	return 0;
+}
+
+/**
+ * asd_find_ll_by_id - find a linked list entry by its id
+ * @start: void pointer to the first element in the linked list
+ * @id0: the first byte of the id  (offs 0)
+ * @id1: the second byte of the id (offs 1)
+ *
+ * @start has to be the _base_ element start, since the
+ * linked list entries's offset is from this pointer.
+ * Some linked list entries use only the first id, in which case
+ * you can pass 0xFF for the second.
+ */
+static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
+{
+	struct asd_ll_el *el = start;
+
+	do {
+		switch (id1) {
+		default:
+			if (el->id1 == id1)
+		case 0xFF:
+				if (el->id0 == id0)
+					return el;
+		}
+		el = start + le16_to_cpu(el->next);
+	} while (el != start);
+
+	return NULL;
+}
+
+/**
+ * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @manuf_sec: pointer to the manufacturing sector
+ *
+ * The manufacturing sector contans also the linked list of sub-segments,
+ * since when it was read, its size was taken from the flash directory,
+ * not from the structure size.
+ *
+ * HIDDEN phys do not count in the total count.  REPORTED phys cannot
+ * be enabled but are reported and counted towards the total.
+ * ENEBLEABLE phys are enabled by default and count towards the total.
+ * The absolute total phy number is ASD_MAX_PHYS.  hw_prof->num_phys
+ * merely specifies the number of phys the host adapter decided to
+ * report.  E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
+ * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE.
+ * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
+ * are actually enabled (enabled by default, max number of phys
+ * enableable in this case).
+ */
+static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
+				 struct asd_manuf_sec *manuf_sec)
+{
+	int i;
+	int en_phys = 0;
+	int rep_phys = 0;
+	struct asd_manuf_phy_param *phy_param;
+	struct asd_manuf_phy_param dflt_phy_param;
+
+	phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
+	if (!phy_param) {
+		ASD_DPRINTK("ms: no phy parameters found\n");
+		ASD_DPRINTK("ms: Creating default phy parameters\n");
+		dflt_phy_param.sig[0] = 'P';
+		dflt_phy_param.sig[1] = 'M';
+		dflt_phy_param.maj = 0;
+		dflt_phy_param.min = 2;
+		dflt_phy_param.num_phy_desc = 8;
+		dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
+		for (i =0; i < ASD_MAX_PHYS; i++) {
+			dflt_phy_param.phy_desc[i].state = 0;
+			dflt_phy_param.phy_desc[i].phy_id = i;
+			dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
+			dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
+			dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
+			dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
+		}
+
+		phy_param = &dflt_phy_param;
+
+	}
+
+	if (phy_param->maj != 0) {
+		asd_printk("unsupported manuf. phy param major version:0x%x\n",
+			   phy_param->maj);
+		return -ENOENT;
+	}
+
+	ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
+	asd_ha->hw_prof.enabled_phys = 0;
+	for (i = 0; i < phy_param->num_phy_desc; i++) {
+		struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
+		switch (pd->state & 0xF) {
+		case MS_PHY_STATE_HIDDEN:
+			ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
+			continue;
+		case MS_PHY_STATE_REPORTED:
+			ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
+			asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+			rep_phys++;
+			continue;
+		case MS_PHY_STATE_ENABLEABLE:
+			ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i);
+			asd_ha->hw_prof.enabled_phys |= (1 << i);
+			en_phys++;
+			break;
+		}
+		asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
+		asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
+		asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
+		asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
+	}
+	asd_ha->hw_prof.max_phys = rep_phys + en_phys;
+	asd_ha->hw_prof.num_phys = en_phys;
+	ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
+		    asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
+	ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
+	return 0;
+}
+
+static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
+				    struct asd_manuf_sec *manuf_sec)
+{
+	struct asd_ms_conn_map *cm;
+
+	cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
+	if (!cm) {
+		ASD_DPRINTK("ms: no connector map found\n");
+		return 0;
+	}
+
+	if (cm->maj != 0) {
+		ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
+			    "\n", cm->maj);
+		return -ENOENT;
+	}
+
+	/* XXX */
+
+	return 0;
+}
+
+
+/**
+ * asd_process_ms - find and extract information from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ms(struct asd_ha_struct *asd_ha,
+			  struct asd_flash_dir *flash_dir)
+{
+	int err;
+	struct asd_manuf_sec *manuf_sec;
+	u32 offs, size;
+
+	err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
+	if (err) {
+		ASD_DPRINTK("Couldn't find the manuf. sector\n");
+		goto out;
+	}
+
+	if (size == 0)
+		goto out;
+
+	err = -ENOMEM;
+	manuf_sec = kmalloc(size, GFP_KERNEL);
+	if (!manuf_sec) {
+		ASD_DPRINTK("no mem for manuf sector\n");
+		goto out;
+	}
+
+	err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
+	if (err) {
+		ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
+			    offs, size);
+		goto out2;
+	}
+
+	err = asd_validate_ms(manuf_sec);
+	if (err) {
+		ASD_DPRINTK("couldn't validate manuf sector\n");
+		goto out2;
+	}
+
+	err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
+	if (err) {
+		ASD_DPRINTK("couldn't read the SAS_ADDR\n");
+		goto out2;
+	}
+	ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
+		    SAS_ADDR(asd_ha->hw_prof.sas_addr));
+
+	err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
+	if (err) {
+		ASD_DPRINTK("couldn't read the PCBA SN\n");
+		goto out2;
+	}
+	ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
+
+	err = asd_ms_get_phy_params(asd_ha, manuf_sec);
+	if (err) {
+		ASD_DPRINTK("ms: couldn't get phy parameters\n");
+		goto out2;
+	}
+
+	err = asd_ms_get_connector_map(asd_ha, manuf_sec);
+	if (err) {
+		ASD_DPRINTK("ms: couldn't get connector map\n");
+		goto out2;
+	}
+
+out2:
+	kfree(manuf_sec);
+out:
+	return err;
+}
+
+static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
+					  struct asd_ctrla_phy_settings *ps)
+{
+	int i;
+	for (i = 0; i < ps->num_phys; i++) {
+		struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
+
+		if (!PHY_ENABLED(asd_ha, i))
+			continue;
+		if (*(u64 *)pe->sas_addr == 0) {
+			asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+			continue;
+		}
+		/* This is the SAS address which should be sent in IDENTIFY. */
+		memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
+		       SAS_ADDR_SIZE);
+		asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
+			(pe->sas_link_rates & 0xF0) >> 4;
+		asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
+			(pe->sas_link_rates & 0x0F);
+		asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
+			(pe->sata_link_rates & 0xF0) >> 4;
+		asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
+			(pe->sata_link_rates & 0x0F);
+		asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
+		ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
+			    " sata rate:0x%x-0x%x, flags:0x%x\n",
+			    i,
+			    SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
+			    asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
+			    asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
+			    asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
+			    asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
+			    asd_ha->hw_prof.phy_desc[i].flags);
+	}
+
+	return 0;
+}
+
+/**
+ * asd_process_ctrl_a_user - process CTRL-A user settings
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
+				   struct asd_flash_dir *flash_dir)
+{
+	int err, i;
+	u32 offs, size;
+	struct asd_ll_el *el;
+	struct asd_ctrla_phy_settings *ps;
+	struct asd_ctrla_phy_settings dflt_ps;
+
+	err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
+	if (err) {
+		ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
+		ASD_DPRINTK("Creating default CTRL-A user settings section\n");
+
+		dflt_ps.id0 = 'h';
+		dflt_ps.num_phys = 8;
+		for (i =0; i < ASD_MAX_PHYS; i++) {
+			memcpy(dflt_ps.phy_ent[i].sas_addr,
+			       asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+			dflt_ps.phy_ent[i].sas_link_rates = 0x98;
+			dflt_ps.phy_ent[i].flags = 0x0;
+			dflt_ps.phy_ent[i].sata_link_rates = 0x0;
+		}
+
+		size = sizeof(struct asd_ctrla_phy_settings);
+		ps = &dflt_ps;
+	}
+
+	if (size == 0)
+		goto out;
+
+	err = -ENOMEM;
+	el = kmalloc(size, GFP_KERNEL);
+	if (!el) {
+		ASD_DPRINTK("no mem for ctrla user settings section\n");
+		goto out;
+	}
+
+	err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
+	if (err) {
+		ASD_DPRINTK("couldn't read ctrla phy settings section\n");
+		goto out2;
+	}
+
+	err = -ENOENT;
+	ps = asd_find_ll_by_id(el, 'h', 0xFF);
+	if (!ps) {
+		ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
+		goto out2;
+	}
+
+	err = asd_process_ctrla_phy_settings(asd_ha, ps);
+	if (err) {
+		ASD_DPRINTK("couldn't process ctrla phy settings\n");
+		goto out2;
+	}
+out2:
+	kfree(el);
+out:
+	return err;
+}
+
+/**
+ * asd_read_flash - read flash memory
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_flash(struct asd_ha_struct *asd_ha)
+{
+	int err;
+	struct asd_flash_dir *flash_dir;
+
+	err = asd_flash_getid(asd_ha);
+	if (err)
+		return err;
+
+	flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
+	if (!flash_dir)
+		return -ENOMEM;
+
+	err = -ENOENT;
+	if (!asd_find_flash_dir(asd_ha, flash_dir)) {
+		ASD_DPRINTK("couldn't find flash directory\n");
+		goto out;
+	}
+
+	if (le32_to_cpu(flash_dir->rev) != 2) {
+		asd_printk("unsupported flash dir version:0x%x\n",
+			   le32_to_cpu(flash_dir->rev));
+		goto out;
+	}
+
+	err = asd_process_ms(asd_ha, flash_dir);
+	if (err) {
+		ASD_DPRINTK("couldn't process manuf sector settings\n");
+		goto out;
+	}
+
+	err = asd_process_ctrl_a_user(asd_ha, flash_dir);
+	if (err) {
+		ASD_DPRINTK("couldn't process CTRL-A user settings\n");
+		goto out;
+	}
+
+out:
+	kfree(flash_dir);
+	return err;
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_seq.c newtree/drivers/scsi/aic94xx/aic94xx_seq.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_seq.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_seq.c	2006-04-01 05:35:45.911489250 -0500
@@ -0,0 +1,1319 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Parts of this code adapted from David Chaw's adp94xx_seq.c.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_seq.c#42 $
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+#include "aic94xx_seq_microcode.c"
+
+/* It takes no more than 0.05 us for an instruction
+ * to complete. So waiting for 1 us should be more than
+ * plenty.
+ */
+#define PAUSE_DELAY 1
+#define PAUSE_TRIES 1000
+
+static u16 first_scb_site_no = 0xFFFF;
+static u16 last_scb_site_no;
+
+/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */
+
+/**
+ * asd_pause_cseq - pause the central sequencer
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_cseq(struct asd_ha_struct *asd_ha)
+{
+	int	count = PAUSE_TRIES;
+	u32	arp2ctl;
+
+	arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+	if (arp2ctl & PAUSED)
+		return 0;
+
+	asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE);
+	do {
+		arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+		if (arp2ctl & PAUSED)
+			return 0;
+		udelay(PAUSE_DELAY);
+	} while (--count > 0);
+
+	ASD_DPRINTK("couldn't pause CSEQ\n");
+	return -1;
+}
+
+/**
+ * asd_unpause_cseq - unpause the central sequencer.
+ * @asd_ha: pointer to host adapter structure.
+ *
+ * Return 0 on success, negative on error.
+ */
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha)
+{
+	u32	arp2ctl;
+	int	count = PAUSE_TRIES;
+
+	arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+	if (!(arp2ctl & PAUSED))
+		return 0;
+
+	asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE);
+	do {
+		arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+		if (!(arp2ctl & PAUSED))
+			return 0;
+		udelay(PAUSE_DELAY);
+	} while (--count > 0);
+
+	ASD_DPRINTK("couldn't unpause the CSEQ\n");
+	return -1;
+}
+
+/**
+ * asd_seq_pause_lseq - pause a link sequencer
+ * @asd_ha: pointer to a host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+	u32    arp2ctl;
+	int    count = PAUSE_TRIES;
+
+	arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+	if (arp2ctl & PAUSED)
+		return 0;
+
+	asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE);
+	do {
+		arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+		if (arp2ctl & PAUSED)
+			return 0;
+		udelay(PAUSE_DELAY);
+	} while (--count > 0);
+
+	ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq);
+	return -1;
+}
+
+/**
+ * asd_pause_lseq - pause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+	int lseq;
+	int err = 0;
+
+	for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+		err = asd_seq_pause_lseq(asd_ha, lseq);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
+/**
+ * asd_seq_unpause_lseq - unpause a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+	u32 arp2ctl;
+	int count = PAUSE_TRIES;
+
+	arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+	if (!(arp2ctl & PAUSED))
+		return 0;
+
+	asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE);
+	do {
+		arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+		if (!(arp2ctl & PAUSED))
+			return 0;
+		udelay(PAUSE_DELAY);
+	} while (--count > 0);
+
+	ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq);
+	return 0;
+}
+
+
+/**
+ * asd_unpause_lseq - unpause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+	int lseq;
+	int err = 0;
+
+	for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+		err = asd_seq_unpause_lseq(asd_ha, lseq);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
+/* ---------- Downloading CSEQ/LSEQ microcode ---------- */
+
+static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+			   u32 size)
+{
+	u32 addr = CSEQ_RAM_REG_BASE_ADR;
+	const u32 *prog = (u32 *) _prog;
+	u32 i;
+
+	for (i = 0; i < size; i += 4, prog++, addr += 4) {
+		u32 val = asd_read_reg_dword(asd_ha, addr);
+
+		if (le32_to_cpu(*prog) != val) {
+			asd_printk("%s: cseq verify failed at %u "
+				   "read:0x%x, wanted:0x%x\n",
+				   pci_name(asd_ha->pcidev),
+				   i, val, le32_to_cpu(*prog));
+			return -1;
+		}
+	}
+	ASD_DPRINTK("verified %d bytes, passed\n", size);
+	return 0;
+}
+
+/**
+ * asd_verify_lseq - verify the microcode of a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @_prog: pointer to the microcode
+ * @size: size of the microcode in bytes
+ * @lseq: link sequencer of interest
+ *
+ * The link sequencer code is accessed in 4 KB pages, which are selected
+ * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register.
+ * The 10 KB LSEQm instruction code is mapped, page at a time, at
+ * LmSEQRAM address.
+ */
+static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+			   u32 size, int lseq)
+{
+#define LSEQ_CODEPAGE_SIZE 4096
+	int pages =  (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE;
+	u32 page;
+	const u32 *prog = (u32 *) _prog;
+
+	for (page = 0; page < pages; page++) {
+		u32 i;
+
+		asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq),
+				    page << LmRAMPAGE_LSHIFT);
+		for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE;
+		     i += 4, prog++, size-=4) {
+
+			u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i);
+
+			if (le32_to_cpu(*prog) != val) {
+				asd_printk("%s: LSEQ%d verify failed "
+					   "page:%d, offs:%d\n",
+					   pci_name(asd_ha->pcidev),
+					   lseq, page, i);
+				return -1;
+			}
+		}
+	}
+	ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq,
+		    (int)((u8 *)prog-_prog));
+	return 0;
+}
+
+/**
+ * asd_verify_seq -- verify CSEQ/LSEQ microcode
+ * @asd_ha: pointer to host adapter structure
+ * @prog: pointer to microcode
+ * @size: size of the microcode
+ * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest
+ *
+ * Return 0 if microcode is correct, negative on mismatch.
+ */
+static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog,
+			      u32 size, u8 lseq_mask)
+{
+	if (lseq_mask == 0)
+		return asd_verify_cseq(asd_ha, prog, size);
+	else {
+		int lseq, err;
+
+		for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+			err = asd_verify_lseq(asd_ha, prog, size, lseq);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+#define ASD_DMA_MODE_DOWNLOAD
+#ifdef ASD_DMA_MODE_DOWNLOAD
+/* This is the size of the CSEQ Mapped instruction page */
+#define MAX_DMA_OVLY_COUNT ((1U << 14)-1)
+static int asd_download_seq(struct asd_ha_struct *asd_ha,
+			    const u8 * const prog, u32 size, u8 lseq_mask)
+{
+	u32 comstaten;
+	u32 reg;
+	int page;
+	const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT;
+	struct asd_dma_tok *token;
+	int err = 0;
+
+	if (size % 4) {
+		asd_printk("sequencer program not multiple of 4\n");
+		return -1;
+	}
+
+	asd_pause_cseq(asd_ha);
+	asd_pause_lseq(asd_ha, 0xFF);
+
+	/* save, disable and clear interrupts */
+	comstaten = asd_read_reg_dword(asd_ha, COMSTATEN);
+	asd_write_reg_dword(asd_ha, COMSTATEN, 0);
+	asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK);
+
+	asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+	asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK);
+
+	token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL);
+	if (!token) {
+		asd_printk("out of memory for dma SEQ download\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	ASD_DPRINTK("dma-ing %d bytes\n", size);
+
+	for (page = 0; page < pages; page++) {
+		int i;
+		u32 left = min(size-page*MAX_DMA_OVLY_COUNT,
+			       (u32)MAX_DMA_OVLY_COUNT);
+
+		memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left);
+		asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle);
+		asd_write_reg_dword(asd_ha, OVLYDMACNT, left);
+		reg = !page ? RESETOVLYDMA : 0;
+		reg |= (STARTOVLYDMA | OVLYHALTERR);
+		reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+		/* Start DMA. */
+		asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+		for (i = PAUSE_TRIES*100; i > 0; i--) {
+			u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL);
+			if (!(dmadone & OVLYDMAACT))
+				break;
+			udelay(PAUSE_DELAY);
+		}
+	}
+
+	reg = asd_read_reg_dword(asd_ha, COMSTAT);
+	if (!(reg & OVLYDMADONE) || (reg & OVLYERR)
+	    || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){
+		asd_printk("%s: error DMA-ing sequencer code\n",
+			   pci_name(asd_ha->pcidev));
+		err = -ENODEV;
+	}
+
+	asd_free_coherent(asd_ha, token);
+ out:
+	asd_write_reg_dword(asd_ha, COMSTATEN, comstaten);
+
+	return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask);
+}
+#else /* ASD_DMA_MODE_DOWNLOAD */
+static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+			    u32 size, u8 lseq_mask)
+{
+	int i;
+	u32 reg = 0;
+	const u32 *prog = (u32 *) _prog;
+
+	if (size % 4) {
+		asd_printk("sequencer program not multiple of 4\n");
+		return -1;
+	}
+
+	asd_pause_cseq(asd_ha);
+	asd_pause_lseq(asd_ha, 0xFF);
+
+	reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+	reg |= PIOCMODE;
+
+	asd_write_reg_dword(asd_ha, OVLYDMACNT, size);
+	asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+	ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n",
+		    lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : "");
+
+	for (i = 0; i < size; i += 4, prog++)
+		asd_write_reg_dword(asd_ha, SPIODATA, *prog);
+
+	reg = (reg & ~PIOCMODE) | OVLYHALTERR;
+	asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+	return asd_verify_seq(asd_ha, _prog, size, lseq_mask);
+}
+#endif /* ASD_DMA_MODE_DOWNLOAD */
+
+/**
+ * asd_seq_download_seqs - download the sequencer microcode
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Download the central and link sequencer microcode.
+ */
+static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha)
+{
+	int 	err;
+
+	if (!asd_ha->hw_prof.enabled_phys) {
+		asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev));
+		return -ENODEV;
+	}
+
+	/* Download the CSEQ */
+	ASD_DPRINTK("downloading CSEQ...\n");
+	err = asd_download_seq(asd_ha, Cseq, sizeof(Cseq), 0);
+	if (err) {
+		asd_printk("CSEQ download failed:%d\n", err);
+		return err;
+	}
+
+	/* Download the Link Sequencers code. All of the Link Sequencers
+	 * microcode can be downloaded at the same time.
+	 */
+	ASD_DPRINTK("downloading LSEQs...\n");
+	err = asd_download_seq(asd_ha, Lseq, sizeof(Lseq),
+			       asd_ha->hw_prof.enabled_phys);
+	if (err) {
+		/* Try it one at a time */
+		u8 lseq;
+		u8 lseq_mask = asd_ha->hw_prof.enabled_phys;
+
+		for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+			err = asd_download_seq(asd_ha, Lseq, sizeof(Lseq),
+					       1<<lseq);
+			if (err)
+				break;
+		}
+	}
+	if (err)
+		asd_printk("LSEQs download failed:%d\n", err);
+
+	return err;
+}
+
+/* ---------- Initializing the chip, chip memory, etc. ---------- */
+
+/**
+ * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha)
+{
+	/* CSEQ Mode Independent, page 4 setup. */
+	asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_REG0, 0);
+	asd_write_reg_word(asd_ha, CSEQ_REG1, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_REG2, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0);
+	{
+		u8 con = asd_read_reg_byte(asd_ha, CCONEXIST);
+		u8 val = hweight8(con);
+		asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val);
+	}
+	asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0);
+
+	/* CSEQ Mode independent, page 5 setup. */
+	asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0);
+	asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0);
+
+	/* CSEQ Mode independent, page 6 setup. */
+	asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0);
+	asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0);
+	asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0);
+	asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0);
+	asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0);
+	asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF);
+	/* Calculate the free scb mask. */
+	{
+		u16 cmdctx = asd_get_cmdctx_size(asd_ha);
+		cmdctx = (~((cmdctx/128)-1)) >> 8;
+		asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx);
+	}
+	asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD,
+			   first_scb_site_no);
+	asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL,
+			   last_scb_site_no);
+	asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF);
+
+	/* CSEQ Mode independent, page 7 setup. */
+	asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0);
+	asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0);
+	asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0);
+}
+
+/**
+ * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha)
+{
+	int	i;
+	int	moffs;
+
+	moffs = CSEQ_PAGE_SIZE * 2;
+
+	/* CSEQ Mode dependent, modes 0-7, page 0 setup. */
+	for (i = 0; i < 8; i++) {
+		asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0);
+		asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0);
+		asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF);
+		asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF);
+		asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0);
+	}
+
+	/* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */
+
+	/* CSEQ Mode dependent, mode 8, page 0 setup. */
+	asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF);
+	asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0);
+	asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0);
+	asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0);
+	asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0);
+	asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0);
+	asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0);
+	asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0);
+	asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0);
+	asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0);
+	asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0);
+	asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE,
+			   (u16)last_scb_site_no+1);
+	asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE,
+			   (u16)asd_ha->hw_prof.max_ddbs);
+
+	/* CSEQ Mode dependent, mode 8, page 1 setup. */
+	asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0);
+	asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0);
+
+	/* CSEQ Mode dependent, mode 8, page 2 setup. */
+	/* Tell the sequencer the bus address of the first SCB. */
+	asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER,
+			   asd_ha->seq.next_scb.dma_handle);
+	ASD_DPRINTK("First SCB dma_handle: 0x%08llx\n",
+		    (u64)asd_ha->seq.next_scb.dma_handle);
+
+	/* Tell the sequencer the first Done List entry address. */
+	asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE,
+			   asd_ha->seq.actual_dl->dma_handle);
+
+	/* Initialize the Q_DONE_POINTER with the least significant
+	 * 4 bytes of the first Done List address. */
+	asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER,
+			    ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle));
+
+	asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE);
+
+	/* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */
+}
+
+/**
+ * asd_init_cseq_scratch -- setup and init CSEQ
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Setup and initialize Central sequencers. Initialiaze the mode
+ * independent and dependent scratch page to the default settings.
+ */
+static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha)
+{
+	asd_init_cseq_mip(asd_ha);
+	asd_init_cseq_mdp(asd_ha);
+}
+
+/**
+ * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq)
+{
+	int i;
+
+	/* LSEQ Mode independent page 0 setup. */
+	asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq);
+	asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq),
+			   ASD_NOTIFY_ENABLE_SPINUP);
+	asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000);
+	asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0);
+
+	/* LSEQ Mode independent page 1 setup. */
+	asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0);
+
+	/* LSEQ Mode Independent page 2 setup. */
+	asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0);
+	for (i = 0; i < 12; i += 4)
+		asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0);
+
+	/* LSEQ Mode Independent page 3 setup. */
+
+	/* Device present timer timeout */
+	asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq),
+			    ASD_DEV_PRESENT_TIMEOUT);
+
+	/* SATA interlock timer disabled */
+	asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq),
+			    ASD_SATA_INTERLOCK_TIMEOUT);
+
+	/* STP shutdown timer timeout constant, IGNORED by the sequencer,
+	 * always 0. */
+	asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq),
+			    ASD_STP_SHUTDOWN_TIMEOUT);
+
+	asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq),
+			    ASD_SRST_ASSERT_TIMEOUT);
+
+	asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq),
+			    ASD_RCV_FIS_TIMEOUT);
+
+	asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq),
+			    ASD_ONE_MILLISEC_TIMEOUT);
+
+	/* COM_INIT timer */
+	asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq),
+			    ASD_TEN_MILLISEC_TIMEOUT);
+
+	asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq),
+			    ASD_SMP_RCV_TIMEOUT);
+}
+
+/**
+ * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages.
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha,  int lseq)
+{
+	int    i;
+	u32    moffs;
+	static const u16 ret_addr[] = {
+		0xFFFF,		  /* mode 0 */
+		0xFFFF,		  /* mode 1 */
+		MODE2_TASK,	  /* mode 2 */
+		0,
+		0xFFFF,		  /* mode 4/5 */
+		0xFFFF,		  /* mode 4/5 */
+	};
+
+	/*
+	 * Mode 0,1,2 and 4/5 have common field on page 0 for the first
+	 * 14 bytes.
+	 */
+	for (i = 0; i < 3; i++) {
+		moffs = i * LSEQ_MODE_SCRATCH_SIZE;
+		asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs,
+				   ret_addr[i]);
+		asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0);
+		asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0);
+		asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF);
+		asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF);
+		asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0);
+		asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0);
+	}
+	/*
+	 *  Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3.
+	 */
+	asd_write_reg_word(asd_ha,
+			 LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET,
+			   ret_addr[5]);
+	asd_write_reg_word(asd_ha,
+			 LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+	asd_write_reg_word(asd_ha,
+			 LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+	asd_write_reg_word(asd_ha,
+			 LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+	asd_write_reg_word(asd_ha,
+			 LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+	asd_write_reg_byte(asd_ha,
+		         LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+	asd_write_reg_word(asd_ha,
+		         LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+
+	/* LSEQ Mode dependent 0, page 0 setup. */
+	asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq),
+			   (u16)asd_ha->hw_prof.max_ddbs);
+	asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq),
+			   (u16)last_scb_site_no+1);
+	asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq),
+			    (u16) LmM0INTEN_MASK & 0xFFFF0000 >> 16);
+	asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2,
+			    (u16) LmM0INTEN_MASK & 0xFFFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0);
+
+	/* LSEQ mode dependent, mode 1, page 0 setup. */
+	asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF);
+	asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0);
+
+	/* LSEQ Mode dependent mode 2, page 0 setup */
+	asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0);
+
+	/* LSEQ Mode dependent, mode 4/5, page 0 setup. */
+	asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0);
+	/*
+	 * Set the desired interval between transmissions of the NOTIFY
+	 * (ENABLE SPINUP) primitive.  Must be initilized to val - 1.
+	 */
+	asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq),
+			   ASD_NOTIFY_TIMEOUT - 1);
+	/* No delay for the first NOTIFY to be sent to the attached target. */
+	asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq),
+			   ASD_NOTIFY_DOWN_COUNT);
+
+	/* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */
+	for (i = 0; i < 2; i++)	{
+		int j;
+		/* Start from Page 1 of Mode 0 and 1. */
+		moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE;
+		/* All the fields of page 1 can be intialized to 0. */
+		for (j = 0; j < LSEQ_PAGE_SIZE; j += 4)
+			asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0);
+	}
+
+	/* LSEQ Mode dependent, mode 2, page 1 setup. */
+	asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0);
+
+	/* LSEQ Mode dependent, mode 4/5, page 1. */
+	for (i = 0; i < LSEQ_PAGE_SIZE; i+=4)
+		asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF);
+	asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF);
+	asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF);
+
+	/* LSEQ Mode dependent, mode 0, page 2 setup. */
+	asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0);
+	asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0);
+	asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0);
+
+	/* LSEQ Mode Dependent 1, page 2 setup. */
+	asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0);
+
+	/* LSEQ Mode Dependent 2, page 2 setup. */
+	/* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer,
+	 * i.e. always 0. */
+	asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0);
+	asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0);
+	asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0);
+
+	/* LSEQ Mode Dependent 4/5, page 2 setup. */
+	asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0);
+	asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq),	0);
+}
+
+/**
+ * asd_init_lseq_scratch -- setup and init link sequencers
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha)
+{
+	u8 lseq;
+	u8 lseq_mask;
+
+	lseq_mask = asd_ha->hw_prof.enabled_phys;
+	for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+		asd_init_lseq_mip(asd_ha, lseq);
+		asd_init_lseq_mdp(asd_ha, lseq);
+	}
+}
+
+/**
+ * asd_init_scb_sites -- initialize sequencer SCB sites (memory).
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This should be done before initializing common CSEQ and LSEQ
+ * scratch since those areas depend on some computed values here,
+ * last_scb_site_no, etc.
+ */
+static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
+{
+	u16	site_no;
+	u16     max_scbs = 0;
+
+	for (site_no = asd_ha->hw_prof.max_scbs-1;
+	     site_no != (u16) -1;
+	     site_no--) {
+		u16	i;
+
+		/* Initialize all fields in the SCB site to 0. */
+		for (i = 0; i < ASD_SCB_SIZE; i += 4)
+			asd_scbsite_write_dword(asd_ha, site_no, i, 0);
+
+		/* Workaround needed by SEQ to fix a SATA issue is to exclude
+		 * certain SCB sites from the free list. */
+		if (!SCB_SITE_VALID(site_no))
+			continue;
+
+		if (last_scb_site_no == 0)
+			last_scb_site_no = site_no;
+
+		/* For every SCB site, we need to initialize the
+		 * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS,
+		 * and SG Element Flag. */
+
+		/* Q_NEXT field of the last SCB is invalidated. */
+		asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no);
+
+		/* Initialize SCB Site Opcode field to invalid. */
+		asd_scbsite_write_byte(asd_ha, site_no,
+				       offsetof(struct scb_header, opcode),
+				       0xFF);
+
+		/* Initialize SCB Site Flags field to mean a response
+		 * frame has been received.  This means inadvertent
+		 * frames received to be dropped. */
+		asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
+
+		first_scb_site_no = site_no;
+		max_scbs++;
+	}
+	asd_ha->hw_prof.max_scbs = max_scbs;
+	ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs);
+	ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no);
+	ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no);
+}
+
+/**
+ * asd_init_cseq_cio - initialize CSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
+{
+	int i;
+
+	asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0);
+	asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS);
+	asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0);
+	asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0);
+	asd_ha->seq.scbpro = 0;
+	asd_write_reg_dword(asd_ha, SCBPRO, 0);
+	asd_write_reg_dword(asd_ha, CSEQCON, 0);
+
+	/* Intialize CSEQ Mode 11 Interrupt Vectors.
+	 * The addresses are 16 bit wide and in dword units.
+	 * The values of their macros are in byte units.
+	 * Thus we have to divide by 4. */
+	asd_write_reg_word(asd_ha, CM11INTVEC0, CSEQ_INT_VEC0);
+	asd_write_reg_word(asd_ha, CM11INTVEC1, CSEQ_INT_VEC1);
+	asd_write_reg_word(asd_ha, CM11INTVEC2, CSEQ_INT_VEC2);
+
+	/* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+	asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC);
+
+	/* Initialize CSEQ Scratch Page to 0x04. */
+	asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04);
+
+	/* Initialize CSEQ Mode[0-8] Dependent registers. */
+	/* Initialize Scratch Page to 0. */
+	for (i = 0; i < 9; i++)
+		asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0);
+
+	/* Reset the ARP2 Program Count. */
+	asd_write_reg_word(asd_ha, CPRGMCNT, CSEQ_IDLE_LOOP_ENTRY);
+
+	for (i = 0; i < 8; i++) {
+		/* Intialize Mode n Link m Interrupt Enable. */
+		asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF);
+		/* Initialize Mode n Request Mailbox. */
+		asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0);
+	}
+}
+
+/**
+ * asd_init_lseq_cio -- initialize LmSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq)
+{
+	u8  *sas_addr;
+	int  i;
+
+	/* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+	asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC);
+
+	asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0);
+
+	/* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */
+	for (i = 0; i < 3; i++)
+		asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0);
+
+	/* Initialize Mode 5 SCRATCHPAGE to 0. */
+	asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0);
+
+	asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0);
+	/* Initialize Mode 0,1,2 and 5 Interrupt Enable and
+	 * Interrupt registers. */
+	asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK);
+	asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF);
+	/* Mode 1 */
+	asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK);
+	asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF);
+	/* Mode 2 */
+	asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK);
+	asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF);
+	/* Mode 5 */
+	asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK);
+	asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF);
+
+	/* Enable HW Timer status. */
+	asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK);
+
+	/* Enable Primitive Status 0 and 1. */
+	asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK);
+	asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK);
+
+	/* Enable Frame Error. */
+	asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK);
+	asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50);
+
+	/* Initialize Mode 0 Transfer Level to 512. */
+	asd_write_reg_byte(asd_ha,  LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512);
+	/* Initialize Mode 1 Transfer Level to 256. */
+	asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256);
+
+	/* Initialize Program Count. */
+	asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), LSEQ_IDLE_LOOP_ENTRY);
+
+	/* Enable Blind SG Move. */
+	asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48);
+	asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq),
+			   ASD_SATA_INTERLOCK_TIMEOUT);
+
+	(void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq));
+
+	/* Clear Primitive Status 0 and 1. */
+	asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF);
+	asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF);
+
+	/* Clear HW Timer status. */
+	asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF);
+
+	/* Clear DMA Errors for Mode 0 and 1. */
+	asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF);
+	asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF);
+
+	/* Clear SG DMA Errors for Mode 0 and 1. */
+	asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF);
+	asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF);
+
+	/* Clear Mode 0 Buffer Parity Error. */
+	asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR);
+
+	/* Clear Mode 0 Frame Error register. */
+	asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF);
+
+	/* Reset LSEQ external interrupt arbiter. */
+	asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL);
+
+	/* Set the Phy SAS for the LmSEQ WWN. */
+	sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr;
+	for (i = 0; i < SAS_ADDR_SIZE; i++)
+		asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]);
+
+	/* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */
+	asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0);
+
+	/* Set the Bus Inactivity Time Limit Timer. */
+	asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9);
+
+	/* Enable SATA Port Multiplier. */
+	asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80);
+
+	/* Initialize Interrupt Vector[0-10] address in Mode 3.
+	 * See the comment on CSEQ_INT_* */
+	asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), LSEQ_INT_VEC0);
+	asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), LSEQ_INT_VEC1);
+	asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), LSEQ_INT_VEC2);
+	asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), LSEQ_INT_VEC3);
+	asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), LSEQ_INT_VEC4);
+	asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), LSEQ_INT_VEC5);
+	asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), LSEQ_INT_VEC6);
+	asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), LSEQ_INT_VEC7);
+	asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), LSEQ_INT_VEC8);
+	asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), LSEQ_INT_VEC9);
+	asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), LSEQ_INT_VEC10);
+	/*
+	 * Program the Link LED control, applicable only for
+	 * Chip Rev. B or later.
+	 */
+	asd_write_reg_dword(asd_ha, LmCONTROL(lseq),
+			    (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms));
+
+	/* Set the Align Rate for SAS and STP mode. */
+	asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT);
+	asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT);
+}
+
+
+/**
+ * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_post_init_cseq(struct asd_ha_struct *asd_ha)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF);
+	for (i = 0; i < 8; i++)
+		asd_read_reg_dword(asd_ha, CMnRSPMBX(i));
+	/* Reset the external interrupt arbiter. */
+	asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL);
+}
+
+/**
+ * asd_init_ddb_0 -- initialize DDB 0
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Initialize DDB site 0 which is used internally by the sequencer.
+ */
+static void asd_init_ddb_0(struct asd_ha_struct *asd_ha)
+{
+	int	i;
+
+	/* Zero out the DDB explicitly */
+	for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4)
+		asd_ddbsite_write_dword(asd_ha, 0, i, 0);
+
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail),
+			       asd_ha->hw_prof.max_ddbs-1);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0);
+	asd_ddbsite_write_word(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh),
+			       asd_ha->hw_prof.num_phys * 2);
+	asd_ddbsite_write_byte(asd_ha, 0,
+		 offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0);
+	asd_ddbsite_write_byte(asd_ha, 0,
+	       offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF);
+	asd_ddbsite_write_byte(asd_ha, 0,
+	       offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00);
+	/* DDB 0 is reserved */
+	set_bit(0, asd_ha->hw_prof.ddb_bitmap);
+}
+
+/**
+ * asd_seq_setup_seqs -- setup and initialize central and link sequencers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha)
+{
+	int 		lseq;
+	u8		lseq_mask;
+
+	/* Initialize SCB sites. Done first to compute some values which
+	 * the rest of the init code depends on. */
+	asd_init_scb_sites(asd_ha);
+
+	/* Initialize CSEQ Scratch RAM registers. */
+	asd_init_cseq_scratch(asd_ha);
+
+	/* Initialize LmSEQ Scratch RAM registers. */
+	asd_init_lseq_scratch(asd_ha);
+
+	/* Initialize CSEQ CIO registers. */
+	asd_init_cseq_cio(asd_ha);
+
+	asd_init_ddb_0(asd_ha);
+
+	/* Initialize LmSEQ CIO registers. */
+	lseq_mask = asd_ha->hw_prof.enabled_phys;
+	for_each_sequencer(lseq_mask, lseq_mask, lseq)
+		asd_init_lseq_cio(asd_ha, lseq);
+	asd_post_init_cseq(asd_ha);
+}
+
+
+/**
+ * asd_seq_start_cseq -- start the central sequencer, CSEQ
+ * @asd_ha: pointer to host adapter structure
+ */
+static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha)
+{
+	/* Reset the ARP2 instruction to location zero. */
+	asd_write_reg_word(asd_ha, CPRGMCNT, CSEQ_IDLE_LOOP_ENTRY);
+
+	/* Unpause the CSEQ  */
+	return asd_unpause_cseq(asd_ha);
+}
+
+/**
+ * asd_seq_start_lseq -- start a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: the link sequencer of interest
+ */
+static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+	/* Reset the ARP2 instruction to location zero. */
+	asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), LSEQ_IDLE_LOOP_ENTRY);
+
+	/* Unpause the LmSEQ  */
+	return asd_seq_unpause_lseq(asd_ha, lseq);
+}
+
+int asd_init_seqs(struct asd_ha_struct *asd_ha)
+{
+	int err;
+
+	asd_printk("using sequencer %s\n", SAS_RAZOR_SEQUENCER_VERSION);
+	err = asd_seq_download_seqs(asd_ha);
+	if (err) {
+		asd_printk("couldn't download sequencers for %s\n",
+			   pci_name(asd_ha->pcidev));
+		return err;
+	}
+
+	asd_seq_setup_seqs(asd_ha);
+
+	return 0;
+}
+
+int asd_start_seqs(struct asd_ha_struct *asd_ha)
+{
+	int err;
+	u8  lseq_mask;
+	int lseq;
+
+	err = asd_seq_start_cseq(asd_ha);
+	if (err) {
+		asd_printk("couldn't start CSEQ for %s\n",
+			   pci_name(asd_ha->pcidev));
+		return err;
+	}
+
+	lseq_mask = asd_ha->hw_prof.enabled_phys;
+	for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+		err = asd_seq_start_lseq(asd_ha, lseq);
+		if (err) {
+			asd_printk("coudln't start LSEQ %d for %s\n", lseq,
+				   pci_name(asd_ha->pcidev));
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * asd_update_port_links -- update port_map_by_links and phy_is_up
+ * @sas_phy: pointer to the phy which has been added to a port
+ *
+ * 1) When a link reset has completed and we got BYTES DMAED with a
+ * valid frame we call this function for that phy, to indicate that
+ * the phy is up, i.e. we update the phy_is_up in DDB 0.  The
+ * sequencer checks phy_is_up when pending SCBs are to be sent, and
+ * when an open address frame has been received.
+ *
+ * 2) When we know of ports, we call this function to update the map
+ * of phys participaing in that port, i.e. we update the
+ * port_map_by_links in DDB 0.  When a HARD_RESET primitive has been
+ * received, the sequencer disables all phys in that port.
+ * port_map_by_links is also used as the conn_mask byte in the
+ * initiator/target port DDB.
+ */
+void asd_update_port_links(struct sas_phy *sas_phy)
+{
+	struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
+	const u8 phy_mask = (u8) sas_phy->port->phy_mask;
+	u8  phy_is_up;
+	u8  mask;
+	int i, err;
+
+	for_each_phy(phy_mask, mask, i)
+		asd_ddbsite_write_byte(asd_ha, 0,
+				       offsetof(struct asd_ddb_seq_shared,
+						port_map_by_links)+i,phy_mask);
+
+	for (i = 0; i < 12; i++) {
+		phy_is_up = asd_ddbsite_read_byte(asd_ha, 0,
+			  offsetof(struct asd_ddb_seq_shared, phy_is_up));
+		err = asd_ddbsite_update_byte(asd_ha, 0,
+				offsetof(struct asd_ddb_seq_shared, phy_is_up),
+				phy_is_up,
+				phy_is_up | phy_mask);
+		if (!err)
+			break;
+		else if (err == -EFAULT) {
+			asd_printk("phy_is_up: parity error in DDB 0\n");
+			break;
+		}
+	}
+
+	if (err)
+		asd_printk("couldn't update DDB 0:error:%d\n", err);
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_seq.h newtree/drivers/scsi/aic94xx/aic94xx_seq.h
--- oldtree/drivers/scsi/aic94xx/aic94xx_seq.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_seq.h	2006-04-01 05:35:45.911489250 -0500
@@ -0,0 +1,40 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_seq.h#7 $
+ */
+
+#ifndef _AIC94XX_SEQ_H_
+#define _AIC94XX_SEQ_H_
+
+int asd_pause_cseq(struct asd_ha_struct *asd_ha);
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha);
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+int asd_init_seqs(struct asd_ha_struct *asd_ha);
+int asd_start_seqs(struct asd_ha_struct *asd_ha);
+
+void asd_update_port_links(struct sas_phy *phy);
+
+#endif
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_seq_microcode.c newtree/drivers/scsi/aic94xx/aic94xx_seq_microcode.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_seq_microcode.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_seq_microcode.c	2006-04-01 05:35:45.915489500 -0500
@@ -0,0 +1,1469 @@
+/*
+ * Aic94xx SAS/SATA driver central and link sequencer code for AIC-94xx
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_seq_microcode.c#24 $
+ *
+ * Compile options: RAZOR BYPASS_OOB SATA_II_NCQ TARGET_MODE CONCURR_CONNECTION
+ */
+
+/*
+ * Those are offsets in byte units.  Addresses in sequencer are in
+ * dword units, so those values will have to be divided by 4 before
+ * being written out to the sequencer.
+ */
+#define CSEQ_IDLE_LOOP_ENTRY	(0x0000/4)
+#define CSEQ_INT_VEC0		(0x0858/4)
+#define CSEQ_INT_VEC1		(0x00E8/4)
+#define CSEQ_INT_VEC2		(0x00EC/4)
+
+#define LSEQ_IDLE_LOOP_ENTRY	(0x0000/4)
+#define LSEQ_INT_VEC0		(0x012C/4)
+#define LSEQ_INT_VEC1		(0x163C/4)
+#define LSEQ_INT_VEC2		(0x0350/4)
+#define LSEQ_INT_VEC3		(0x0380/4)
+#define LSEQ_INT_VEC4		(0x1624/4)
+#define LSEQ_INT_VEC5		(0x27C8/4)
+#define LSEQ_INT_VEC6		(0x28CC/4)
+#define LSEQ_INT_VEC7		(0x011C/4)
+#define LSEQ_INT_VEC8		(0x1594/4)
+#define LSEQ_INT_VEC9		(0x1880/4)
+#define LSEQ_INT_VEC10		(0x004C/4)
+
+#define MODE2_TASK              (0x1000/4)
+
+#define SAS_RAZOR_SEQUENCER_VERSION "Razor_10a1"
+
+static const u8 Cseq[] = {
+0x04,0x10,0x88,0xB3,0x88,0x11,0x00,0x80,0x06,0x11,0x48,0x80,0x01,0xC7,0x5F,0x68,
+0xFD,0x05,0x0A,0x88,0x07,0x11,0x48,0x00,0x00,0x00,0x14,0x38,0x02,0x05,0x0A,0x00,
+0x8A,0xD4,0x17,0x28,0xFF,0xD1,0x17,0x70,0x00,0x0C,0xDC,0x5A,0xFD,0x05,0x0A,0x88,
+0x05,0x11,0x48,0x80,0x00,0x00,0x14,0x38,0x02,0x05,0x0A,0x00,0x8A,0xD4,0x25,0xA8,
+0xFF,0xD1,0x25,0xF0,0x00,0x0C,0xDC,0x5A,0xFD,0x05,0x0A,0x88,0x04,0x11,0x48,0x00,
+0xFF,0xC1,0x2D,0xF0,0x00,0x0C,0x2C,0xDB,0xFF,0xC9,0x31,0xF0,0x00,0x0C,0x34,0xDB,
+0x06,0x11,0x48,0x80,0xFF,0xD1,0x37,0xF0,0x00,0x0C,0x94,0xDE,0x04,0x11,0x48,0x00,
+0xFF,0xDC,0x3D,0xF8,0x00,0x0C,0xF2,0xDB,0x02,0x05,0x0A,0x00,0x80,0xE1,0x45,0x68,
+0x02,0xE2,0x41,0x30,0x02,0xE0,0x0D,0xB4,0x01,0x35,0xB0,0xE9,0xFF,0xCD,0xFD,0xE0,
+0xFF,0xC5,0x7B,0xE0,0xFF,0xD1,0x69,0x61,0x00,0x0C,0x02,0xC0,0x06,0x11,0x48,0x80,
+0x01,0x00,0x8C,0xB3,0x02,0x20,0x88,0xB3,0x04,0x06,0x80,0xB3,0x01,0xC7,0x8F,0x03,
+0x04,0x11,0x48,0x00,0x88,0x11,0x00,0x80,0x00,0x0C,0x3E,0xC0,0xFE,0xC7,0x8F,0x8B,
+0x01,0xC6,0x01,0xB0,0x02,0xC4,0x41,0xB0,0x02,0xC2,0x0D,0x30,0x02,0xC0,0x0D,0xB0,
+0x07,0x11,0x48,0x84,0x02,0x20,0xC4,0x33,0x02,0x06,0xC0,0x33,0x02,0xE0,0x0D,0xB4,
+0x80,0xE1,0xC3,0x03,0x00,0x0C,0x02,0xC0,0x01,0x11,0x2A,0x80,0x02,0x11,0x2A,0x80,
+0x01,0x05,0x0A,0x84,0x80,0x00,0x1C,0x38,0x02,0xC4,0x41,0xB0,0x02,0x08,0x27,0xB0,
+0x01,0x0A,0x15,0xB0,0xC0,0x0A,0x86,0xF0,0xD0,0x0A,0xA6,0x60,0x00,0x04,0x27,0x00,
+0x44,0x04,0x19,0xA8,0x01,0x11,0x1A,0x80,0x01,0x12,0x08,0x32,0x01,0x0C,0x18,0x18,
+0x04,0x12,0x26,0xB0,0x01,0x0C,0x19,0x1A,0x01,0x0C,0x15,0xB0,0x00,0x0B,0xA1,0xE0,
+0x5A,0x00,0x0C,0x38,0xD0,0x0A,0x9F,0xF0,0x07,0x11,0x94,0xC4,0x05,0x11,0x94,0x44,
+0xFF,0x04,0xBF,0x68,0x02,0x00,0x41,0x30,0x00,0x0C,0xBE,0x40,0x01,0x4D,0x15,0xB0,
+0x01,0x0A,0x26,0xB0,0x04,0x3C,0xB1,0x33,0xFF,0x0A,0xB2,0x68,0x02,0x30,0xB0,0xB3,
+0x00,0x00,0xB4,0x3B,0x04,0xD8,0x27,0x30,0x02,0x00,0x0D,0xB0,0x02,0x0E,0x0C,0xB0,
+0xB1,0x00,0xAC,0xA8,0x02,0x06,0x1C,0xB0,0x02,0x06,0x40,0xB0,0x02,0x11,0x4A,0x80,
+0x01,0xF4,0x27,0xB0,0x00,0x11,0x4A,0x88,0x01,0x4E,0x22,0x30,0xFF,0x21,0xCC,0x70,
+0xFF,0x0E,0xCC,0x78,0x10,0x4D,0x7E,0x78,0x02,0x20,0x88,0xB3,0xFF,0x21,0xD2,0xE0,
+0xFF,0xFF,0x8C,0xBB,0x02,0x11,0x4A,0x80,0x04,0xF0,0x81,0x30,0x04,0xEC,0x89,0x30,
+0x03,0xE8,0x15,0x88,0x44,0x0A,0x14,0xA8,0x00,0x11,0x4A,0x88,0x80,0x0E,0x90,0x98,
+0xFF,0x0A,0x96,0x08,0x1C,0x11,0x6E,0x80,0x00,0x0C,0x6A,0x58,0x40,0x35,0x02,0xF8,
+0x40,0x11,0x6A,0x00,0x04,0x11,0x68,0x80,0x02,0x11,0x4A,0x80,0x04,0x40,0xE0,0x33,
+0x10,0x4D,0xF8,0xF8,0x04,0xE8,0xE1,0x33,0xFC,0xF0,0xE1,0x0B,0x01,0xF4,0xE9,0x93,
+0x00,0x11,0x4A,0x88,0x00,0x0C,0x70,0xC0,0x07,0x11,0x48,0x00,0xFF,0xD1,0x03,0x70,
+0xB1,0x00,0x80,0x28,0xFF,0x0E,0xFE,0x68,0x04,0x11,0x48,0x00,0x02,0x20,0xC8,0x33,
+0x80,0x00,0x1C,0x38,0x02,0xCC,0x41,0x30,0x17,0x4D,0x17,0xF1,0x0C,0x4D,0x1B,0xF1,
+0x0B,0x4D,0x1B,0x71,0x0A,0x4D,0x2D,0xF1,0x1C,0x11,0x2A,0x80,0x30,0x50,0x27,0xB0,
+0x00,0x0C,0x2E,0xC1,0x04,0x0C,0x27,0x30,0x00,0x00,0x26,0xB8,0x14,0x00,0x26,0xB8,
+0x08,0x11,0x26,0xB0,0x14,0x10,0x27,0x30,0x0C,0x28,0x27,0xB0,0x02,0x46,0x45,0x30,
+0x04,0xB0,0x27,0xB0,0x00,0x0C,0x2E,0xC1,0x10,0x10,0x27,0xB0,0x02,0xE4,0x41,0x30,
+0x44,0x0C,0x18,0xA8,0x01,0x11,0x1A,0x80,0x01,0x0C,0xD2,0x33,0x80,0xFF,0x14,0xB8,
+0x83,0x0E,0x14,0xA8,0xB1,0x00,0x52,0xA9,0x00,0x11,0xD0,0x8B,0x80,0xE8,0xD1,0x2B,
+0x08,0x12,0x80,0xB0,0x01,0x0A,0x90,0x30,0x07,0x0C,0x18,0x18,0x30,0x12,0x14,0x08,
+0xFF,0x0A,0x96,0x08,0x1C,0x11,0x6E,0x80,0x02,0x08,0xCD,0x33,0x00,0x0C,0x8A,0x5C,
+0x02,0xCC,0x41,0x30,0x02,0xE6,0x79,0xB2,0x02,0xE8,0x7D,0xB2,0x00,0x0C,0x6A,0x58,
+0x40,0x35,0x02,0xF8,0x40,0x11,0x6A,0x00,0xFF,0xFF,0xB0,0xBB,0x01,0x11,0x1A,0x80,
+0xCC,0x11,0x54,0x5F,0x00,0x0C,0x58,0x5F,0xFF,0xCD,0xFD,0xE0,0x00,0x0C,0x70,0xC0,
+0x02,0xD0,0x41,0xB0,0x02,0x0C,0x19,0xB0,0x80,0x00,0x14,0xB8,0xB1,0x00,0xDA,0x2E,
+0x80,0x0F,0x76,0xE9,0x80,0x00,0xFC,0x3A,0x00,0x0C,0x78,0xC1,0x02,0x0C,0xFD,0x32,
+0x08,0x10,0x81,0xB0,0x08,0x18,0x97,0x80,0x01,0x7E,0x91,0xB0,0x1C,0x11,0x6E,0x80,
+0x00,0x0C,0x6A,0x58,0x40,0x35,0x02,0xF8,0x40,0x11,0x6A,0x00,0x08,0x40,0x20,0xB2,
+0x08,0x50,0x81,0x30,0xFF,0x58,0x97,0x08,0x01,0x7E,0x91,0xB0,0x1C,0x11,0x6E,0x80,
+0x00,0x0C,0x6A,0x58,0x40,0x35,0x02,0xF8,0x40,0x11,0x6A,0x00,0x08,0x40,0xA0,0x32,
+0x02,0x7E,0x15,0xB0,0x82,0x10,0x14,0x28,0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,
+0x83,0x0C,0x19,0x2A,0x02,0x0C,0x15,0xB0,0x89,0x10,0x6A,0x29,0xFF,0xFF,0xB0,0xBB,
+0x01,0x11,0x1A,0x80,0xD0,0x11,0x54,0xDF,0x00,0x11,0x5A,0xDF,0x00,0x0C,0x70,0xC0,
+0x00,0x0C,0xD8,0xD9,0x01,0x11,0x6A,0x00,0x02,0x11,0x4A,0x80,0xFC,0xE0,0x81,0x88,
+0x07,0xE1,0x83,0xB0,0x03,0xE0,0x15,0x08,0x44,0x0A,0x14,0xA8,0x00,0x11,0x4A,0x88,
+0x80,0x11,0x90,0x00,0x08,0x0A,0x96,0x00,0x1C,0x11,0x6E,0x80,0x01,0x00,0x14,0xB8,
+0x83,0x30,0x60,0x28,0x00,0x0C,0x6A,0x58,0x40,0x35,0x02,0xF8,0x40,0x11,0x6A,0x00,
+0x80,0x80,0x00,0x32,0x00,0x0C,0xEC,0x59,0x88,0x11,0x00,0x80,0x00,0x0C,0x70,0xC0,
+0x06,0x11,0x48,0x80,0xD6,0x01,0x18,0x38,0xFF,0xD7,0xE3,0xE1,0xDA,0x01,0x18,0x38,
+0xFF,0xDB,0xEB,0xF1,0x02,0x0C,0x1C,0xB0,0x02,0x12,0x40,0xB0,0x02,0x00,0x27,0x30,
+0x04,0x11,0x48,0x9C,0x14,0x11,0x2A,0x00,0x02,0x11,0x4A,0x80,0x08,0x00,0xC1,0xB3,
+0x00,0x11,0x4A,0x88,0xC0,0x0A,0x15,0x88,0xFF,0x0A,0x0A,0x7A,0x40,0x0A,0x46,0xF2,
+0x80,0x0A,0x6E,0xF2,0x01,0x0A,0x15,0xB0,0xC0,0x0A,0x8E,0xF2,0xC3,0x0A,0xC4,0x72,
+0xC4,0x0A,0x08,0xF2,0xC6,0x0A,0xC6,0xF2,0xD0,0x0A,0x90,0x72,0x15,0x11,0x2A,0x80,
+0xA1,0x00,0x20,0xAB,0x10,0x0B,0x2D,0x7A,0x16,0x10,0x2D,0x62,0x08,0x48,0x1B,0xFA,
+0x02,0x46,0x45,0x30,0x08,0x9F,0x3F,0x03,0x02,0x52,0x21,0xB3,0x80,0xBF,0x1B,0x7A,
+0x00,0x0C,0x10,0x5F,0x03,0x0A,0x1F,0xE2,0xA1,0x00,0xE2,0xAA,0x08,0x0A,0x2D,0x72,
+0x04,0x48,0x2D,0xFA,0xB1,0x00,0xF8,0x2E,0x00,0x0C,0x5A,0x4F,0x02,0x20,0x0C,0xB0,
+0x00,0x0C,0xCC,0xDF,0x02,0x06,0x40,0xB0,0xB1,0x00,0xBA,0xA9,0xB1,0x00,0xC0,0xA8,
+0x00,0x0C,0x58,0xCF,0x02,0x46,0x45,0x30,0x01,0x00,0x14,0xB8,0x83,0xAC,0x59,0x2B,
+0x0F,0x0A,0xBB,0x76,0x02,0xA0,0xAD,0xB3,0x02,0x20,0x40,0x33,0xFF,0xFF,0x04,0x3A,
+0xFF,0xD7,0x45,0x72,0xA1,0x00,0xA4,0x2F,0xC1,0x11,0x52,0xC7,0xB1,0x00,0xBA,0xA9,
+0xB1,0x00,0xC0,0xA8,0x80,0x0B,0x59,0x7A,0x00,0x11,0x18,0x08,0xB0,0x00,0x60,0xAF,
+0x04,0x0C,0x81,0xB2,0x02,0x46,0x45,0x30,0x01,0x00,0x14,0xB8,0x83,0xAC,0x59,0x2B,
+0x00,0x04,0x18,0xB8,0xB1,0x00,0x72,0x29,0xFF,0xFF,0x08,0x3A,0x02,0x46,0x45,0x30,
+0x02,0xA2,0xAD,0x33,0x02,0x20,0x44,0xB3,0xFF,0xD7,0x69,0xF2,0xA1,0x00,0xAC,0xAF,
+0xFF,0x8E,0x6D,0x6A,0xC9,0x11,0x52,0x47,0x02,0x20,0x18,0x37,0x02,0x20,0x0C,0xB0,
+0x44,0x0B,0x15,0xA8,0x00,0x0B,0x01,0x80,0x02,0x06,0x40,0xB0,0xFF,0xFF,0x00,0xBA,
+0xFF,0xE5,0x83,0x62,0xFF,0xE7,0x85,0xE2,0x02,0x20,0xC8,0x33,0x02,0x20,0xCC,0xB3,
+0xA1,0x00,0xA6,0x28,0xFF,0xE7,0x8D,0xF2,0x02,0xE6,0xA9,0xB3,0x02,0x20,0xCC,0xB3,
+0x02,0xD4,0x41,0x30,0x02,0xE6,0x01,0x36,0x1B,0x11,0x2A,0x00,0x07,0x11,0x9A,0x42,
+0x00,0x00,0x44,0x38,0x00,0x11,0x16,0x88,0x01,0x0B,0x15,0x30,0x83,0x8E,0x1D,0x2B,
+0x05,0x11,0x9A,0xC2,0x01,0x0C,0x48,0x30,0x00,0x11,0x08,0x0A,0x00,0x11,0x0A,0x8A,
+0x00,0x11,0x18,0x8A,0xFF,0xFF,0x04,0x3A,0xFF,0xFF,0x00,0xBA,0xFF,0xD1,0xB1,0x62,
+0x02,0x20,0xA0,0xB3,0x02,0x20,0xA4,0x33,0x01,0x11,0xB0,0x83,0x00,0x0C,0xB8,0xC2,
+0x02,0x20,0x14,0xB0,0x02,0xD2,0x41,0x30,0x02,0x0A,0x04,0x32,0x02,0x0A,0xA4,0xB3,
+0x06,0x11,0x48,0x80,0x01,0xC7,0x15,0x30,0x04,0x11,0x48,0x00,0x01,0x0A,0x1E,0xED,
+0x01,0x0C,0x48,0x30,0x00,0x0C,0x1E,0x43,0xD1,0x11,0x52,0x47,0x02,0x46,0x45,0x30,
+0xB1,0x00,0xF8,0x2E,0x00,0x0C,0x5A,0x4F,0xFD,0x0B,0xD9,0xE2,0xFD,0x8F,0xD9,0xE2,
+0x04,0x9F,0xDB,0x6A,0x04,0x9F,0x3F,0x03,0x02,0x20,0x60,0xB3,0xA1,0x00,0x08,0x2F,
+0x2A,0x11,0x5A,0x47,0x2B,0x11,0x5A,0xC7,0xC0,0x01,0x18,0xB8,0x01,0xD6,0x15,0x30,
+0x00,0x0C,0x18,0x98,0x01,0x12,0x00,0x30,0xC8,0x01,0x18,0x38,0x0F,0x00,0x14,0x08,
+0x00,0x0C,0x18,0x98,0x02,0x0C,0x1C,0xB0,0xFF,0x12,0x2A,0x7B,0xFF,0x0C,0x18,0x98,
+0x02,0x0C,0x0C,0x30,0x02,0x0E,0x0C,0xB0,0xB1,0x00,0x80,0x28,0xFF,0x0E,0xFE,0x7A,
+0xFF,0xD1,0xF5,0x62,0x04,0x06,0x22,0x30,0x00,0x0C,0x26,0xC3,0x01,0x0C,0xC0,0x33,
+0x02,0x06,0x1C,0xB0,0x02,0x06,0x18,0x30,0xFF,0xFF,0x14,0x38,0x83,0xD4,0xA9,0x2B,
+0xFF,0x12,0x26,0x18,0x01,0xD6,0xAD,0x1B,0x07,0xD6,0xAD,0x8B,0xFF,0x0C,0x18,0x98,
+0xFF,0x12,0x1C,0x7B,0xC0,0x01,0x1C,0x38,0x01,0xD7,0x15,0xB0,0x00,0x0E,0x1C,0x98,
+0x01,0x00,0x26,0xB0,0x07,0x0E,0xAE,0x8B,0x00,0xE0,0x57,0xDF,0x02,0x05,0x0A,0x00,
+0x00,0x00,0x14,0x38,0x8A,0xD4,0x27,0x2B,0xFF,0xD1,0xDD,0x62,0x04,0x11,0x48,0x00,
+0x88,0x11,0x00,0x04,0x25,0x11,0x2A,0x80,0xC0,0x11,0x3C,0x5B,0x00,0x0C,0x5E,0xCF,
+0x00,0x11,0x56,0xDF,0x88,0x11,0x00,0x04,0xC8,0x11,0x3C,0xDB,0x00,0x0C,0x5E,0xCF,
+0x01,0x11,0x56,0x5F,0x88,0x11,0x00,0x04,0x01,0x11,0x1A,0x80,0x02,0x05,0x0A,0x00,
+0xFF,0xFF,0xB0,0xBB,0x02,0x12,0x40,0xB0,0xFE,0x0C,0x18,0x18,0x02,0x0C,0x0C,0x30,
+0x02,0x46,0x45,0x30,0x01,0x9D,0x5B,0x7B,0x20,0x0B,0x5D,0x7B,0x02,0x9E,0x5D,0x7B,
+0x04,0x4C,0x5D,0xEB,0x04,0x49,0x5D,0xEB,0x20,0x9D,0xDD,0x6B,0xB1,0x00,0xCE,0x2E,
+0x00,0x0C,0xDC,0x4B,0x40,0x9E,0xDD,0x6B,0x01,0x9C,0x15,0xB0,0x02,0x22,0x0C,0x30,
+0x00,0x00,0x44,0x38,0x00,0xAF,0x15,0x88,0x02,0x06,0x44,0x30,0xFF,0x0A,0x70,0xEB,
+0x80,0xBF,0xDD,0x6B,0x09,0x11,0x6E,0x03,0x00,0x0C,0x10,0x5F,0x00,0x0C,0xE0,0xC3,
+0x80,0xBF,0x7F,0x7B,0x09,0xB7,0x77,0xE3,0x00,0x11,0x7E,0x0B,0x02,0x0A,0x0C,0x30,
+0x00,0x0C,0x38,0x5F,0x02,0x06,0x14,0x30,0x00,0x0C,0xEA,0x4B,0x02,0x22,0x0C,0x30,
+0x00,0x00,0x44,0x38,0x00,0xAE,0xC1,0x08,0x02,0x06,0x44,0x30,0x02,0x62,0x14,0xB0,
+0x01,0x0B,0xE0,0xEB,0xFF,0x0A,0xE0,0xF3,0x04,0x9D,0xA3,0xFB,0x02,0x0A,0x0C,0x30,
+0x00,0x11,0x12,0xDC,0x04,0x11,0x14,0x30,0x01,0xA8,0x19,0x30,0x01,0xA9,0x15,0xB0,
+0xB1,0x00,0xDA,0x2E,0x02,0x06,0x14,0x30,0x80,0x0F,0xA2,0xFB,0x01,0x11,0x12,0x5C,
+0x00,0x0C,0xE0,0xC3,0x02,0x06,0x18,0x30,0x02,0x20,0x0C,0xB0,0x02,0x22,0x0C,0x30,
+0x01,0x0A,0x00,0x30,0x02,0x06,0x44,0x30,0x02,0x06,0x40,0xB0,0x00,0x0C,0x54,0x5F,
+0x04,0x4C,0xC1,0x7B,0xFF,0x03,0xC1,0xF3,0x02,0x20,0x0C,0xB0,0x02,0x02,0x41,0xB0,
+0x01,0x0C,0x18,0x18,0x00,0x0C,0x52,0x5F,0x02,0x06,0x40,0xB0,0xFF,0xFF,0x04,0x3A,
+0x04,0x9D,0xDB,0xFB,0xC0,0x0C,0xDA,0xF3,0xFF,0xAA,0xDB,0xFB,0x02,0x20,0x0C,0xB0,
+0x01,0x11,0x14,0x00,0x00,0xAA,0xD1,0xE3,0xB1,0x00,0x60,0x2F,0x00,0x0C,0xD8,0x43,
+0xB1,0x00,0x5A,0x2F,0xFF,0x21,0xD8,0x73,0x01,0x0A,0x14,0x18,0x00,0x0C,0xCA,0x43,
+0x02,0x06,0x40,0xB0,0x01,0x11,0x22,0x9C,0x00,0x0C,0x38,0x5F,0x00,0x0C,0xEA,0x4B,
+0x02,0x06,0x18,0x30,0xFF,0x01,0xF1,0x73,0x02,0x20,0xB0,0x33,0x02,0x00,0x41,0x30,
+0x00,0x0C,0x46,0xC3,0x02,0x06,0x18,0x30,0xB1,0x00,0xD6,0xA9,0xFF,0x21,0x46,0x63,
+0x01,0x10,0x22,0x1C,0x00,0x11,0x00,0x08,0x02,0x05,0x0A,0x00,0xFF,0xE5,0x09,0x74,
+0x02,0xE4,0x41,0x30,0xFF,0xFF,0xC8,0xBB,0x01,0x00,0x0E,0xB0,0xFF,0x07,0x14,0x90,
+0x00,0xDC,0xB9,0x0B,0x0A,0x11,0x56,0xDF,0x02,0x05,0x0A,0x00,0xFF,0xDC,0x0F,0xFC,
+0x11,0x00,0x00,0x98,0x01,0x00,0x14,0x30,0x00,0xDD,0xF7,0x63,0xFD,0x05,0x0A,0x88,
+0x88,0x11,0x00,0x04,0x02,0xA8,0x15,0x30,0x01,0x0A,0x04,0xB0,0x01,0x0B,0x06,0x98,
+0xFF,0x0C,0x1C,0xFC,0xFF,0x0B,0x06,0x18,0xE0,0xA8,0x21,0x2C,0xFF,0x11,0x22,0x8C,
+0x02,0xA8,0x51,0x33,0x00,0x0C,0x12,0xC4,0x04,0x9D,0xCB,0xFF,0x00,0x0C,0x5C,0xDF,
+0xFF,0x21,0xCA,0xF7,0x01,0x10,0x22,0x1C,0x3C,0x00,0x0C,0x38,0x02,0x34,0xA8,0x33,
+0x02,0x36,0x40,0xB0,0xF8,0xD4,0x15,0x08,0xC0,0x0A,0x72,0xF4,0xD0,0x0A,0x72,0x74,
+0x01,0xD4,0x15,0xB0,0x00,0x11,0x16,0x88,0x20,0x02,0x18,0x38,0x83,0x0C,0x0C,0xAC,
+0x00,0x0C,0x7E,0x45,0x00,0x0C,0x86,0xC5,0x00,0x0C,0x92,0xC5,0x00,0x0C,0x9E,0xC5,
+0x00,0x0C,0xA8,0x44,0x00,0x0C,0x24,0x45,0x00,0x0C,0x9E,0x44,0x00,0x0C,0x20,0xC5,
+0x00,0x0C,0xB8,0x45,0x00,0x0C,0xCC,0x45,0x00,0x0C,0xE2,0x45,0x00,0x0C,0xD8,0xC4,
+0x00,0x0C,0x54,0xC5,0x00,0x0C,0x8C,0xC5,0x00,0x0C,0x50,0x45,0x00,0x0C,0xA6,0x45,
+0x00,0x0C,0x46,0xC5,0x00,0x0C,0xD4,0x45,0x00,0x0C,0xDE,0x45,0x00,0x0C,0xE6,0xC5,
+0x00,0x0C,0x58,0x47,0x00,0x0C,0xC8,0xC6,0x00,0x0C,0x5C,0x46,0x00,0x0C,0xE8,0x45,
+0x00,0x0C,0xB6,0xC6,0x07,0xD4,0x8B,0xFC,0x01,0x05,0xAD,0xB3,0x07,0xD4,0x0B,0x8A,
+0x44,0x05,0x1D,0xA8,0x01,0x11,0x1E,0x00,0x00,0x11,0x26,0x88,0xFF,0x04,0x87,0xFC,
+0x44,0xD6,0x1D,0x28,0x01,0x11,0x1E,0x00,0x01,0x05,0x27,0xB4,0x01,0x05,0x09,0xB2,
+0xC5,0x11,0x52,0x47,0x01,0x0C,0x19,0x1A,0x01,0x0C,0x15,0xB0,0x00,0x0B,0x1F,0xE5,
+0x07,0x11,0x94,0xDC,0xA1,0x00,0xAC,0x28,0x01,0x0C,0x48,0x30,0x02,0xD0,0x15,0x30,
+0x88,0x20,0x9C,0xAC,0xB1,0x00,0x9C,0xA8,0x04,0x11,0x48,0x84,0x80,0x0B,0xA3,0x7C,
+0x00,0x0C,0x24,0x5E,0xFF,0xFF,0x04,0x3A,0x00,0x0C,0x46,0xDD,0xA1,0x00,0xA0,0xAF,
+0x80,0x0B,0xAD,0xFC,0x00,0x0C,0x24,0x5E,0x00,0x0C,0x46,0xDD,0x02,0x20,0x0C,0xB0,
+0x02,0x46,0x45,0x30,0x02,0x02,0x0D,0x30,0xFF,0xFF,0x04,0x3A,0x02,0x06,0x40,0xB0,
+0xFF,0xFF,0x40,0xBB,0xFF,0x21,0xD6,0x74,0x02,0x02,0xB1,0xB3,0x40,0x49,0xC5,0x7C,
+0x00,0x0C,0xAA,0x5D,0x00,0x0C,0xD2,0xC4,0x02,0xA0,0xAD,0xB3,0x02,0x20,0x40,0x33,
+0xFF,0xFF,0x04,0x3A,0xFF,0xD7,0xD1,0xF4,0xB1,0x00,0xA4,0xAF,0x00,0x0C,0xD2,0xC4,
+0xC1,0x11,0x52,0xDF,0x02,0xD8,0x41,0x30,0xFF,0x21,0xBC,0xE4,0xA1,0x00,0x9E,0x2F,
+0x02,0x46,0x45,0x30,0x02,0x06,0xB1,0x33,0xFF,0xFF,0x0C,0xBA,0x40,0x49,0x19,0xED,
+0x04,0x4C,0x0F,0xFD,0xB1,0x00,0xA0,0x2F,0xFF,0xA1,0xEB,0xE4,0xC1,0x11,0x52,0xDF,
+0x00,0x0C,0x1A,0xC5,0x02,0x20,0xA8,0x33,0xC0,0x11,0x5C,0xDF,0xFF,0x21,0xF2,0xE4,
+0x23,0x11,0x2A,0x80,0x02,0x20,0x14,0xB0,0xFF,0xD7,0xFD,0x74,0x02,0xD6,0x41,0xB0,
+0x02,0xD4,0x01,0x32,0x00,0x0C,0xFE,0x44,0x02,0xD4,0x81,0x33,0x02,0x0A,0x40,0xB0,
+0x02,0x00,0xAD,0xB3,0x02,0xD4,0x41,0x30,0x02,0x0A,0x04,0x32,0x02,0xD6,0x01,0xB2,
+0xFF,0xD7,0x1B,0xE5,0x02,0x20,0x84,0xB3,0x00,0x0C,0x1A,0xC5,0x80,0x49,0x15,0xED,
+0x00,0x0C,0x58,0x5A,0x00,0x0C,0x1A,0xC5,0xB1,0x00,0xC8,0xA9,0x00,0x0C,0x1A,0xC5,
+0x00,0x0C,0xAA,0x5D,0x02,0xD8,0x41,0x30,0xFF,0x21,0xD8,0x64,0xFF,0x11,0x22,0x8C,
+0x00,0x0C,0x36,0x5D,0xA1,0x00,0xA0,0xAF,0x02,0x04,0x0D,0x30,0x00,0x0C,0x36,0x5D,
+0x02,0x06,0x08,0x32,0x02,0x20,0x0C,0xB0,0x02,0x46,0x45,0x30,0x02,0x04,0x0D,0x30,
+0xFF,0xFF,0x08,0x3A,0x02,0x06,0x40,0xB0,0xA1,0x00,0x78,0xAF,0x80,0x49,0x3F,0x6D,
+0xFF,0x4D,0x43,0xED,0x04,0x49,0x43,0x7D,0x00,0x0C,0x5C,0xC2,0x80,0x0B,0x47,0x6D,
+0xA1,0x00,0xC8,0x29,0x80,0x0B,0x47,0xFD,0x00,0x0C,0x3C,0x5E,0xB1,0x00,0xC8,0xA9,
+0x40,0x49,0xB3,0xED,0x80,0x49,0x1F,0xED,0x01,0x49,0x1F,0x7D,0xA1,0x00,0x00,0x28,
+0xB1,0x00,0x9A,0x29,0x00,0x0C,0x46,0xC5,0x07,0x11,0x48,0x00,0x02,0x20,0xB4,0xB3,
+0x84,0x80,0x14,0xB8,0x88,0xDA,0x63,0x2D,0x04,0x11,0x48,0x00,0xB1,0x00,0x3C,0x2F,
+0x07,0x11,0x48,0x00,0xFF,0xD1,0x69,0xE5,0x00,0x0C,0x4E,0x58,0xFF,0xD1,0x65,0x75,
+0xB1,0x00,0x80,0x28,0xFF,0x0E,0x62,0x6D,0x44,0x0C,0x1C,0x28,0x02,0x0E,0x1C,0x18,
+0x01,0x11,0x1E,0xA0,0x0F,0x00,0x14,0x08,0x08,0x0A,0x26,0x80,0x02,0xDA,0x27,0xB0,
+0x04,0x11,0x48,0x00,0x01,0x0C,0xA8,0xB3,0x00,0x0C,0x74,0xC4,0x08,0x4C,0xC3,0x6D,
+0x02,0x46,0x45,0x30,0x02,0x20,0x0C,0xB0,0x00,0x0C,0xB8,0xC4,0x02,0x46,0x45,0x30,
+0x02,0x20,0x0C,0xB0,0xA1,0x00,0x78,0xAF,0xB1,0x00,0xD2,0x2A,0x00,0x0C,0x1E,0xCD,
+0xA1,0x00,0x00,0x28,0x02,0x20,0x0C,0xB0,0x02,0x46,0x45,0x30,0x80,0x0B,0x9B,0x7D,
+0x04,0x0C,0x79,0x32,0x00,0x4D,0xAB,0xDD,0x00,0x0C,0xB2,0xC4,0x02,0x20,0x0C,0xB0,
+0x02,0x46,0x45,0x30,0x00,0x4D,0xAB,0xDD,0x00,0x0C,0x2E,0x45,0x02,0x46,0x45,0x30,
+0x01,0x4D,0x19,0xB0,0xB1,0x00,0xC8,0xA9,0x40,0x49,0xB3,0xED,0x80,0x49,0x1F,0xED,
+0xA1,0x00,0x40,0x2A,0xFF,0x45,0xB7,0x65,0x1B,0x11,0xB0,0xC5,0x23,0x11,0xB0,0x45,
+0x02,0x20,0x0C,0xB0,0x00,0x0C,0xCE,0xDE,0x00,0x0C,0x96,0xCD,0x08,0x4C,0xB9,0xFC,
+0x02,0x06,0x22,0x30,0xF7,0x11,0x18,0x00,0xB1,0x00,0xAC,0x29,0x04,0x11,0x18,0x00,
+0xB1,0x00,0x7E,0x29,0x00,0x0C,0xD8,0xC4,0x02,0x20,0x0C,0xB0,0x00,0x0C,0xCE,0xDE,
+0x00,0x0C,0xA2,0x4D,0xA1,0x00,0x78,0xAF,0x02,0x00,0xC9,0x33,0x00,0x0C,0xDE,0x5D,
+0xFF,0xE5,0xDD,0x65,0xFF,0xFF,0xCC,0xBF,0xA1,0x00,0xA6,0x28,0x0A,0x4D,0x59,0x67,
+0xCD,0x11,0x52,0xC7,0x02,0x20,0xC8,0x33,0xA1,0x00,0xA6,0x28,0x07,0x11,0xEA,0x45,
+0x05,0x11,0xEA,0xC5,0x01,0x0C,0x48,0x30,0x02,0x38,0xF8,0x7D,0xFF,0xD1,0xF9,0x75,
+0xB1,0x00,0x80,0x28,0xFF,0x0E,0xEE,0xED,0x01,0x0C,0x60,0x30,0x02,0x20,0x64,0xB4,
+0x01,0x00,0x14,0xB8,0x83,0xD4,0xA9,0x2B,0xC8,0x01,0x18,0x38,0x0F,0x00,0x14,0x08,
+0x00,0x0C,0x18,0x98,0x02,0x0C,0x1C,0xB0,0x01,0x12,0x14,0x30,0xFF,0x0A,0x14,0x6E,
+0x01,0x11,0x26,0x80,0xC0,0x01,0x1C,0x38,0x01,0xD7,0x15,0xB0,0x00,0x0E,0x1C,0x98,
+0x01,0x00,0x26,0xB0,0x07,0x0E,0xAE,0x0F,0x01,0x0A,0x14,0x18,0x00,0x0C,0x1A,0x4E,
+0x01,0x0A,0x26,0x34,0x24,0x11,0x2A,0x00,0x00,0x40,0x18,0xB8,0xA1,0x00,0x1E,0xAF,
+0xFF,0xBF,0x18,0xB8,0xA1,0x00,0x2E,0xAF,0xC0,0x49,0x1F,0x6D,0x04,0x4E,0x2D,0xEE,
+0x03,0x4E,0x39,0x6E,0x27,0x11,0x2A,0x00,0xFB,0x4E,0x9D,0x8A,0x00,0x0C,0x5C,0x5E,
+0x00,0x0C,0x1E,0xD5,0x06,0x11,0x48,0x80,0x00,0x0C,0x64,0xDE,0x04,0x11,0x48,0x84,
+0xFC,0x4E,0x9D,0x0A,0xA1,0x00,0xD2,0xAA,0xC0,0x49,0x1F,0x6D,0xFF,0x4D,0x4F,0xEE,
+0x00,0x0C,0x44,0x46,0xC0,0x49,0x1F,0x6D,0x20,0x48,0x4B,0xEE,0x01,0x48,0x1F,0xFD,
+0x00,0x0C,0x5C,0x46,0x20,0x49,0x4F,0xEE,0x01,0x4E,0x51,0x6E,0xA1,0x00,0xD2,0xAA,
+0x00,0x11,0x66,0x8A,0x01,0x4E,0x9D,0x8A,0xFC,0x49,0x93,0x0A,0xB1,0x00,0xBA,0xA9,
+0x02,0x46,0x45,0x30,0x00,0x0C,0x3A,0xC2,0x02,0x46,0x45,0x30,0xA6,0x01,0x18,0xB8,
+0x30,0x01,0x1C,0x38,0x00,0x0C,0x18,0xC7,0xFF,0xFF,0x0C,0xBA,0xFF,0xD1,0x6D,0x66,
+0x02,0x20,0xA0,0xB3,0x02,0x20,0xA4,0xB7,0x02,0x20,0x14,0xB0,0x02,0xD2,0x41,0x30,
+0x02,0x0A,0x0C,0xB2,0x02,0x0A,0xA4,0xB3,0x02,0x0A,0x40,0x34,0xFF,0xD9,0x83,0xE6,
+0x06,0x11,0x48,0x80,0x02,0x06,0xA1,0xB3,0xFF,0x07,0x81,0x66,0xFF,0xFF,0xA4,0xBB,
+0x04,0x11,0x48,0x84,0x02,0x20,0xA8,0x33,0x02,0x06,0xAD,0xB3,0x02,0xD8,0x41,0x30,
+0x02,0xD6,0x0D,0xB2,0x02,0xD4,0x41,0x30,0xFF,0x07,0x1F,0xE5,0x06,0x11,0x48,0x80,
+0x02,0xD8,0xA5,0x33,0x04,0x11,0x48,0x84,0x02,0x05,0x0A,0x00,0x02,0xD0,0x41,0xB0,
+0x04,0x11,0x48,0x00,0xFF,0xFF,0xB0,0xBB,0x01,0x49,0xAD,0xEE,0x80,0x33,0xAD,0xFE,
+0x02,0x46,0x45,0x30,0xA6,0x01,0x1C,0x38,0x33,0x01,0x18,0xB8,0x00,0x0C,0x3C,0xDF,
+0x00,0x0C,0xAE,0x56,0x26,0x11,0x5A,0x5F,0x00,0x0C,0x76,0xDE,0xFF,0x07,0x5F,0x77,
+0x02,0x20,0xB0,0x33,0x02,0x06,0x41,0x30,0x00,0x0C,0x9C,0x46,0x00,0x0C,0x42,0x5E,
+0x00,0x0C,0x46,0xC5,0x44,0x43,0x15,0xA8,0x00,0x43,0x15,0x80,0x02,0x20,0x0C,0xB0,
+0x01,0x0A,0x00,0x30,0x02,0x06,0x40,0xB0,0x15,0x11,0x56,0x5F,0x02,0x05,0x0A,0x84,
+0x02,0x46,0x45,0x30,0xB1,0x00,0xC8,0xA9,0x00,0x4D,0x5B,0x47,0x02,0x46,0x45,0x30,
+0x03,0xD5,0x09,0x77,0x09,0xD5,0x09,0x77,0x12,0xD5,0x09,0x77,0xF0,0xD5,0x15,0x08,
+0x80,0x0A,0xEA,0x76,0x08,0xD5,0xE1,0x6E,0x44,0xD5,0x0F,0x28,0x06,0x07,0xE2,0x7E,
+0x00,0x11,0x7E,0x0B,0x0F,0xD5,0x7D,0x0A,0x02,0x11,0x7A,0x02,0x04,0x11,0x60,0x5F,
+0x01,0x10,0x22,0x1C,0x44,0xD5,0x15,0xA8,0x80,0x0A,0xF6,0xEE,0x01,0x0A,0x0E,0xB0,
+0x0C,0x07,0xF6,0xEE,0xC2,0x07,0xFE,0xEE,0x31,0x07,0xFA,0x6E,0x00,0x11,0x7E,0x0B,
+0x01,0x11,0x22,0x9C,0x80,0xBF,0xFF,0x6E,0x00,0x0C,0x10,0x5F,0x04,0x11,0x6E,0x83,
+0x0F,0x9F,0x3F,0x0B,0x44,0xD5,0x15,0xA8,0x00,0x9F,0x3F,0x83,0x01,0x11,0x22,0x9C,
+0x80,0xBF,0x0D,0x6F,0x00,0x0C,0x10,0x5F,0x01,0xD5,0x6F,0xB3,0x01,0x11,0x22,0x9C,
+0xBA,0x01,0x18,0x38,0xBC,0x01,0x1C,0xB8,0x08,0x9F,0x19,0x7F,0x90,0x01,0x18,0xB8,
+0x02,0x12,0x14,0x30,0x8B,0x10,0xCA,0xAF,0x00,0x0C,0x22,0xDF,0x04,0x64,0x26,0x30,
+0x01,0x10,0x22,0x1C,0x07,0x11,0x48,0x00,0x04,0x11,0xB8,0x33,0x02,0x0A,0xBA,0xB3,
+0x00,0x0C,0x30,0xDF,0x00,0x0C,0x30,0xDF,0x04,0xDC,0xC9,0xB0,0x04,0x11,0x48,0x84,
+0x02,0xDC,0x15,0x30,0x83,0xDC,0xB9,0x2B,0x02,0xDE,0x15,0xB0,0x84,0xDE,0xBD,0x2F,
+0xBA,0x01,0x1C,0xB8,0xBF,0x01,0x18,0x38,0x11,0x12,0x22,0xA8,0x00,0x0C,0x1E,0xD5,
+0x02,0x0C,0x0C,0x30,0x02,0x0E,0x18,0xB0,0x02,0x12,0x14,0x30,0x00,0x0C,0x22,0xDF,
+0x02,0x06,0x18,0x30,0xFC,0x0C,0x18,0x98,0x04,0x12,0xC8,0xB0,0xFF,0x11,0x22,0x20,
+0x11,0x67,0x22,0xAC,0xA1,0x00,0x32,0xA8,0xA1,0x00,0x4C,0xA8,0xA1,0x00,0x66,0x28,
+0xA1,0x00,0x72,0xAA,0xA1,0x00,0x6C,0xAA,0xA1,0x00,0x9E,0x2A,0xFD,0x05,0x0A,0x0C,
+0xA1,0x00,0x8C,0x29,0x00,0x0C,0x1C,0xDE,0x02,0x86,0x45,0x30,0xFF,0x23,0x20,0x76,
+0xB1,0x00,0xEC,0x2D,0x00,0x0C,0x6E,0xD7,0xB1,0x00,0x12,0xAE,0x02,0xAE,0x45,0x30,
+0x00,0x0C,0x66,0xC7,0x00,0x00,0x40,0xB8,0x00,0x0C,0xAA,0xDF,0x00,0x0C,0x84,0x57,
+0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,0x02,0x34,0x15,0x30,0x02,0x06,0x40,0xB0,
+0x88,0x20,0x85,0x2F,0x01,0x10,0x22,0x1C,0xB1,0x00,0xB0,0x2E,0x00,0x0C,0x74,0x57,
+0x1F,0x11,0x18,0x9C,0x00,0x00,0x40,0xB8,0x00,0x0C,0xAA,0xDF,0x00,0x0C,0xA4,0xD7,
+0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,0x09,0x0B,0x9F,0xE7,0x02,0x34,0x15,0x30,
+0x02,0x06,0x40,0xB0,0x88,0x20,0xA5,0xAF,0x00,0x0C,0xA0,0xC7,0x02,0x06,0x40,0xB0,
+0x23,0x11,0x18,0x00,0xB1,0x00,0x2C,0xAC,0xB1,0x00,0xB0,0x2E,0x00,0x0C,0x8C,0xD7,
+0xFF,0x11,0x22,0x8C,0xB1,0x00,0xEE,0xAE,0x00,0x0C,0x1E,0xD5,0x01,0x11,0x4A,0x80,
+0x28,0x01,0x18,0xB8,0x80,0x0B,0xB7,0x7F,0x34,0x01,0x18,0x38,0x08,0x12,0xD0,0xB3,
+0xE0,0x01,0x18,0x38,0x01,0x12,0x14,0x30,0x07,0x0C,0x18,0x18,0x00,0x12,0xC8,0xE7,
+0xF8,0x0C,0x18,0x18,0xE8,0x0C,0xBA,0xE7,0x00,0x11,0x4A,0x88,0x01,0x10,0x22,0x1C,
+0x00,0x11,0x4A,0x88,0x01,0x11,0x22,0x9C,0x01,0x8E,0x1D,0x1B,0x01,0x8E,0x1F,0xE5,
+0xC8,0x11,0x5C,0x5F,0xFF,0x21,0xD8,0xF7,0x02,0xD6,0xB1,0xB3,0x00,0x0C,0x54,0x5F,
+0x02,0x20,0x18,0x37,0xFF,0x8E,0x1D,0x9B,0xFF,0x8E,0x1F,0xED,0xFF,0x8D,0x1F,0xF5,
+0x02,0x8C,0x41,0xB0,0xFF,0xFF,0x18,0x3B,0xC9,0x11,0x52,0x47,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0xFF,0x4B,0x39,0x6D,0xFF,0x4D,0x25,0xE8,0x03,0x48,0x25,0x78,0x20,0x48,0x1D,0xE8,
+0x80,0x49,0x0F,0xF8,0xFF,0xFE,0x18,0xB8,0x00,0x0C,0xA0,0xC1,0x02,0x4C,0x19,0x78,
+0x00,0x00,0x14,0x38,0x88,0x0C,0x19,0x28,0x88,0x0E,0x19,0xA8,0x17,0x11,0x2E,0x40,
+0x04,0x0C,0x79,0x32,0x01,0x11,0x22,0xC0,0x20,0x49,0x25,0x78,0x04,0x11,0x78,0xB2,
+0x02,0x11,0x22,0xC0,0x00,0x0C,0x8C,0x59,0x80,0x4C,0x73,0xFA,0x21,0x1F,0x2D,0xE8,
+0x40,0x48,0x73,0x7A,0x0B,0x11,0x2E,0xC0,0x0C,0x11,0x2E,0x40,0x00,0x0C,0x8C,0x59,
+0xCD,0x11,0x32,0x40,0x01,0x11,0x1A,0x80,0xFF,0xFF,0x00,0xBA,0xFF,0x12,0x40,0x60,
+0x01,0x11,0x1E,0x00,0xFE,0x0C,0x1C,0x98,0x02,0x20,0x26,0x30,0x02,0x20,0x26,0xB4,
+0x02,0x0C,0x1C,0xB0,0x02,0x20,0x14,0xB0,0x02,0x12,0x40,0xB0,0x02,0x0A,0x00,0xB2,
+0x02,0x0A,0x26,0xB0,0x02,0x0A,0x40,0x34,0x02,0x0C,0x1C,0xB0,0xFF,0xD9,0x57,0xE0,
+0x02,0x00,0x27,0x30,0xFF,0x01,0x39,0x65,0xFF,0xFF,0x26,0x3C,0x02,0x20,0xA8,0x33,
+0x02,0x00,0xAD,0xB3,0x02,0xD8,0x41,0x30,0x02,0xD6,0x01,0xB2,0x02,0xD4,0x41,0x30,
+0xFF,0x01,0x39,0x65,0x02,0x0C,0x1C,0x98,0x02,0xD8,0x27,0xB4,0x02,0x0C,0xC0,0x33,
+0x02,0x20,0xC4,0x33,0x01,0x24,0xD0,0xB3,0x04,0x11,0x48,0x00,0xFD,0x05,0x0A,0x88,
+0x02,0x05,0x0A,0x00,0x02,0x38,0x78,0x68,0xFD,0x05,0x0A,0x88,0x00,0x0C,0x70,0xC0,
+0x01,0xE0,0x61,0x30,0x02,0xE2,0x65,0x30,0x01,0xE8,0x49,0xB0,0xFD,0x05,0x0A,0x0C,
+0x02,0xD0,0x41,0xB0,0x44,0xD8,0x19,0x28,0x0F,0x0C,0x18,0x98,0x01,0x11,0x1A,0x20,
+0xC0,0x12,0x1C,0x88,0x05,0x24,0x8E,0x70,0xC0,0xD8,0x99,0x40,0xFF,0x0E,0x96,0xE8,
+0x00,0x00,0x44,0x38,0xFF,0xFF,0x14,0x38,0x83,0x8E,0x1D,0x2B,0xD0,0xD8,0x99,0xC0,
+0x01,0xD8,0xB1,0x1B,0x07,0xD8,0x39,0xED,0x02,0x02,0xA1,0x33,0xFF,0xFF,0x04,0x3A,
+0xFF,0xD1,0xA5,0xE0,0xFF,0xFF,0xA4,0xBB,0x01,0x11,0xB0,0x07,0x01,0x00,0x0E,0xB0,
+0x01,0x07,0x14,0xB0,0x00,0xDC,0xB9,0x07,0xFF,0x11,0x14,0x02,0xFF,0xFF,0x10,0x3A,
+0xFF,0xFF,0x8C,0x3A,0x06,0x11,0x48,0x80,0x01,0xD5,0x15,0x30,0x00,0x21,0xBA,0xE8,
+0xD7,0x11,0xBC,0xC0,0xDB,0x11,0xBC,0xC0,0x00,0x0C,0x32,0xD8,0x04,0x11,0x48,0x84,
+0xC0,0x0A,0x15,0x88,0x40,0x0A,0xFE,0x70,0x01,0x0A,0x15,0xB0,0x00,0x11,0x16,0x88,
+0x66,0x04,0x18,0xB8,0x83,0x0C,0x0C,0xAC,0x00,0x0C,0xF8,0xC0,0x00,0x0C,0xF8,0xC0,
+0x00,0x0C,0xF8,0xC0,0x00,0x0C,0xEC,0xC0,0x00,0x0C,0xF8,0xC0,0x00,0x0C,0xFE,0xC0,
+0x00,0x0C,0xFE,0xC0,0x00,0x0C,0xFE,0xC0,0x00,0x0C,0xEC,0xC0,0x00,0x0C,0x04,0x41,
+0x00,0x0C,0x40,0x41,0x00,0x0C,0x40,0x41,0x00,0x0C,0x40,0x41,0xA0,0x00,0x06,0x2A,
+0xA0,0x00,0x06,0x2A,0x00,0x0C,0x40,0x41,0xFF,0xFF,0x14,0x38,0x88,0x34,0xF5,0x28,
+0x00,0x0C,0x92,0xDE,0x00,0x0C,0x38,0x4D,0x00,0x0C,0x62,0xDE,0x00,0x0C,0x38,0x4D,
+0x01,0x21,0x40,0x32,0x01,0x20,0x42,0x32,0x01,0x11,0x22,0x9C,0x01,0x21,0x44,0xB2,
+0x01,0x20,0x46,0xB2,0x01,0x11,0x22,0x9C,0x08,0x48,0x41,0xF9,0x02,0x46,0x45,0x30,
+0x04,0x11,0xA8,0xB3,0x01,0xB4,0xAD,0xB3,0xA8,0x01,0x18,0x38,0x01,0x12,0xB0,0xB3,
+0xFF,0xD8,0x17,0xE9,0x08,0xD4,0xA9,0x1B,0x00,0x0C,0x1E,0xC1,0x44,0xD4,0x0F,0xA8,
+0x01,0x07,0x14,0xB0,0x00,0xD8,0x23,0x69,0x01,0xD4,0xA9,0x1B,0x07,0xD4,0x17,0x69,
+0x00,0x0C,0x0E,0x41,0x02,0x0C,0x1C,0xB0,0xFF,0x0E,0x1C,0x98,0x00,0xD8,0x27,0x10,
+0x01,0xD4,0x15,0xB0,0x00,0x0A,0x14,0x98,0x80,0x01,0x1C,0xB8,0x00,0x0E,0x1C,0x98,
+0x02,0xA4,0x45,0x30,0x02,0x20,0x26,0x30,0x33,0xD4,0x15,0x28,0x00,0x1C,0x39,0x82,
+0x01,0x11,0x22,0x9C,0x00,0x00,0x14,0x38,0x88,0x12,0xB8,0xAE,0x88,0x12,0xB8,0xAE,
+0x01,0x11,0x22,0x9C,0x02,0x22,0x0C,0x30,0x00,0x00,0x44,0x38,0xB8,0x01,0x18,0xB8,
+0x0F,0x00,0x14,0x08,0x00,0x0C,0x18,0x98,0x01,0x12,0x14,0x30,0x02,0x06,0x44,0x30,
+0xFF,0x11,0x22,0x8C,0x02,0x0C,0x0C,0x30,0x08,0x0C,0x18,0x18,0x02,0x12,0x1C,0xB0,
+0x02,0x0A,0x0C,0x30,0x82,0x10,0x14,0x28,0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,
+0x83,0x0E,0x1C,0x28,0x02,0x06,0x14,0x30,0x80,0x0F,0x6A,0xF9,0xFE,0x0C,0x18,0x18,
+0x02,0x12,0x14,0x30,0x02,0x06,0x18,0x30,0xFF,0x11,0x22,0x8C,0x01,0x0C,0x1A,0xB0,
+0x00,0x11,0x72,0xC1,0x02,0x48,0x15,0xB0,0x80,0x0C,0x04,0xA8,0xE1,0x48,0x7B,0x29,
+0xFF,0x11,0x22,0x8C,0x02,0x48,0x91,0x32,0x00,0x0C,0x72,0xC1,0x00,0x11,0x1A,0x88,
+0x02,0x4C,0x15,0x30,0x80,0x0C,0x04,0xA8,0xE1,0x4C,0x89,0x29,0xFF,0x11,0x22,0x8C,
+0x02,0x4C,0x99,0x32,0x00,0x0C,0x80,0x41,0x02,0x4C,0x15,0x30,0x01,0x0A,0x04,0x80,
+0x01,0x0C,0x06,0x30,0xE1,0x4C,0x97,0x29,0xFF,0x11,0x22,0x8C,0x02,0x4C,0x99,0x32,
+0x00,0x0C,0x8C,0x41,0x7F,0x11,0x9C,0x41,0x01,0x0C,0x1A,0xB0,0xFF,0x11,0xA0,0xC1,
+0x02,0x48,0x15,0xB0,0x81,0x0C,0x04,0x28,0xE1,0x48,0xA9,0x29,0xFF,0x11,0x22,0x8C,
+0x02,0x48,0x91,0x32,0x00,0x0C,0xA0,0xC1,0xFF,0x11,0x1A,0x00,0x02,0x4C,0x15,0x30,
+0x81,0x0C,0x04,0x28,0xE1,0x4C,0xB7,0xA9,0xFF,0x11,0x22,0x8C,0x02,0x4C,0x99,0x32,
+0x00,0x0C,0xAE,0x41,0x02,0x4A,0x15,0x30,0x01,0x0A,0x04,0xB0,0x01,0x0B,0x06,0x98,
+0xE1,0x4A,0xC5,0xA9,0xFF,0x11,0x22,0x8C,0x02,0x4A,0x95,0x32,0x00,0x0C,0xBA,0x41,
+0x02,0x4A,0x15,0x30,0x01,0x0A,0x04,0xB0,0xFF,0x0B,0x06,0x18,0xE1,0x4A,0xD3,0x29,
+0xFF,0x11,0x22,0x8C,0x02,0x4A,0x95,0x32,0x00,0x0C,0xC8,0x41,0x02,0x0C,0x0C,0x30,
+0x02,0xD8,0x0D,0xB0,0x00,0x0C,0x4C,0xD8,0x1B,0x11,0x14,0x80,0x00,0x0C,0x1A,0x5A,
+0xC0,0x0C,0xE4,0xF1,0xC0,0x11,0xF0,0xC1,0xFF,0x8E,0xEF,0xF9,0x02,0x8C,0x41,0xB0,
+0xFF,0x21,0xFC,0xF1,0xFF,0xFF,0x18,0x3B,0xC8,0x11,0xF8,0xC1,0xC8,0x11,0xF0,0x41,
+0x00,0x0C,0x9E,0x5A,0xFF,0x21,0xFC,0xF1,0x02,0xD6,0xB1,0xB3,0x00,0x0C,0x4C,0xD8,
+0x1B,0x11,0x14,0x80,0x00,0x0C,0x1A,0x5A,0x00,0x00,0x40,0xB8,0xFF,0xFF,0xD4,0x3B,
+0x00,0x0C,0xEE,0x5E,0x00,0x0C,0x06,0x52,0x1B,0x11,0x2C,0x5C,0x00,0x0C,0xB0,0xDE,
+0x00,0x0C,0x00,0x52,0x00,0x0C,0x16,0xDE,0x02,0x06,0xB0,0xB3,0x02,0x06,0x18,0x30,
+0xFF,0xD9,0x17,0x72,0x02,0xD8,0x41,0x30,0x02,0x00,0x41,0xB4,0x02,0x12,0x40,0xB0,
+0xFE,0x0C,0x18,0x9C,0x02,0x0C,0x0C,0x30,0x00,0x0C,0x36,0xDA,0x02,0x0A,0x0C,0x30,
+0x00,0x0A,0x40,0x5A,0x02,0x06,0x14,0x30,0x02,0xD4,0x19,0xB0,0x02,0x12,0x0C,0x30,
+0x02,0xD4,0x1D,0x30,0xFF,0xFF,0x26,0xB8,0x02,0x06,0x40,0xB0,0xFF,0x21,0x1E,0x62,
+0x02,0x06,0x18,0x30,0x02,0xDA,0x1D,0xB0,0xFF,0xFF,0x26,0x3C,0xC0,0x0C,0x3C,0x62,
+0x02,0x01,0xA8,0xBB,0xA0,0x01,0xB4,0x3F,0x04,0x01,0xA8,0xBB,0xA2,0x01,0xB4,0xBF,
+0x1B,0x0C,0x52,0xE2,0x01,0xB7,0x79,0x32,0x04,0xB7,0x4D,0xE2,0x01,0x11,0x7A,0x02,
+0xF0,0x9F,0x7D,0x8A,0x00,0x0C,0x6C,0xC2,0x03,0xB7,0x6D,0xE2,0x01,0x9E,0x7B,0x8A,
+0x00,0x0C,0x6C,0xC2,0x23,0x0C,0x56,0x72,0x13,0x0C,0x6C,0xE2,0x02,0x20,0x78,0x32,
+0x80,0x0B,0x5F,0x7A,0x01,0x21,0x79,0x32,0x01,0x20,0x7B,0x32,0x88,0x11,0x02,0x00,
+0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,0x02,0x52,0x15,0x30,0x02,0x06,0x40,0xB0,
+0x01,0x01,0x22,0xB0,0x02,0x0A,0x7C,0x32,0x00,0x0C,0xD2,0xDA,0x00,0x0C,0x38,0x4D,
+0x00,0x0C,0x8C,0x59,0x00,0x0C,0xF6,0x5D,0x00,0x0C,0x9C,0x52,0x02,0x46,0x45,0x30,
+0xFF,0xFF,0x14,0x38,0x83,0xAC,0x59,0x2B,0x04,0x9F,0x81,0xFA,0x00,0x0C,0x08,0x5F,
+0x40,0x49,0x9B,0xFA,0xFF,0x45,0x9B,0xF2,0x02,0x20,0x0C,0xB0,0x02,0x44,0x0D,0xB0,
+0x00,0x0C,0xB2,0xDA,0xC5,0x11,0x32,0xD8,0x88,0x11,0x02,0x00,0x02,0x06,0x40,0xB0,
+0xFF,0xFF,0x14,0x38,0x83,0x4A,0x95,0x2A,0x00,0x0C,0x60,0xDC,0x01,0x01,0x22,0xB0,
+0x00,0x0C,0x36,0x45,0x00,0x0C,0xB2,0xDA,0xC5,0x11,0x32,0xC0,0xFF,0xFF,0xAC,0x3B,
+0x01,0x11,0x1A,0x80,0x02,0x12,0x40,0xB0,0xFE,0x0C,0x18,0x18,0xFF,0x21,0x38,0xF5,
+0x00,0x0C,0xF2,0xDE,0x00,0x0C,0x38,0x4D,0x02,0x20,0xAC,0xB3,0x02,0x00,0x41,0x30,
+0x00,0x0C,0xA6,0xC2,0x09,0x0A,0x39,0xE5,0x08,0x48,0x39,0x7D,0x3D,0x1C,0x17,0xA8,
+0x02,0x22,0x0C,0x30,0x02,0x46,0x45,0x30,0xA8,0x01,0x18,0x38,0x3D,0x0B,0x14,0xA8,
+0x00,0x0C,0x18,0x98,0x02,0x0C,0x1C,0xB0,0x44,0x0B,0x0E,0xA8,0x01,0x07,0x14,0xB0,
+0x00,0x12,0xD0,0x6A,0xFF,0x0C,0x18,0x98,0x00,0x12,0x26,0x00,0x00,0x0C,0x4E,0xC1,
+0x1A,0x11,0x2A,0x80,0x02,0x48,0x15,0xB0,0x01,0x0B,0xB8,0x6E,0x01,0x0A,0x04,0xB0,
+0x01,0x0B,0x06,0x80,0xE1,0x48,0xDF,0xAA,0x01,0x11,0x22,0x9C,0x02,0x48,0x91,0x32,
+0x00,0x0C,0xD2,0xC2,0x02,0x20,0xD4,0xB3,0x01,0x0A,0xE5,0xB3,0x10,0x0B,0xF1,0xFA,
+0xFF,0xFF,0x14,0x38,0x8A,0x34,0xF1,0xAA,0x00,0x0C,0x3E,0xDD,0x00,0x0C,0x72,0x4A,
+0x02,0x46,0x45,0x30,0xFD,0x8F,0x1F,0xF3,0xC0,0x11,0x4C,0xDD,0x00,0x0C,0xFE,0xD2,
+0x1E,0x11,0x6C,0xDA,0x02,0xEA,0x41,0xB0,0x00,0x11,0x6C,0xC2,0xFF,0x8E,0x09,0xFB,
+0x02,0x8C,0x41,0xB0,0xFF,0x21,0x0C,0x73,0x00,0x0C,0xB2,0x5D,0x00,0x0C,0x0A,0x43,
+0xC8,0x11,0x4C,0x5D,0x00,0x0C,0x14,0xCB,0x02,0xEA,0x41,0xB0,0x00,0x0C,0x92,0xDE,
+0x00,0x0C,0x72,0x4A,0x02,0x0A,0x40,0xB0,0x10,0x0B,0x1D,0xFB,0x80,0x11,0x6E,0xD9,
+0x02,0xEA,0x41,0xB0,0xA0,0x00,0x2C,0xAA,0x1D,0x11,0x6C,0xC2,0x2A,0x11,0x2A,0x80,
+0x02,0x20,0xD4,0xB3,0x01,0x0A,0xE5,0xB3,0xFF,0x0B,0x3B,0xFB,0x01,0x0B,0x3D,0xF3,
+0x02,0x0B,0x53,0x73,0x03,0x0B,0x83,0x73,0x04,0x0B,0xA9,0x73,0x05,0x0B,0xB3,0x73,
+0x06,0x0B,0xAF,0xF3,0x07,0x0B,0xF9,0x73,0x08,0x0B,0xF7,0xF3,0x09,0x0B,0x15,0xF4,
+0xA0,0x00,0x06,0x2A,0xFF,0x11,0x28,0x02,0xC0,0x11,0x88,0xDC,0xC8,0x11,0x88,0x5C,
+0x00,0x00,0x40,0xB8,0x00,0x0C,0xF2,0xDD,0x00,0x0C,0x4C,0x53,0x00,0x0C,0xE2,0x5D,
+0x00,0x0C,0x4C,0x53,0x23,0x11,0x2C,0xDC,0x00,0x0C,0xB0,0xDE,0x00,0x0C,0x42,0xD3,
+0x00,0x0C,0x5C,0xC4,0x00,0x0C,0xF8,0xDE,0x00,0x0C,0x6C,0x4A,0x02,0x10,0x5D,0x7B,
+0xC0,0x11,0xB2,0xDC,0x02,0xEA,0x41,0xB0,0x04,0x10,0x63,0xFB,0x00,0x0C,0xA4,0x5C,
+0x02,0xEA,0x41,0xB0,0x01,0x10,0x73,0x7B,0x00,0x00,0x40,0xB8,0x00,0x0C,0xEE,0x5E,
+0x00,0x0C,0x6C,0xD3,0x23,0x11,0x2C,0xDC,0x00,0x0C,0xB0,0xDE,0x00,0x0C,0x66,0xD3,
+0x02,0xEA,0x41,0xB0,0xFD,0x8F,0x81,0x73,0x80,0x10,0x7B,0xFB,0xB0,0x00,0xCC,0xAF,
+0x02,0xEA,0x41,0xB0,0x40,0x10,0x81,0xFB,0xB0,0x00,0xDA,0x2F,0x02,0xEA,0x41,0xB0,
+0x00,0x0C,0x5C,0xC4,0x02,0x46,0x45,0x30,0x00,0x0C,0x24,0x5D,0x02,0x10,0x8D,0xFB,
+0xC0,0x11,0xC8,0x5C,0x02,0xEA,0x41,0xB0,0x04,0x10,0x93,0xFB,0x00,0x0C,0xBE,0xDC,
+0x02,0xEA,0x41,0xB0,0x01,0x10,0x99,0xFB,0xB0,0x00,0x8A,0x2F,0x02,0xEA,0x41,0xB0,
+0xFD,0x8F,0xA7,0xF3,0x80,0x10,0xA1,0x7B,0xB0,0x00,0xCC,0xAF,0x02,0xEA,0x41,0xB0,
+0x40,0x10,0xA7,0x7B,0xB0,0x00,0xDA,0x2F,0x02,0xEA,0x41,0xB0,0x00,0x0C,0x5C,0xC4,
+0x00,0x0C,0x3E,0xDD,0x00,0x0C,0x72,0x4A,0x00,0x0C,0xB2,0x43,0x00,0x0C,0x3A,0x5D,
+0x00,0x0C,0x72,0x4A,0x02,0x46,0x45,0x30,0xC0,0x11,0x4C,0xDD,0x00,0x0C,0xEC,0x4B,
+0xFF,0x8E,0xC3,0xFB,0x02,0x8C,0x41,0xB0,0xFF,0x21,0xC6,0x73,0x00,0x0C,0xB2,0x5D,
+0x00,0x0C,0xC4,0xC3,0xC8,0x11,0x4C,0x5D,0x00,0x0C,0xCE,0x4B,0x02,0xEA,0x41,0xB0,
+0x00,0x0C,0x92,0xDE,0x00,0x0C,0x72,0x4A,0x02,0x0A,0x40,0xB0,0x02,0x20,0x0C,0xB0,
+0x02,0xEA,0x41,0xB0,0x01,0x10,0x15,0x30,0x02,0x06,0x40,0xB0,0x40,0x0A,0xF2,0xFB,
+0xFF,0x4D,0xE7,0x6B,0x00,0x0C,0x9A,0xD9,0x40,0x01,0x18,0x38,0x00,0x0C,0x3A,0xD9,
+0x00,0x0C,0xE8,0xD3,0xB0,0x00,0x46,0x2A,0x00,0x0C,0xE8,0x43,0x00,0x4D,0x6D,0x5A,
+0x02,0xEA,0x41,0xB0,0x13,0x11,0x40,0xC2,0x23,0x11,0x40,0xDA,0x02,0xEA,0x41,0xB0,
+0x00,0x11,0x6C,0xC2,0x23,0x11,0x2C,0xDC,0x00,0x0C,0x5C,0xC4,0xFF,0x11,0x28,0x02,
+0x00,0x0C,0x24,0x5D,0xB0,0x00,0x1C,0xAE,0x02,0x86,0x45,0x30,0xFF,0x23,0x10,0xF4,
+0x00,0x0C,0xEC,0xDD,0x00,0x0C,0x0C,0x54,0xC0,0x11,0xC8,0x5C,0xC8,0x11,0xC8,0xDC,
+0xB0,0x00,0x8A,0x2F,0x02,0xEA,0x41,0xB0,0x02,0xAE,0x45,0x30,0x00,0x0C,0xFE,0xC3,
+0xB0,0x00,0x20,0xAE,0x00,0x0C,0x5C,0xC4,0x00,0x0C,0xF8,0xDE,0x00,0x0C,0x6C,0x4A,
+0xFD,0x8F,0x1D,0xF4,0x22,0x11,0x6C,0xC2,0x00,0x0C,0x24,0x5D,0xB0,0x00,0x72,0xAF,
+0x02,0xEA,0x41,0xB0,0x00,0x0C,0x6C,0x52,0xC0,0x11,0xC8,0x5C,0xC8,0x11,0xC8,0xDC,
+0xB0,0x00,0x8A,0x2F,0x00,0x0C,0x5C,0xC4,0x65,0x07,0x0C,0xB8,0x00,0x0C,0xBA,0xDE,
+0x02,0x0C,0x0C,0x30,0x80,0x11,0x6E,0xD9,0x02,0x06,0x18,0x30,0xFF,0x4B,0x41,0x7A,
+0x40,0x49,0x4D,0x7C,0xFF,0x45,0x4D,0x74,0x02,0x20,0x0C,0xB0,0x02,0x44,0x41,0x30,
+0xFF,0xFF,0x14,0x38,0x83,0x4A,0x95,0x2A,0x02,0x4A,0x15,0x30,0x89,0x10,0x4A,0xAC,
+0x00,0x11,0x6C,0xDA,0x02,0x06,0x40,0xB0,0x02,0xEA,0x89,0xB2,0x40,0x11,0x6E,0xD9,
+0xFF,0xEB,0x39,0x75,0x02,0x20,0xA8,0x33,0x02,0xEA,0x41,0xB0,0x01,0x00,0x14,0xB8,
+0x83,0x4A,0x95,0x2A,0x02,0xD4,0x41,0xB4,0x02,0xEA,0x41,0xB0,0x40,0x10,0x83,0x74,
+0x02,0x4A,0x15,0x30,0x89,0x10,0x38,0x2D,0xFF,0x0B,0x7B,0xFC,0x01,0x0B,0x7B,0xF4,
+0x02,0x0B,0x7F,0x74,0x03,0x0B,0x7F,0xF4,0x04,0x0B,0x7F,0x74,0x05,0x0B,0x7F,0xF4,
+0x06,0x0B,0x7F,0xF4,0x07,0x0B,0x85,0x74,0x08,0x0B,0x85,0x74,0x09,0x0B,0x7F,0xF4,
+0xA0,0x00,0x06,0x2A,0x00,0x0C,0xFE,0xDD,0x00,0x11,0x6C,0xC2,0x00,0x0C,0x12,0x5E,
+0x00,0x11,0x6C,0xC2,0x13,0x11,0x40,0xC2,0xB0,0x00,0x62,0x2F,0x00,0x11,0x6C,0xC2,
+0x01,0x11,0x1A,0x80,0xFF,0xFF,0xB0,0xBB,0x02,0x12,0x40,0xB0,0xFE,0x0C,0x18,0x18,
+0xFF,0x21,0x38,0xF5,0x00,0x0C,0xE2,0x5D,0x00,0x0C,0xA0,0x54,0x00,0x0C,0x4C,0xD8,
+0x23,0x11,0x14,0x00,0x00,0x0C,0x1A,0x5A,0xFF,0xD9,0x8D,0x74,0x02,0xD8,0x41,0x30,
+0x02,0x00,0x41,0x30,0x00,0x0C,0x90,0xC4,0xFF,0x8E,0xB1,0x7C,0x02,0x8C,0x41,0xB0,
+0xFF,0x21,0x38,0xF5,0xFF,0xFF,0x18,0x3B,0xFF,0xFF,0x44,0x3B,0xC8,0x11,0xBA,0xC4,
+0xC8,0x11,0xB2,0x44,0x00,0x0C,0x9E,0x5A,0xFF,0x21,0x38,0xF5,0x02,0xD6,0xB1,0xB3,
+0x00,0x0C,0x4C,0xD8,0x23,0x11,0x14,0x00,0x00,0x0C,0x1A,0x42,0xFF,0x8E,0xC7,0xFC,
+0x02,0x8C,0x41,0xB0,0xFF,0x21,0x38,0xF5,0xC8,0x11,0xD0,0xC4,0xC8,0x11,0xC8,0xC4,
+0x00,0x0C,0x9E,0x5A,0xFF,0x21,0x38,0xF5,0x02,0xD6,0xB1,0xB3,0x00,0x0C,0x4C,0xD8,
+0x02,0x0C,0x0C,0x30,0x02,0x20,0xE0,0x33,0x00,0x0C,0x36,0xDA,0xFF,0xFF,0xB0,0xBB,
+0xB0,0x00,0xAE,0x2F,0x00,0x0C,0x0C,0xD5,0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,
+0x09,0x0B,0xEB,0xE4,0x02,0x34,0x15,0x30,0x02,0x06,0x40,0xB0,0x88,0x20,0x0D,0xAD,
+0x00,0x0C,0xEC,0x44,0x02,0x06,0x40,0xB0,0xFF,0xD9,0xF7,0x64,0x02,0xD4,0x19,0xB0,
+0x02,0x12,0xE0,0xB3,0xFF,0xF1,0xFB,0xF4,0x00,0x0C,0xFE,0x44,0x00,0x0C,0x2A,0xDD,
+0xFF,0xD7,0xFF,0x64,0x02,0xDA,0x1D,0xB0,0x02,0xD8,0x27,0x30,0x02,0xD4,0x19,0xB0,
+0x02,0x12,0x0C,0x30,0x02,0xD4,0x1D,0x30,0xFF,0xFF,0x26,0xB8,0x23,0x11,0x40,0xDA,
+0x02,0x06,0x40,0xB0,0x00,0x0C,0x12,0x45,0x02,0x20,0xB0,0x33,0x02,0xD4,0x19,0xB0,
+0x02,0x12,0x40,0xB0,0xFF,0x21,0xD8,0x64,0x02,0x06,0x18,0x30,0xC8,0x0C,0x1A,0xE5,
+0xFF,0x8E,0x23,0xED,0xFF,0xF1,0x39,0xF5,0x02,0xF0,0x41,0x30,0x01,0x0C,0x18,0x18,
+0x00,0x0C,0x32,0xC0,0x02,0xF0,0x19,0x37,0x01,0x11,0x4A,0x80,0x08,0x28,0xC1,0xB3,
+0x00,0x11,0x4A,0x0C,0x02,0x20,0x0C,0xB0,0x02,0xD4,0x19,0xB0,0x02,0x12,0xAC,0x33,
+0x02,0xD8,0x41,0x30,0x02,0xD4,0x1D,0x30,0x02,0xD6,0x27,0xB0,0x02,0x06,0x40,0xB0,
+0xFF,0x11,0x22,0x8C,0x00,0x0C,0x4E,0x5E,0x00,0x0C,0x40,0xC5,0x00,0x0C,0x62,0xDE,
+0x00,0x0C,0x38,0x4D,0x00,0x0C,0x8C,0xDE,0x02,0x08,0x15,0x30,0x02,0xEA,0x41,0xB0,
+0x02,0x0A,0xA0,0xB2,0x01,0x11,0x22,0x9C,0x00,0x0C,0x9E,0x5A,0x02,0x0C,0xDC,0xB3,
+0x02,0xD6,0xD9,0x33,0x00,0x0C,0x36,0xDA,0xFF,0xFF,0xB0,0xBB,0xFF,0x21,0x40,0x71,
+0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,0x02,0x50,0x15,0xB0,0x02,0x06,0x40,0xB0,
+0x8A,0x08,0x6B,0x2D,0x02,0x20,0xB0,0x33,0x02,0xD4,0x19,0xB0,0x02,0x12,0x40,0xB0,
+0x00,0x0C,0x56,0x45,0xC4,0xF2,0x6F,0x75,0x04,0x4C,0x41,0xE9,0xFF,0xD9,0x7B,0xF5,
+0x00,0x0C,0x2A,0xDD,0xFF,0xD7,0xAD,0x65,0x02,0xDA,0x1D,0xB0,0x02,0xD8,0x27,0x30,
+0x00,0x0C,0xAC,0x45,0x02,0xD4,0x19,0xB0,0x02,0x12,0x14,0x30,0xFF,0x0B,0xA4,0x75,
+0xFF,0xED,0x8D,0x75,0x02,0x20,0x0C,0xB0,0x02,0xEC,0x41,0xB0,0x02,0x0A,0x00,0xB2,
+0x02,0x06,0x40,0xB0,0x00,0x0C,0x90,0x45,0x02,0xEE,0x1D,0x30,0x02,0x0A,0x26,0xB0,
+0xFF,0x01,0x99,0x65,0x02,0xEE,0x1D,0x30,0x02,0x0E,0x1C,0x18,0x02,0x0A,0x26,0xB0,
+0x02,0x20,0x0C,0xB0,0x02,0x00,0xAD,0xB3,0x02,0x0A,0x40,0xB0,0x02,0xD6,0x01,0xB2,
+0x02,0x06,0x40,0xB0,0x00,0x0C,0xAC,0x45,0x02,0xDA,0x1D,0xB0,0xFF,0xFF,0x26,0xB8,
+0x02,0xEC,0xB1,0xB3,0x00,0xEE,0x4D,0x58,0xC8,0xEE,0xB1,0x65,0x00,0x0C,0xC8,0x59,
+0x01,0x10,0x22,0x1C,0xFF,0xFF,0xB0,0xBB,0xFF,0x21,0x40,0x71,0x02,0x20,0x0C,0xB0,
+0x02,0xEA,0x41,0xB0,0x02,0x50,0x15,0xB0,0x02,0x06,0x40,0xB0,0x8A,0x08,0xC7,0x2D,
+0x02,0x20,0xB0,0x33,0x02,0x04,0x41,0xB0,0x00,0x0C,0xB4,0x45,0xFF,0xD9,0xD9,0x75,
+0x02,0x20,0x0C,0xB0,0x02,0x04,0xAD,0x33,0x02,0xD8,0x41,0x30,0x02,0xD6,0x09,0x32,
+0x02,0x06,0x40,0xB0,0xFF,0xD7,0xDF,0x65,0x02,0xD8,0x45,0xB3,0x00,0x0C,0xDE,0x45,
+0x02,0x04,0x19,0x33,0xFF,0x05,0xDF,0x65,0xFF,0xFF,0x44,0x3B,0x00,0x0C,0xC8,0x59,
+0x01,0x10,0x22,0x1C,0x02,0x46,0x45,0x30,0x02,0x20,0x0C,0xB0,0x02,0xEA,0x41,0xB0,
+0x00,0x0C,0xEC,0xDD,0x00,0x0C,0x36,0x45,0x01,0x14,0x15,0xB0,0x00,0x9C,0x41,0x79,
+0x01,0x10,0x22,0x1C,0x01,0x49,0x41,0xE9,0xFF,0x0A,0x41,0xF1,0xC0,0x0A,0x15,0x88,
+0x80,0x0A,0x40,0xF1,0xC0,0x0A,0x40,0x71,0x01,0x10,0x22,0x1C,0x01,0x00,0x44,0xB8,
+0xFE,0x8F,0x09,0xE6,0x00,0x0C,0xEC,0xDD,0x00,0x0C,0x08,0x56,0x00,0x0C,0x16,0xDE,
+0x01,0x00,0x14,0xB8,0x83,0x22,0x44,0x28,0x02,0xFE,0x15,0x30,0x88,0x22,0x00,0xAE,
+0xFF,0x11,0x22,0x8C,0x02,0xAC,0x15,0xB0,0x89,0x10,0x38,0x2D,0x00,0x00,0x3C,0x3B,
+0x04,0x10,0x40,0x33,0x00,0x11,0x7E,0x0B,0x04,0x9D,0x39,0x6D,0xFF,0xFF,0x4C,0xBB,
+0x04,0x11,0x60,0x33,0x00,0x11,0x6A,0x0B,0x00,0x11,0x6C,0x0B,0xFF,0xB4,0x39,0xFD,
+0x04,0x11,0x50,0x33,0x3D,0xB4,0x15,0xA8,0xA8,0x01,0x1C,0xB8,0x00,0x11,0x16,0x88,
+0xFF,0x0A,0x3A,0xFE,0xFF,0x11,0x26,0x00,0x08,0x0B,0x16,0x18,0xFF,0x0A,0x14,0x98,
+0x00,0x0C,0x30,0x46,0xFF,0x0B,0x14,0x90,0x01,0x0A,0x14,0x18,0x00,0xB4,0x15,0x18,
+0xFF,0x0A,0x46,0x7E,0x44,0x0A,0x0E,0x28,0xFF,0x07,0x26,0x98,0x02,0x22,0x14,0x30,
+0x01,0xA4,0x45,0x30,0x40,0x10,0x00,0xB3,0x02,0x0A,0x44,0xB4,0x02,0x20,0x0C,0xB0,
+0x02,0x46,0x45,0x30,0x02,0xA4,0x45,0x30,0x01,0x35,0x15,0xB0,0x00,0x0A,0x14,0x98,
+0x80,0x01,0x18,0x38,0x00,0x0C,0x18,0x98,0x02,0x12,0x40,0xB0,0xFF,0x21,0x80,0xF6,
+0x00,0x0C,0x72,0x46,0x02,0x20,0x0C,0xB0,0x00,0x0C,0x8C,0xDE,0x02,0x20,0x18,0xB0,
+0x02,0xFC,0x15,0xB0,0x00,0x0C,0xDA,0xDE,0x80,0x0F,0x80,0xFE,0xFF,0x20,0x72,0x66,
+0xF0,0x21,0x80,0x7E,0xFF,0x0A,0x83,0xF6,0x01,0x49,0x85,0xEE,0x02,0x20,0x14,0xB0,
+0x02,0x06,0x40,0xB0,0x01,0x0A,0x6A,0xB2,0x01,0x0B,0x68,0xB2,0x01,0x11,0x22,0x9C,
+0x1F,0x11,0x86,0x46,0x20,0x11,0x86,0x46,0x21,0x11,0x86,0xC6,0x02,0x06,0x40,0xB0,
+0x00,0x0C,0x8C,0x59,0x01,0x10,0x22,0x1C,0x01,0x35,0x15,0xB0,0x01,0x34,0x17,0xB0,
+0x02,0x0A,0x40,0x34,0x02,0x50,0xA9,0x33,0x02,0x20,0x0C,0xB0,0x00,0x00,0x40,0xB8,
+0x02,0x08,0x15,0x30,0x8A,0xD4,0xA7,0xAE,0x00,0x0C,0xB0,0xDE,0x00,0x0C,0x98,0x56,
+0x02,0x06,0x40,0xB0,0x1D,0x11,0x8C,0x59,0x01,0x10,0x22,0x1C,0x02,0x20,0x14,0xB0,
+0x02,0x06,0x40,0xB0,0x01,0x0B,0x68,0xB2,0x01,0x0A,0x6A,0xB2,0x01,0x11,0x22,0x9C,
+0x01,0x00,0x14,0xB8,0x83,0x20,0x40,0x28,0x02,0xFC,0x15,0xB0,0x88,0x20,0x40,0x29,
+0x01,0x10,0x22,0x1C,0x02,0x48,0x15,0xB0,0x02,0x0B,0xBA,0xEE,0x01,0x0A,0x04,0xB0,
+0x02,0x0B,0x06,0x80,0xE1,0x48,0xC7,0x2E,0xFF,0x11,0x22,0x8C,0x02,0x48,0x91,0x32,
+0x00,0x0C,0xBA,0xC6,0xFF,0xFD,0x18,0xB8,0x00,0x0C,0xA0,0xC1,0x01,0x9E,0x1D,0xB0,
+0x08,0x0E,0xD6,0x7E,0xB0,0x01,0x18,0x38,0x00,0x0C,0x3A,0xC1,0xFF,0xA7,0xB9,0xE6,
+0x01,0x11,0x22,0x9C,0x82,0x10,0x14,0x28,0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,
+0x02,0x0A,0x0C,0x30,0xFF,0xFF,0x14,0x38,0x84,0x11,0x1C,0x28,0x02,0x06,0x14,0x30,
+0x83,0x0C,0x18,0x28,0x00,0x00,0x14,0x38,0x84,0x0E,0x1C,0x2C,0x00,0x0C,0xF2,0xDD,
+0x00,0x0C,0x38,0x55,0x02,0x46,0x15,0x30,0x88,0x22,0x40,0xA9,0x01,0x10,0x22,0x1C,
+0x02,0x46,0x45,0x30,0x00,0x00,0x14,0x38,0x8A,0x22,0x06,0xAF,0x02,0x22,0x18,0x30,
+0x02,0xFE,0x15,0x30,0xB1,0x00,0xDA,0x2E,0x80,0x0F,0x40,0xE9,0x22,0x11,0xB8,0x46,
+0x02,0xAC,0x15,0xB0,0x89,0x10,0x38,0x2D,0x02,0x20,0x0C,0xB0,0x02,0xB0,0x41,0xB0,
+0x02,0x12,0x75,0xB3,0x02,0x14,0x4D,0x33,0x02,0x16,0x71,0xB3,0x03,0x18,0x69,0xB3,
+0xFB,0x9F,0x3F,0x8B,0x00,0x11,0x6C,0xDA,0x00,0x0C,0x36,0x45,0x00,0x00,0x44,0x38,
+0x02,0x8A,0x15,0x30,0x89,0x0C,0x1E,0xAF,0x80,0x0C,0x04,0xA8,0xE1,0x8A,0x2B,0xAF,
+0xFF,0x11,0x22,0x8C,0x02,0x8A,0x15,0x33,0x00,0x0C,0x1E,0xC7,0x00,0x00,0x44,0x38,
+0x02,0x8A,0x15,0x30,0x81,0x0C,0x04,0x28,0xE1,0x8A,0x39,0xAF,0xFF,0x11,0x22,0x8C,
+0x02,0x8A,0x15,0x33,0x00,0x0C,0x2E,0xC7,0x00,0x0C,0x42,0xD9,0x01,0x0A,0xB0,0xB3,
+0x0F,0x00,0x18,0x08,0x00,0x11,0x1A,0x88,0x00,0x11,0x02,0x88,0x01,0xD8,0x15,0xB0,
+0x01,0x00,0x0E,0xB0,0x00,0x07,0x52,0x7F,0x02,0x38,0x4C,0xFF,0x02,0x00,0x60,0xB8,
+0x02,0x0C,0x64,0xB0,0x11,0x00,0x00,0x98,0x01,0x00,0x14,0x30,0x00,0xDD,0x47,0x67,
+0x01,0x01,0x22,0x34,0xC0,0x0C,0x5E,0xE7,0x02,0x02,0x41,0x34,0x02,0x04,0x41,0x34,
+0xC0,0x0C,0x6C,0x67,0x02,0x02,0x0D,0x30,0xFF,0xFF,0x04,0x3A,0x02,0x06,0x40,0xB0,
+0xFF,0x21,0x38,0xF5,0xC1,0x11,0x32,0x40,0x02,0x04,0x0D,0x30,0xFF,0xFF,0x08,0x3A,
+0x02,0x06,0x40,0xB0,0xFF,0x21,0x38,0xF5,0xC9,0x11,0x32,0xC0,0xA0,0x00,0x24,0x2C,
+0x02,0x20,0x0C,0xB0,0xC8,0x11,0x76,0xDF,0x02,0x06,0x40,0xB0,0x00,0x0C,0x82,0x4F,
+0xFF,0xFF,0x44,0x3B,0xFF,0x21,0x9E,0x77,0x02,0x04,0xB1,0xB3,0x40,0x49,0x8D,0x7F,
+0xB0,0x00,0xAA,0x2D,0x00,0x0C,0x9A,0xC7,0x02,0xA2,0xAD,0x33,0x02,0x20,0x44,0xB3,
+0xFF,0xFF,0x08,0x3A,0xFF,0xD7,0x99,0xF7,0x00,0x0C,0xAC,0xDF,0x00,0x0C,0x9A,0xC7,
+0xC9,0x11,0x32,0xD8,0x02,0xD8,0x41,0x30,0xFF,0x21,0x84,0x67,0x02,0x06,0x40,0xB0,
+0x10,0x49,0x39,0xFD,0xEF,0x11,0x9C,0x41,0x02,0x20,0xA8,0x33,0x02,0xD6,0x41,0xB0,
+0x02,0xD4,0x05,0xB2,0x02,0xD4,0x41,0xB4,0x02,0x20,0xA8,0x33,0x02,0xD6,0x41,0xB0,
+0x02,0xD4,0x09,0xB2,0x02,0xD4,0x41,0xB4,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+};
+
+static const u8 Lseq[] = {
+0x33,0x11,0x00,0x80,0x00,0x00,0x44,0x38,0x00,0x11,0x00,0x08,0xFD,0x05,0x0A,0x88,
+0x44,0x00,0x12,0x70,0x11,0x00,0x00,0x98,0x33,0x00,0x14,0xE0,0x44,0x11,0x00,0x80,
+0x00,0x0C,0x14,0x40,0x00,0x11,0x00,0x08,0x80,0xE1,0x09,0xE8,0x00,0x0C,0x1E,0x40,
+0x02,0x06,0xC0,0x33,0x02,0x06,0xD0,0xB3,0x02,0x06,0xCC,0x33,0x04,0xE6,0x0D,0x30,
+0x02,0xE0,0x0D,0xB4,0x80,0xE1,0xC3,0x03,0x00,0x0C,0x06,0x40,0x4A,0x00,0x0C,0xB8,
+0x02,0x3C,0x14,0x30,0x81,0x38,0xB0,0xAB,0x02,0x3E,0x14,0xB0,0x81,0x3A,0xB4,0xAB,
+0x22,0x00,0x34,0x60,0x08,0xDA,0x83,0xE8,0x01,0xDA,0x59,0xF8,0x10,0x83,0x14,0x08,
+0x00,0xE3,0x14,0x88,0xFF,0x0A,0x4A,0x78,0x40,0xD9,0x7F,0x78,0x40,0x11,0x72,0x00,
+0xB1,0x00,0x78,0x2A,0x40,0xC8,0x47,0xF8,0x80,0xC8,0x91,0x03,0x10,0x11,0x06,0x81,
+0x01,0x11,0x74,0x84,0xFF,0x80,0x14,0x88,0x00,0xE0,0x14,0x88,0xFF,0x0A,0x7E,0xF8,
+0x40,0xD9,0x7F,0x78,0xC0,0xD9,0x14,0x88,0xC0,0x0A,0x7E,0x70,0x00,0x0C,0xFA,0x45,
+0x55,0x11,0x02,0x00,0x01,0x3B,0x14,0xB0,0x00,0x3F,0x14,0x08,0x01,0x0A,0x86,0x68,
+0x01,0x01,0x22,0xB0,0x40,0xD9,0xFB,0xED,0x80,0xD9,0x67,0x6A,0xFF,0x00,0x6E,0x78,
+0x11,0x00,0x74,0x70,0x22,0x00,0x7A,0xF0,0x00,0x0C,0x8E,0x40,0x20,0xD9,0x1F,0x69,
+0x02,0xDA,0x81,0x68,0xFF,0x11,0x22,0x8C,0x02,0xDB,0x8D,0xE8,0x02,0xDA,0x81,0x68,
+0xFF,0x11,0x22,0x8C,0x80,0xDA,0x85,0xE8,0xFF,0x11,0x22,0x8C,0xA1,0x00,0xE0,0x2C,
+0xA3,0x00,0xAE,0xAA,0xA1,0x00,0x48,0x2E,0xA1,0x00,0x3C,0xAF,0x01,0x01,0x22,0xB0,
+0x55,0x11,0x00,0x80,0xA2,0x00,0x00,0x28,0x02,0x11,0x76,0x04,0xF0,0x04,0x14,0x88,
+0x4C,0x0A,0x14,0x28,0xFF,0x0A,0x2A,0x18,0x01,0x05,0x0A,0x84,0x4A,0x00,0x0C,0xB8,
+0x10,0x45,0xCE,0xE8,0x20,0xCE,0xDB,0x68,0x02,0x54,0x40,0x30,0xB1,0x00,0x8C,0xAC,
+0x00,0x0C,0x18,0x49,0x00,0x00,0x90,0x38,0x18,0x10,0xA1,0xB0,0x55,0x11,0x02,0x00,
+0x01,0x25,0x14,0xB0,0x01,0x11,0x4A,0x80,0x05,0x11,0x00,0x80,0x18,0xE0,0xA3,0x30,
+0x55,0x11,0x00,0x80,0x0A,0x11,0x4A,0x00,0x01,0x01,0x22,0xB0,0x00,0x11,0x94,0x88,
+0x01,0x52,0x14,0xB0,0x01,0x0A,0xC4,0x70,0x00,0x11,0x92,0x88,0x00,0x11,0xA2,0x88,
+0x07,0x0A,0xC4,0xE0,0xFD,0x11,0xC6,0xC0,0xFF,0x11,0xC6,0x40,0x0A,0x11,0x92,0x00,
+0x01,0x0C,0xA2,0xB0,0x02,0x8A,0xC4,0x30,0x80,0x11,0x90,0x84,0x01,0xCA,0xDB,0x78,
+0x00,0x00,0x90,0x38,0x34,0x00,0xA0,0xB8,0xFF,0x00,0xA2,0xB8,0xB2,0x00,0x5E,0x2D,
+0x80,0x11,0x90,0x84,0xB2,0x00,0x6C,0xAD,0x00,0x0C,0x18,0x49,0x00,0x11,0x94,0x88,
+0xA1,0x52,0x1A,0x71,0xB1,0x00,0x9C,0x2C,0x00,0x0C,0x18,0x49,0xC0,0xC8,0x19,0xE9,
+0x40,0x9E,0x19,0x69,0xB2,0x00,0x4E,0xAD,0x03,0x3A,0x1D,0x61,0x00,0x11,0x94,0x88,
+0x01,0x52,0x14,0xB0,0x46,0x0A,0xFA,0xF0,0x39,0x0A,0x08,0x71,0x34,0x0A,0x12,0x71,
+0x80,0x11,0x90,0x84,0x1B,0x48,0x15,0x88,0x13,0x0A,0x1C,0x61,0x02,0x11,0x82,0x5F,
+0xB2,0x00,0x08,0x2D,0x04,0x0C,0x81,0xB2,0xB2,0x00,0x1C,0x2E,0x00,0x0C,0x14,0xC1,
+0x1B,0x48,0x15,0x88,0x13,0x0A,0x1C,0x61,0x01,0x11,0x82,0x5F,0xB2,0x00,0x0E,0x2D,
+0x00,0x0C,0x14,0xC1,0xB2,0x00,0xDE,0x2C,0xB2,0x00,0x4E,0xAD,0x80,0x11,0x90,0x84,
+0x02,0xE4,0xC9,0x03,0xB2,0x00,0x44,0x2F,0x80,0x11,0x90,0x84,0x20,0x11,0x72,0x00,
+0x02,0xE4,0x3F,0x69,0xFF,0xC0,0x3E,0x69,0xFF,0xC1,0x3E,0xE9,0x0F,0xC2,0x3E,0xE9,
+0x00,0x11,0x94,0x88,0x01,0x52,0x14,0xB0,0x01,0x0A,0x34,0xF1,0x05,0x0A,0x3C,0x61,
+0xB1,0x00,0x28,0x2C,0x00,0x0C,0x3C,0xC1,0xA0,0x00,0x0C,0x38,0x20,0x49,0x3B,0x69,
+0xA1,0x00,0x46,0xAB,0xA1,0x00,0x32,0xAB,0x80,0x11,0x7E,0x5F,0x18,0x11,0xB8,0x80,
+0xFD,0xE4,0xC9,0x8B,0xFF,0xFF,0xC4,0x3C,0x80,0x0B,0x49,0xF9,0xB3,0x00,0x66,0xA9,
+0x00,0x0C,0x18,0x58,0x80,0xE4,0x89,0xE9,0x08,0xC8,0x87,0xE9,0x80,0xE5,0x87,0xE9,
+0x0F,0xCB,0x6F,0x69,0x80,0x48,0x93,0x69,0x20,0xE4,0x93,0x69,0x40,0x49,0x87,0xE9,
+0x80,0xC8,0x7D,0xE9,0x80,0xCE,0x61,0xF9,0x20,0xE5,0x91,0x69,0x00,0x0C,0x06,0x40,
+0x20,0xC8,0x87,0xE9,0x02,0xCA,0x7F,0xE9,0x02,0x86,0x80,0x69,0x40,0x4C,0x07,0x78,
+0x02,0x93,0x06,0x78,0x02,0x7F,0x06,0x68,0x00,0x0C,0x86,0x41,0xC0,0x06,0x14,0x38,
+0x8B,0xB0,0x76,0x29,0xC0,0x06,0x60,0xB9,0x80,0x11,0x72,0x00,0x08,0x11,0xCE,0x5D,
+0x08,0x11,0xB8,0x00,0x00,0x0C,0x9E,0x41,0x05,0x11,0x84,0xC1,0x0F,0x11,0x84,0xC1,
+0x40,0xE5,0xCB,0x03,0x24,0x11,0x84,0xC1,0x00,0x0C,0xCE,0xDD,0x00,0x0C,0xA0,0xDF,
+0x80,0x4C,0x9F,0x79,0xB1,0x00,0x98,0xA9,0x00,0x0C,0x52,0xDD,0x00,0x0C,0x5C,0xC2,
+0x00,0x0C,0xA0,0xDF,0x06,0x11,0x18,0x80,0x80,0x0B,0x9D,0xF9,0x28,0x11,0x18,0x80,
+0x20,0xE5,0x9D,0x69,0x29,0x11,0x18,0x00,0x00,0x0C,0xCE,0xDD,0xB1,0x00,0x98,0xA9,
+0x00,0x0C,0x5C,0xC2,0x06,0x11,0xF8,0x03,0x00,0x0C,0xDE,0x5D,0x00,0x0C,0x5C,0xC2,
+0x4A,0x00,0x0C,0xB8,0x02,0x48,0xB9,0x79,0xB1,0x00,0x18,0x2C,0x80,0x48,0xBB,0x69,
+0x12,0x11,0x94,0x00,0x02,0x52,0x44,0x32,0xB1,0x00,0x2A,0xAC,0x00,0x0C,0xBC,0x41,
+0x80,0x11,0x7E,0x5F,0xB1,0x00,0x28,0x2C,0x18,0x11,0xB8,0x80,0xFF,0xFF,0xC4,0x3C,
+0x4A,0x00,0x0C,0xB8,0xF3,0x00,0x0C,0x38,0x00,0x11,0x94,0x88,0x01,0x52,0x14,0xB0,
+0x40,0xCE,0xD7,0xE9,0x80,0xCC,0xD1,0xF9,0x07,0x0A,0xEA,0xF1,0x00,0x0C,0xE4,0xC1,
+0x06,0x0A,0xD4,0xF1,0x16,0x0A,0xE4,0xE1,0xA3,0x00,0xBC,0x28,0x80,0xCC,0xDD,0xF9,
+0x41,0x0A,0xE0,0xE1,0xA1,0x00,0x20,0xAE,0x40,0x0A,0xE0,0x61,0xA3,0x00,0xA2,0x28,
+0x20,0xE4,0xC9,0x03,0xB1,0x00,0x74,0x2A,0x18,0x11,0xB8,0x04,0x40,0xCE,0x9F,0xEF,
+0xFF,0xFF,0xC4,0x3C,0x02,0xE4,0x3F,0x69,0xFF,0xC0,0xE4,0xE9,0xFF,0xC1,0xE4,0x69,
+0x0F,0xC2,0xE4,0x69,0x80,0x7F,0xF6,0xE9,0x07,0x11,0xFA,0x41,0x05,0x01,0xC0,0xBB,
+0x00,0x0C,0x02,0x42,0x01,0x0C,0xF8,0xB3,0xB3,0x00,0x74,0x2B,0x00,0x0C,0xE4,0x49,
+0x08,0x01,0xC0,0x3B,0xB1,0x00,0x64,0xAC,0x40,0xCA,0x95,0x03,0x02,0x06,0x22,0x30,
+0xFF,0x11,0x22,0x8C,0x00,0x0C,0x52,0xDD,0x18,0x11,0xB8,0x80,0x00,0x0C,0x5A,0xC2,
+0xB1,0x00,0xA2,0xAF,0x00,0x0C,0x56,0x4A,0x04,0x0C,0x49,0x31,0x03,0x0A,0x1B,0x62,
+0x02,0x34,0x15,0x30,0x02,0x0A,0x48,0xB1,0xFC,0xFF,0x14,0x38,0x83,0x90,0x48,0xA9,
+0x08,0x11,0x48,0xB1,0x30,0xCE,0x2D,0xFA,0x02,0x11,0x48,0x00,0x0C,0xD4,0x4D,0x31,
+0x04,0xB0,0x4D,0x31,0x00,0x11,0x48,0x08,0x02,0x20,0xFC,0xB3,0xB1,0x00,0xAE,0xA9,
+0x44,0x0A,0xE6,0x2B,0x0C,0x00,0x14,0x38,0x30,0xCE,0x39,0xFA,0x14,0x0A,0x14,0x98,
+0x83,0x90,0x14,0x28,0xB1,0x00,0xEA,0xA9,0x00,0x11,0xE4,0x0B,0x80,0xF2,0xE5,0x2B,
+0x20,0x11,0xB8,0x00,0xB1,0x00,0x06,0x2A,0x02,0x08,0xE1,0xB3,0xC0,0x11,0x8C,0x5F,
+0x02,0xFE,0x41,0xB0,0x00,0xFC,0x89,0x5F,0x02,0xF0,0x79,0x32,0x02,0xF2,0x7D,0x32,
+0xB1,0x00,0x58,0xAC,0x0E,0x11,0x8C,0xDF,0x00,0x0C,0x5A,0xC2,0x18,0x11,0xB8,0x80,
+0xB3,0x00,0x92,0xAB,0xFF,0xFF,0xC4,0xB8,0xB1,0x00,0x6E,0xAC,0xBF,0xCA,0x95,0x8B,
+0x01,0xE4,0x39,0x7D,0xB3,0x00,0x32,0xAB,0x00,0x0C,0x38,0xC5,0x00,0x11,0x00,0x08,
+0x02,0xB4,0x14,0x30,0x81,0xB0,0x14,0x28,0x80,0x0A,0x84,0x6A,0x40,0x0A,0xA8,0xEA,
+0x20,0x0A,0xB6,0xEA,0x10,0x0A,0xBA,0xEA,0x04,0x0A,0xBC,0xEA,0x02,0x0A,0xBE,0x6A,
+0x01,0x0A,0xC0,0x6A,0x08,0x0B,0xC2,0x6A,0x04,0x0B,0xC4,0x6A,0x02,0x0B,0xC6,0xEA,
+0x01,0x0B,0xCA,0xEA,0x08,0xF0,0x60,0xBD,0x23,0x11,0x02,0x80,0x02,0x48,0xE4,0x33,
+0x33,0x11,0x00,0x80,0x00,0x00,0x90,0x38,0x22,0x11,0x00,0x80,0x03,0x11,0x48,0x80,
+0xC4,0x01,0x18,0x38,0xB3,0x00,0x46,0x2A,0x00,0x11,0x48,0x08,0x00,0x0C,0x9C,0x4A,
+0xB2,0x00,0x30,0xAE,0x00,0x0C,0xA4,0x42,0x18,0x11,0x18,0x80,0xB1,0x00,0x8A,0xAA,
+0xC4,0x01,0x1C,0xB8,0xF0,0x11,0xB6,0x5F,0x01,0x01,0x22,0xB0,0x80,0x11,0x60,0x05,
+0x40,0xCE,0xB1,0xEA,0xB1,0x00,0x4A,0x2B,0x00,0x0C,0xB2,0x4A,0x40,0x11,0x60,0x05,
+0xB1,0x00,0x74,0x2A,0x20,0xE4,0xC9,0x03,0x40,0x11,0x60,0x05,0x00,0x0C,0xE8,0xDA,
+0x20,0x11,0x60,0x05,0x10,0x11,0x60,0x05,0x04,0x11,0x60,0x05,0x02,0x11,0x60,0x05,
+0x01,0x11,0x60,0x05,0x08,0x11,0x62,0x85,0x04,0x11,0x62,0x85,0x00,0x0C,0xE8,0xDA,
+0x02,0x11,0x62,0x85,0x02,0x90,0x14,0x30,0x8B,0x10,0xDA,0x2A,0x03,0x0A,0xE0,0x39,
+0xFF,0x11,0x22,0x20,0x10,0x00,0xD0,0xB9,0x00,0x00,0xD4,0xB9,0x01,0x11,0x62,0x01,
+0x00,0x00,0xE0,0xBD,0x02,0x54,0x40,0x30,0xB1,0x00,0x8C,0xAC,0x00,0x0C,0xE6,0xCA,
+0xC0,0x11,0xAE,0x5F,0x20,0xE5,0xCB,0x03,0xB1,0x00,0x4C,0x2B,0x01,0x11,0x62,0x85,
+0x80,0xCE,0xF9,0xEA,0x40,0xCE,0xF3,0xEA,0xB1,0x00,0x48,0xAB,0x00,0x0C,0x9E,0xD7,
+0x20,0xE4,0xC9,0x87,0x18,0x11,0xB8,0x80,0x20,0xE4,0xC9,0x03,0xA1,0x00,0x74,0xAA,
+0x10,0x11,0xB8,0x84,0x95,0x01,0x0C,0xB8,0x08,0x11,0xB8,0x00,0x00,0x00,0x90,0xB9,
+0x80,0x0B,0x09,0xFB,0x3F,0x4E,0x15,0x88,0x01,0x0A,0x08,0xE3,0xA3,0x00,0xC2,0xA9,
+0x01,0x0A,0x15,0xB0,0x00,0x11,0x16,0x88,0x88,0x01,0x18,0xB8,0x83,0x0C,0x0C,0xAC,
+0x00,0x0C,0x38,0xC3,0x00,0x0C,0x40,0xC3,0x00,0x0C,0x36,0x43,0x00,0x0C,0x50,0x43,
+0x00,0x0C,0x50,0x43,0x00,0x0C,0x5C,0x43,0x00,0x0C,0x5C,0x43,0xA3,0x00,0xB0,0xA9,
+0x00,0x0C,0x50,0x43,0xA2,0x00,0xAC,0x2B,0xA2,0x00,0x94,0xAB,0xA2,0x00,0xAC,0x2B,
+0x00,0x0C,0x56,0x43,0x02,0x05,0x0A,0x00,0x01,0x4C,0x31,0xEB,0x00,0x11,0x88,0xDF,
+0xB3,0x00,0xB2,0x2B,0x20,0x13,0x08,0x39,0x05,0x11,0xB8,0x04,0x15,0x11,0x2A,0x80,
+0x06,0x11,0x94,0x81,0x33,0x11,0x95,0x31,0x34,0x11,0x84,0x5F,0x10,0x01,0xBC,0x3C,
+0x06,0x11,0x94,0x81,0x23,0x11,0x95,0xB1,0x24,0x00,0x14,0x38,0x83,0x3C,0x99,0x28,
+0x04,0x11,0x86,0xDF,0x00,0x11,0x86,0x5F,0x10,0x34,0xC1,0x30,0x10,0x01,0xBC,0x3C,
+0x34,0x10,0x95,0x31,0x34,0x11,0x84,0x5F,0x10,0x01,0xBC,0x3C,0x10,0x00,0xBC,0x38,
+0x04,0x3C,0x99,0x30,0x10,0x34,0xC1,0xB4,0x05,0x11,0x94,0x81,0x13,0x11,0x95,0xB1,
+0x04,0x11,0x94,0x31,0x04,0x24,0x95,0xB1,0x08,0x2C,0x95,0x31,0x24,0x11,0x84,0xDF,
+0x10,0x01,0xBC,0x3C,0x00,0x0C,0xFA,0xDA,0x02,0xE4,0x11,0x6F,0x04,0x5D,0x80,0x7B,
+0x30,0xCE,0x7F,0xFB,0x00,0x0C,0x18,0x58,0xB2,0x00,0x32,0x2E,0x00,0x0C,0x88,0xCB,
+0x00,0x0C,0xC6,0xDF,0xB1,0x00,0xCE,0xAC,0x00,0x0C,0x80,0xC3,0xB1,0x00,0xC0,0x2C,
+0x00,0x0C,0x18,0x58,0x40,0xCE,0x07,0x6C,0x80,0xCE,0x89,0x7B,0x08,0x5D,0xA4,0xEB,
+0x0F,0xCB,0x19,0xEC,0x80,0xC8,0x1B,0xEC,0x30,0xCE,0xB1,0xEB,0x04,0xC9,0x17,0x6C,
+0x08,0xC9,0x1D,0x6C,0x01,0x85,0x34,0x6C,0x04,0x85,0x06,0xF8,0xFF,0xC6,0x06,0x68,
+0x02,0x11,0xB6,0x5D,0x00,0x0C,0xC2,0xDD,0x02,0x85,0xA4,0xEB,0x04,0x11,0x0A,0x81,
+0x04,0xC9,0x93,0x03,0x00,0x0C,0x16,0x44,0x04,0x11,0x80,0x32,0x10,0x11,0x7E,0x5F,
+0x08,0xC9,0xAF,0xEB,0x02,0x11,0x0A,0x81,0x00,0x0C,0xE0,0xC3,0x04,0x11,0x4E,0x44,
+0x20,0xC8,0xC7,0xEB,0x02,0xCA,0x21,0x6C,0x02,0x86,0x22,0xEC,0x04,0xC4,0xC6,0x6B,
+0x08,0x5D,0x06,0xF8,0x20,0x84,0x34,0xEC,0x10,0x85,0x06,0xF8,0x10,0x11,0x0A,0x81,
+0x0B,0x0A,0xE1,0x63,0x01,0x3A,0xE1,0x63,0xA2,0x00,0xD4,0x2D,0x04,0x5D,0x14,0x08,
+0x00,0xE4,0xC9,0x83,0x02,0x11,0xB6,0x5D,0x00,0x0C,0xC2,0xDD,0x10,0x85,0xDC,0xEB,
+0x20,0x84,0x34,0xEC,0x08,0x11,0xB6,0x5D,0x04,0xE4,0xDB,0xEB,0x08,0x4C,0xDB,0x6B,
+0xB2,0x00,0x42,0xAE,0x00,0x11,0x56,0xC4,0x10,0x11,0x0A,0x81,0x00,0x0C,0x10,0x44,
+0x80,0xCC,0xE5,0x6B,0xC0,0xC9,0x11,0xEC,0xFF,0x03,0x11,0xF4,0x08,0x48,0xC7,0x0B,
+0x79,0x0B,0xC5,0x0B,0x02,0x02,0x41,0xB0,0x08,0x48,0x17,0x88,0x79,0x0B,0x15,0x88,
+0x02,0xEE,0x41,0x30,0x00,0xE2,0x11,0x64,0x30,0xCE,0xFF,0x7B,0x08,0xCE,0x11,0x7C,
+0x01,0x0B,0x14,0xB0,0x00,0xE3,0x11,0xE4,0x20,0xC8,0x11,0xEC,0x02,0x02,0xDD,0xB3,
+0x06,0x11,0x44,0x5D,0x02,0xEE,0x41,0x30,0x00,0x0C,0x6A,0x43,0x08,0x5D,0x06,0xF8,
+0x00,0x11,0x02,0x88,0xDC,0x01,0x1C,0xB8,0xE0,0x11,0xB6,0xDF,0x01,0x01,0x22,0xB0,
+0x08,0x4C,0x15,0x6C,0x04,0x11,0x56,0x44,0x06,0x11,0x56,0xC4,0x00,0x11,0x4E,0xC4,
+0x0D,0x11,0x26,0xC4,0x0E,0x11,0x26,0xC4,0x80,0xE5,0xA5,0x6B,0x18,0x11,0x26,0x44,
+0x19,0x11,0x26,0xC4,0x40,0xE5,0xCB,0x03,0x25,0x11,0x26,0xC4,0x80,0x0B,0x4B,0xEC,
+0x80,0xCE,0x2D,0x7C,0x16,0x10,0x4B,0xF4,0x00,0x0C,0xCE,0xDD,0x30,0xCE,0x33,0xFC,
+0xB2,0x00,0x42,0xAE,0x02,0x11,0x4E,0x44,0x20,0x01,0x08,0x39,0x1A,0x11,0x38,0xC4,
+0x30,0xCE,0x3F,0xFC,0xB2,0x00,0x42,0xAE,0x00,0x0C,0x46,0x44,0x80,0x0B,0x4B,0x7C,
+0x3F,0x4E,0x15,0x88,0x01,0x0A,0x46,0xF4,0x02,0x0A,0x4A,0x64,0xB3,0x00,0xA2,0xAB,
+0xFF,0x4A,0x6B,0x6B,0x00,0x0C,0x88,0xDF,0x02,0x11,0x4E,0x44,0x01,0x0C,0xD6,0xB3,
+0x08,0x11,0xB6,0x5D,0x01,0xEB,0x19,0xB0,0x20,0xE4,0xC9,0x03,0x00,0x0C,0x44,0x5D,
+0xDF,0x5F,0xBE,0x88,0x04,0x11,0x88,0x81,0x00,0x0C,0x1C,0xC5,0x02,0x20,0x14,0x31,
+0x02,0x20,0xA4,0xB1,0x00,0x0C,0x18,0x58,0x10,0x39,0x06,0xE8,0x00,0x0C,0xC6,0xDF,
+0x80,0x48,0x85,0xEC,0xC0,0x49,0x85,0xEC,0x00,0x11,0x94,0x88,0x10,0x0B,0x77,0x7C,
+0x18,0x10,0xA5,0x30,0x18,0x11,0x24,0x01,0x00,0x0C,0x7A,0x44,0x52,0x11,0xBC,0xDF,
+0x04,0x11,0x24,0x81,0xB1,0x00,0x58,0xAC,0x08,0x11,0xB8,0x00,0x01,0xC0,0x23,0xB0,
+0xFF,0x11,0x22,0x20,0xB1,0x00,0x6E,0x2B,0x02,0xE4,0x11,0x6F,0xB1,0x00,0xC0,0x2C,
+0x00,0x0C,0x18,0x58,0x02,0x05,0x0A,0x00,0x0F,0xCB,0xFD,0xEC,0x80,0xC8,0xFF,0xEC,
+0x80,0x48,0xD3,0xEC,0xC0,0x49,0x11,0xED,0x30,0xCE,0xBD,0x6C,0xFF,0x58,0x9A,0x6C,
+0xC0,0xC9,0xF9,0xEC,0x04,0xC9,0xF9,0x6C,0x08,0xC9,0x01,0x6D,0x01,0x85,0x0A,0x6D,
+0x04,0x85,0xB6,0xFC,0xFF,0xC6,0xB6,0x6C,0x80,0xE4,0xD5,0xEC,0x02,0x11,0xB6,0x5D,
+0x04,0x7F,0xB0,0x6C,0x04,0x11,0x0A,0x81,0x04,0xC9,0x93,0x03,0x00,0x0C,0xF8,0x44,
+0x01,0x11,0xB8,0x00,0x00,0x0C,0x18,0x58,0x00,0x0C,0xC4,0x44,0xFF,0x58,0x06,0xE8,
+0x02,0x11,0x0A,0x81,0x00,0x0C,0xC4,0x44,0xB2,0x00,0xFC,0xAD,0x20,0xC8,0xCB,0x6C,
+0x02,0xCA,0x05,0xED,0x02,0x86,0x06,0x6D,0x80,0xE5,0xCF,0xEC,0x80,0xE4,0xD5,0xEC,
+0x00,0x0C,0x06,0x40,0x00,0x0C,0x8E,0xDF,0x00,0x0C,0xF6,0xC4,0x00,0x0C,0xA0,0xDF,
+0x00,0x0C,0xD4,0xC4,0x06,0x11,0xCE,0xDD,0x30,0xCE,0xDF,0x7C,0xB2,0x00,0xFC,0xAD,
+0x08,0xCE,0xF7,0xFC,0xFF,0x05,0xF7,0x74,0x00,0x0C,0xEA,0x44,0xFF,0x05,0xF7,0x74,
+0x79,0x0B,0x15,0x88,0x02,0x04,0x41,0xB0,0x79,0x0B,0xC5,0x0B,0x02,0xEE,0x41,0x30,
+0x00,0xE2,0xF7,0xE4,0x02,0x04,0xDD,0xB3,0x07,0x11,0x44,0xDD,0x00,0x00,0xC8,0xBB,
+0x02,0xEE,0x41,0x30,0x00,0x0C,0x5E,0x44,0x20,0xE4,0xC9,0x03,0x05,0x11,0x14,0x45,
+0x00,0x0C,0x8E,0xDF,0x01,0x11,0x14,0xC5,0x08,0x11,0x0E,0x45,0x05,0x11,0x0E,0xC5,
+0x80,0xE5,0xF5,0xEC,0x14,0x11,0x0E,0xC5,0x0F,0x11,0x0E,0xC5,0x40,0xE5,0xCB,0x03,
+0x24,0x11,0x0E,0xC5,0x03,0x11,0x0A,0x01,0x10,0x11,0x0E,0x45,0x00,0x0C,0xCE,0xDD,
+0x00,0x0C,0x8E,0xDF,0x03,0x11,0x14,0x45,0x30,0xCE,0x1B,0x7D,0x40,0x9E,0x1B,0xFD,
+0xB2,0x00,0x42,0xAE,0x00,0x0C,0x44,0x5D,0xB1,0x00,0x58,0xAC,0xFF,0xFF,0xDC,0xBB,
+0x20,0xE4,0x2D,0xED,0xFF,0x8E,0x2D,0x6D,0xFF,0xC1,0x2D,0xF5,0x00,0x0C,0x5E,0xDD,
+0xFF,0xEF,0x2D,0xF5,0x02,0xE0,0x0D,0xB4,0x02,0x05,0x0A,0x00,0x7F,0xCA,0x95,0x8B,
+0x01,0xE4,0x35,0x7D,0xB3,0x00,0x32,0xAB,0x02,0x86,0x38,0x7D,0x00,0x11,0xB0,0x88,
+0x40,0xE5,0x3F,0xFD,0x02,0x11,0x0C,0x81,0x02,0xE6,0xCC,0x01,0x00,0x00,0xC8,0xBB,
+0xFF,0xFF,0x40,0xB8,0x00,0x0C,0x22,0x40,0x02,0x0C,0x0C,0x30,0x10,0x11,0x7C,0xDF,
+0x02,0x06,0x18,0x30,0x00,0x0C,0x8C,0x5F,0x00,0x0C,0x18,0x58,0x10,0x49,0x07,0xE8,
+0xFF,0xFF,0xC4,0x3C,0xB3,0x00,0x74,0x2B,0x00,0x0C,0x9E,0xCF,0xB1,0x00,0xA2,0xAF,
+0x00,0x0C,0x5C,0xCD,0x0E,0x11,0x8C,0xC7,0xA3,0x00,0x92,0x2B,0x11,0x11,0x02,0x00,
+0x02,0x05,0x0A,0x00,0x02,0xC0,0x41,0x30,0x02,0x20,0xDC,0x33,0x04,0x4C,0x95,0x6D,
+0x80,0x49,0x7B,0xFD,0xB3,0x00,0x92,0xAB,0x02,0xEE,0x15,0xB0,0x88,0x20,0x72,0x2D,
+0xFF,0xFF,0xDC,0xBB,0x02,0x06,0x41,0x30,0xFF,0x21,0x8A,0xF5,0xFF,0xEF,0x65,0xF5,
+0x00,0x0C,0x68,0xC5,0x02,0x06,0x09,0xB2,0xFF,0xFF,0x0C,0xBA,0x04,0x11,0x7C,0xDF,
+0x02,0x04,0x41,0xB0,0xFF,0x21,0x8A,0xF5,0x04,0x4C,0x69,0xFD,0x02,0x20,0x80,0x33,
+0x00,0x0C,0x8C,0xC5,0x00,0x0C,0xAE,0xDD,0xFF,0xEF,0xA9,0xF5,0x01,0x11,0xF6,0x03,
+0x2F,0x02,0xC0,0x3B,0x00,0x0C,0xA0,0x45,0x00,0x11,0xF6,0x0B,0xB5,0x01,0xC0,0x3B,
+0x02,0x06,0x81,0x33,0xFF,0xFF,0x0C,0xBA,0xFF,0xC1,0xA1,0xE5,0xFF,0xFF,0x84,0x3B,
+0x02,0xEE,0x41,0x30,0x02,0x46,0x45,0x30,0x00,0x00,0xC8,0xBB,0x80,0xCA,0x95,0x03,
+0x01,0x01,0x22,0xB0,0xFD,0x05,0x0A,0x0C,0x02,0xC0,0x41,0x30,0x04,0x10,0x80,0xB7,
+0xFF,0xC1,0x9F,0x77,0x00,0x0C,0xAC,0x5D,0x0B,0x11,0x8C,0xC7,0x01,0x0C,0xD8,0x33,
+0x01,0xEC,0xB9,0x30,0xB0,0x00,0x18,0x28,0x01,0xEC,0xB9,0x30,0x20,0x5D,0x06,0x68,
+0xFF,0x11,0x22,0x8C,0x00,0x0C,0x18,0x58,0x05,0x11,0xF6,0x80,0x02,0x78,0x14,0x30,
+0x00,0x7A,0x14,0x00,0x89,0x10,0x06,0xA8,0xFF,0x11,0x22,0x8C,0x80,0xCE,0xD3,0x7D,
+0x80,0x49,0x9F,0xEF,0x00,0x0C,0x88,0xDF,0x80,0x0B,0x9F,0xEF,0x02,0x08,0xE1,0xB3,
+0x01,0x4D,0xF9,0x33,0x80,0x11,0x7C,0xDF,0x80,0xCE,0xE3,0xED,0x40,0x9E,0x9F,0xEF,
+0x40,0x9E,0x3D,0x03,0x02,0x20,0xFC,0xB3,0xB1,0x00,0xAE,0xA9,0x02,0x0C,0x1C,0x98,
+0x80,0xCE,0xF1,0x7D,0xF0,0x11,0x26,0x00,0x02,0xF0,0x27,0x30,0x00,0x0C,0xF4,0xC5,
+0xF1,0x11,0x26,0x80,0x02,0x22,0x26,0xB0,0x01,0xFC,0x27,0x30,0x00,0x0A,0x8C,0x5F,
+0x02,0xFE,0x41,0x34,0xC0,0xD9,0x14,0x88,0x40,0x0A,0x0A,0xF6,0xC0,0x0A,0x0A,0x76,
+0xFF,0x0A,0x04,0x7E,0x40,0x11,0x72,0x84,0x30,0xCB,0x03,0x7E,0x40,0xCB,0x97,0x03,
+0xBF,0x3D,0x7A,0x0C,0x01,0x03,0x0C,0xB8,0x01,0xCD,0x9F,0xEF,0x30,0xCB,0x9F,0x6F,
+0x20,0xD9,0xFE,0xEE,0x00,0x11,0xB2,0x89,0xF0,0xD8,0x14,0x08,0x10,0x0A,0x28,0xF6,
+0x20,0x0A,0x2C,0x76,0x90,0x0A,0x20,0xF6,0x80,0x0A,0x24,0xF6,0x00,0x0C,0xFC,0x46,
+0x08,0xCF,0x2F,0x6E,0x00,0x0C,0xFC,0x46,0x02,0xCF,0x2F,0x6E,0x00,0x0C,0xFC,0x46,
+0x80,0xCF,0x2F,0x6E,0x00,0x0C,0xFC,0x46,0x40,0xCF,0xFD,0xFE,0x0F,0xD8,0x14,0x08,
+0x08,0x0A,0x38,0x76,0x09,0x0A,0x00,0x67,0x55,0x11,0x00,0x80,0x01,0x43,0x01,0x6F,
+0x00,0x11,0x00,0x08,0x44,0xC6,0x0F,0xA8,0x01,0x07,0x14,0xB0,0x00,0x00,0x44,0x38,
+0x00,0xAF,0xFB,0x7E,0x02,0xC8,0x91,0x03,0x01,0xC8,0x85,0x7E,0x11,0x11,0x00,0x80,
+0x08,0xE4,0x63,0xEE,0x01,0x96,0x17,0x30,0x01,0x97,0x15,0x30,0x16,0x11,0xB2,0x81,
+0x01,0xD8,0x1A,0xB0,0x01,0xD8,0x18,0x30,0x8A,0x0C,0x5C,0x2E,0xB3,0x00,0x6E,0x2A,
+0x80,0x0F,0x0E,0xEF,0x00,0x0C,0x62,0xC6,0xA8,0x00,0x18,0xB8,0xB3,0x00,0xB6,0xAB,
+0xFF,0x0A,0x0E,0xFF,0x00,0x0C,0xC2,0x5F,0x84,0x01,0x18,0xB8,0xB3,0x00,0xB6,0xAB,
+0x01,0x0A,0x84,0x66,0x00,0x11,0xB2,0x89,0xF0,0xD8,0xB0,0x8B,0x80,0xD8,0xA5,0x8B,
+0x70,0xD8,0xB1,0x8B,0x70,0x0B,0x15,0x88,0x00,0xD8,0x85,0x66,0x80,0x80,0x7D,0xFE,
+0xFF,0xD2,0x85,0xEE,0x00,0x0C,0x7E,0x46,0x80,0xD2,0x85,0xE6,0x20,0xD8,0x85,0x76,
+0x11,0x11,0x00,0x80,0xB1,0x00,0xBE,0x2C,0x00,0x11,0xB2,0x89,0xF0,0xD8,0x14,0x08,
+0x80,0x0A,0xB0,0x0B,0x30,0x0A,0x14,0x08,0x80,0xD8,0x91,0x6E,0x80,0x0A,0x14,0x00,
+0x01,0xD8,0x98,0x6E,0x55,0x11,0x00,0x80,0x01,0x43,0x99,0x6E,0x08,0x0A,0x14,0x00,
+0x00,0x11,0x00,0x08,0x01,0x0A,0xA4,0xB3,0x80,0x0A,0xA0,0xEE,0xA3,0x00,0x00,0xA8,
+0x01,0xD8,0x46,0xB0,0x01,0xD8,0x44,0x30,0x00,0x00,0x14,0x38,0x8A,0x22,0xFC,0x2E,
+0x02,0x22,0x18,0x30,0x02,0xEE,0x15,0xB0,0xB3,0x00,0x6E,0x2A,0x80,0x0F,0xFC,0x7E,
+0xFE,0x8F,0xFD,0x66,0x84,0x01,0x18,0xB8,0xB3,0x00,0xB6,0xAB,0x01,0x0A,0xFC,0x66,
+0x20,0xD2,0xC5,0x7E,0x20,0x9E,0xFB,0xEE,0x40,0x9D,0xC1,0x7E,0x02,0x9E,0xFD,0x7E,
+0xB2,0x00,0x20,0xAF,0x00,0x0C,0xD8,0x46,0x02,0xC9,0xD9,0x6E,0x04,0x9D,0xD9,0x7E,
+0xB3,0x00,0xDA,0xAB,0x04,0x11,0x14,0x30,0x01,0xA8,0x19,0x30,0x01,0xA9,0x15,0xB0,
+0xB3,0x00,0x6E,0x2A,0x80,0x0F,0xD8,0x7E,0xB3,0x00,0xEA,0xAB,0x00,0x0C,0xFA,0x46,
+0x00,0x11,0x7E,0x0B,0x08,0xD2,0x41,0x09,0x01,0xD2,0x15,0xB0,0xB1,0x00,0xE6,0x28,
+0x34,0x11,0xBA,0xDF,0xB1,0x00,0xBA,0xAA,0xB1,0x00,0x08,0xA9,0xB0,0xCC,0x15,0x08,
+0x10,0x0A,0xEC,0xE6,0xB3,0x00,0x72,0xA9,0xFE,0xC8,0x91,0x8B,0xB3,0x00,0x32,0xAB,
+0x80,0xCA,0xF5,0xEE,0xA3,0x00,0x64,0xAA,0xB1,0x00,0x64,0xAC,0xB6,0x03,0xC0,0xBB,
+0x40,0xCA,0x95,0x87,0x4F,0x11,0x02,0xC7,0x44,0x11,0x02,0x47,0x51,0x11,0x02,0xC7,
+0x41,0x11,0x02,0x47,0xFD,0xC9,0x93,0x8B,0x00,0x0C,0xBA,0x5F,0x80,0xCA,0x0F,0xFF,
+0xBF,0x3D,0x7A,0x88,0xBA,0x03,0xC0,0xBB,0x40,0xCA,0x95,0x87,0xFD,0xC8,0x91,0x0F,
+0x00,0x0C,0x18,0x58,0x02,0x02,0x14,0x38,0x81,0xC8,0x15,0xA8,0x02,0x0B,0x26,0x6F,
+0x02,0x0A,0x2C,0xEF,0x10,0xE4,0x55,0x6F,0x0F,0xCB,0x33,0x6F,0x80,0xC8,0x35,0xEF,
+0xEB,0x11,0x8A,0x5F,0x00,0x0C,0x06,0xD0,0x03,0x11,0x36,0xC7,0xFD,0xE4,0xC9,0x8B,
+0xFF,0xFB,0x6F,0x7B,0x00,0x0C,0x86,0x44,0xB3,0x00,0xEA,0xAB,0xFB,0x9E,0x3D,0x8B,
+0x00,0xFB,0x4F,0xC4,0x09,0x11,0x36,0xC7,0x12,0x11,0x36,0xC7,0x01,0x0C,0xF4,0xB3,
+0x00,0x0C,0xC2,0x5F,0xB1,0x00,0x74,0x2A,0x22,0x11,0x02,0x00,0xE8,0x11,0xB8,0xDF,
+0x01,0x01,0x22,0xB0,0xB1,0x00,0xBA,0xAA,0x00,0x0C,0x54,0xCF,0x00,0x0C,0x18,0x58,
+0x80,0xC8,0x55,0xEF,0x22,0x11,0x02,0x00,0xEB,0x11,0x8A,0x5F,0x01,0x01,0x22,0xB0,
+0x00,0x0C,0x06,0xD0,0x01,0x9E,0x3D,0x03,0xB3,0x00,0xEA,0xAB,0xB2,0x00,0x6E,0xAF,
+0xFD,0x05,0x0A,0x88,0x08,0xFB,0x4F,0x44,0x10,0xC7,0x9F,0x7F,0x10,0x45,0x9E,0x6F,
+0x20,0xCE,0x9F,0xEF,0x02,0xFE,0x15,0x30,0x83,0x10,0xFC,0xAB,0x89,0x10,0x9E,0xAF,
+0x02,0xFC,0xFD,0xB3,0x30,0x11,0xBA,0x47,0x00,0x0C,0x18,0x58,0x80,0xCA,0x07,0x68,
+0xB3,0x00,0x64,0x2A,0x00,0x0C,0x5C,0xC2,0x00,0x0C,0x18,0x58,0x80,0xCA,0x07,0x68,
+0xB2,0x00,0x6E,0xAF,0x00,0x0C,0x5C,0xC2,0xA3,0x00,0xDE,0x2A,0xA3,0x00,0xE2,0x2A,
+0xA3,0x00,0xF2,0xAA,0xA3,0x00,0x04,0x2B,0xA3,0x00,0x54,0xAA,0xA3,0x00,0x4E,0x2A,
+0xA3,0x00,0xBE,0x2A,0xA1,0x00,0x2C,0x2A,0xA3,0x00,0x34,0xAA,0x20,0xE4,0xC9,0x03,
+0x80,0xE4,0x9F,0x6F,0x08,0x5D,0x9E,0x6F,0x02,0x11,0xB6,0x5D,0x05,0x11,0xB8,0x80,
+0x80,0x11,0xB8,0x00,0x00,0x0C,0x18,0x58,0x80,0xE4,0x07,0xF8,0xFF,0x11,0x22,0x8C,
+0x80,0xE4,0x9F,0x6F,0x08,0x5D,0x9E,0x6F,0xA0,0xE5,0xA9,0x6F,0xC0,0x11,0xAE,0x5F,
+0xB0,0x00,0x18,0x28,0x80,0xE4,0x07,0xF8,0xFF,0x11,0x22,0x8C,0xFF,0x00,0xB4,0xEF,
+0x00,0x11,0x86,0x09,0x40,0x11,0x90,0x00,0x01,0x0C,0xB8,0xB4,0xA1,0x00,0x18,0xAA,
+0xA1,0x00,0x16,0x2A,0xA1,0x00,0x7E,0xAA,0xA2,0x00,0xDA,0xAB,0xFE,0xBA,0x74,0x89,
+0x02,0x92,0x71,0x31,0xFE,0xBA,0x74,0x89,0x02,0xB8,0x2C,0x37,0x02,0x20,0xC4,0xB4,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x02,0x05,0x0A,0x00,0x01,0xCB,0x2A,0xE8,0xEF,0x11,0x2C,0xDA,0x00,0x0C,0x2A,0x50,
+0xEF,0x11,0x52,0xDA,0x02,0xCB,0x97,0x03,0xB3,0x00,0x32,0xAB,0x55,0x11,0x02,0x00,
+0x01,0x48,0x15,0xB0,0x01,0x01,0x22,0xB0,0xFF,0x0A,0x2A,0xE8,0x30,0xCB,0x2B,0xE8,
+0x44,0x11,0x02,0x00,0x9A,0x07,0xC0,0xBB,0x01,0x01,0x22,0xB0,0xFD,0x05,0x0A,0x88,
+0x00,0x0C,0xAE,0x59,0x02,0x0C,0x1C,0x98,0x20,0xC6,0x27,0x00,0x00,0x11,0x26,0x88,
+0x00,0x0A,0xAC,0xD9,0xFD,0x05,0x0A,0x88,0x00,0x04,0xC0,0xBB,0x02,0x05,0x0A,0x00,
+0x71,0x04,0x0C,0xB8,0x01,0xCD,0xE1,0xF8,0x80,0xCA,0x61,0xEC,0x0F,0xCB,0x93,0xE8,
+0x10,0x45,0xD2,0x68,0x40,0xC8,0x81,0x68,0x80,0xC8,0x75,0xE8,0x10,0xC8,0x6D,0xE8,
+0x40,0xCE,0x9B,0xE8,0x20,0xCE,0xA7,0xE8,0x04,0xC8,0x5B,0xE8,0xFF,0x8E,0x55,0x68,
+0xFF,0xC1,0xDB,0x60,0x40,0x83,0x60,0xEC,0x01,0xC8,0x55,0x68,0x08,0xC8,0x55,0x68,
+0x80,0xCC,0x55,0x78,0x40,0xC9,0x61,0x7C,0x5A,0x11,0x7C,0x5A,0xB1,0x00,0x9E,0xAF,
+0x01,0x11,0xE4,0x81,0x08,0xC8,0x61,0xE8,0x20,0xC9,0x61,0x7C,0x00,0x0C,0x78,0x40,
+0x02,0x11,0xE4,0x81,0xB1,0x00,0x9E,0xAF,0x00,0x0C,0x12,0xD9,0x00,0x0C,0x5E,0x5A,
+0x20,0xC8,0x95,0x68,0xE4,0x11,0x16,0x42,0x20,0xC8,0x95,0x68,0xE7,0x11,0x2C,0x5A,
+0x00,0x0C,0x60,0x54,0x00,0x0C,0x78,0x40,0x40,0x39,0x78,0x78,0x40,0x11,0x72,0x00,
+0x00,0x0C,0x12,0xD9,0x00,0x0C,0x74,0xDA,0x80,0xC8,0x89,0xE8,0xE8,0x11,0x16,0x42,
+0x80,0xC8,0x89,0xE8,0xEB,0x11,0x2C,0x5A,0x00,0x0C,0x60,0x54,0x01,0x9E,0x3D,0x03,
+0x03,0xC8,0x91,0x0B,0xF0,0x08,0x04,0xB9,0x03,0x11,0x0E,0x81,0x3F,0xC9,0x93,0x0B,
+0x00,0x0C,0x94,0xC0,0x00,0x0C,0x12,0xD9,0x40,0xCA,0x61,0xEC,0xB0,0x00,0xB0,0xAD,
+0x00,0x0C,0x3E,0x41,0x80,0xCC,0xA1,0x68,0x10,0xC9,0x61,0x7C,0x00,0x0C,0x64,0xC0,
+0x40,0xCA,0x61,0xEC,0x10,0xC9,0x79,0x68,0x00,0x0C,0x64,0xC0,0x80,0x83,0xCC,0x68,
+0x10,0xCA,0xCD,0x68,0x02,0xCA,0xCF,0xE8,0x20,0xC8,0xB7,0x68,0xFF,0xC1,0xDB,0x60,
+0x01,0x9F,0xBD,0x78,0xB2,0x00,0x02,0x2E,0x00,0x0C,0x60,0x4C,0x02,0xA1,0x42,0x01,
+0x04,0xA1,0xB8,0xF8,0x00,0x0C,0x64,0xC0,0x02,0xA1,0x42,0x01,0x80,0x83,0xCC,0x68,
+0x13,0x00,0xE0,0xB9,0xFF,0x11,0x22,0x20,0xFF,0xE8,0xCC,0x68,0x04,0x86,0xCC,0x68,
+0x04,0xA1,0xBE,0xF8,0x00,0x0C,0x64,0xC0,0xFD,0xA1,0x42,0x0D,0xB2,0x00,0xE4,0xAD,
+0x00,0x0C,0x78,0x40,0xB2,0x00,0x02,0x2E,0x00,0x0C,0x92,0x50,0x02,0xCA,0xDD,0xE8,
+0xFF,0xC1,0x61,0xF4,0xA0,0x00,0x5E,0x2D,0xB2,0x00,0xE4,0xAD,0x00,0x0C,0x92,0xC0,
+0xA0,0x00,0xB0,0x2D,0x00,0x04,0xC0,0xBB,0xA0,0x00,0x06,0xA8,0x30,0x0A,0x18,0x08,
+0xFF,0x0C,0xF6,0xF8,0x20,0x0C,0xF8,0x70,0x30,0x0C,0xFE,0xF0,0x20,0x11,0x18,0x00,
+0x80,0x0A,0x02,0xE9,0x01,0xC8,0x03,0x79,0xA3,0x00,0x18,0x29,0x10,0x11,0x02,0xC1,
+0x08,0x11,0x0C,0x59,0x20,0x9E,0x3D,0x03,0x00,0x0C,0x00,0xC1,0x00,0x11,0x0C,0xD9,
+0x40,0x11,0x02,0xC1,0xB2,0x00,0x68,0xAF,0x01,0x0A,0x40,0x31,0x01,0x0A,0x60,0xFC,
+0x02,0xA0,0x98,0xB3,0x01,0x45,0x9C,0x37,0x11,0x11,0x02,0x00,0x01,0x0C,0x96,0x30,
+0x01,0x01,0x22,0x34,0x01,0xA1,0x60,0x7C,0xF5,0x45,0x8A,0x08,0x10,0x45,0x60,0xEC,
+0x20,0x45,0x26,0x69,0x80,0xA0,0x22,0x69,0xF7,0x11,0x52,0xDA,0x80,0x45,0x22,0x79,
+0x02,0xF4,0x45,0xB1,0x00,0x0C,0x2A,0x59,0x01,0x11,0x0C,0x41,0x0A,0x11,0x0C,0xD9,
+0x1F,0x11,0x32,0xD9,0x08,0xA0,0x14,0x88,0x02,0x0A,0x14,0x00,0x00,0x11,0x16,0x88,
+0x02,0x0A,0x40,0xB5,0x11,0x11,0x02,0x00,0x01,0x0C,0x90,0x30,0x01,0x01,0x22,0x34,
+0xFF,0x11,0x32,0x59,0xF7,0xA0,0x40,0x89,0x01,0x11,0x0C,0x41,0x02,0x05,0x0A,0x00,
+0x04,0x9E,0x45,0xF9,0xF9,0x9E,0x3D,0x0B,0xDF,0x9E,0x3D,0x8B,0xB3,0x00,0xEA,0xAB,
+0x03,0x11,0x90,0xB3,0x10,0x45,0x52,0x69,0x00,0x00,0x98,0xBB,0x00,0x11,0x9C,0x0B,
+0x00,0x0C,0x60,0xC1,0x00,0x11,0x02,0x88,0xF7,0x5E,0xBC,0x88,0x40,0x11,0x90,0x00,
+0x00,0x11,0x86,0x09,0x01,0x01,0x22,0xB0,0xFE,0xCD,0x9B,0x8B,0xF5,0xCE,0x9D,0x0B,
+0x40,0x3D,0x7A,0x00,0xFF,0xE0,0xC0,0x81,0xB3,0x00,0x94,0x2A,0xB3,0x00,0x32,0xAB,
+0xFD,0x05,0x0A,0x0C,0xFD,0x4D,0x9B,0x8A,0xB0,0x00,0x5C,0xAF,0xB3,0x00,0x98,0x29,
+0x30,0x45,0x74,0xF9,0x00,0x0C,0x7E,0xD9,0x55,0x11,0x02,0x00,0x1D,0x11,0xAC,0x02,
+0x02,0x4D,0x9B,0x02,0x02,0x5B,0xB7,0x02,0x01,0x01,0x22,0x34,0x22,0x11,0x02,0x00,
+0x02,0x11,0x4A,0x80,0xF3,0x11,0x4C,0x5A,0x00,0x0C,0x94,0xD1,0xC4,0x01,0x1C,0xB8,
+0xF3,0x11,0x2E,0xDA,0x00,0x0C,0x90,0x51,0xB2,0x00,0x30,0xAE,0x00,0x0C,0x92,0x41,
+0x08,0x44,0x94,0xE9,0xF3,0x11,0x52,0x5A,0x00,0x11,0x4A,0x88,0x01,0x01,0x22,0x34,
+0xB0,0x00,0x18,0x28,0x80,0x5D,0xE4,0xF8,0xFF,0x4D,0xA5,0xE9,0x80,0x0B,0xA3,0x79,
+0x18,0x11,0xAC,0xC1,0x10,0x11,0xAC,0x41,0x0F,0x11,0xAC,0xD9,0x30,0xCE,0x61,0x7C,
+0x40,0x9E,0x61,0xFC,0xA2,0x00,0x42,0x2E,0xA3,0x00,0x34,0xAA,0x13,0x11,0xD6,0x83,
+0x02,0x11,0xB6,0xC1,0x17,0x11,0xD6,0x03,0x01,0x11,0xB6,0xC1,0x01,0x0C,0xD8,0x33,
+0xB0,0x00,0x18,0x28,0x02,0x05,0x0A,0x00,0x04,0x3A,0xE4,0x78,0x01,0xEB,0x69,0x30,
+0x03,0x11,0x6A,0xB0,0xFD,0x05,0x0A,0x88,0xB0,0x00,0x18,0x28,0x01,0xEC,0x49,0x30,
+0xFF,0xCE,0xCF,0x69,0x00,0x11,0x48,0x08,0x00,0x0C,0xE4,0x40,0xC8,0xCC,0x19,0x98,
+0x01,0x11,0x1A,0x80,0x01,0x12,0x16,0xB0,0x11,0xCC,0x15,0x28,0x03,0x0C,0x98,0x8B,
+0xFF,0xCE,0x9D,0x9B,0xC0,0x0A,0x18,0x98,0x02,0x0C,0x1C,0xB0,0x02,0x12,0x40,0xB0,
+0xFF,0xFF,0x26,0xB8,0x00,0x11,0x48,0x08,0x01,0x0B,0x14,0xB0,0x44,0x0A,0x18,0xA8,
+0x02,0x0C,0x1C,0x34,0x02,0x0C,0x0C,0x30,0x08,0x0C,0x18,0x18,0x02,0x12,0x1C,0xB0,
+0x02,0x0A,0x0C,0x30,0x82,0x10,0x14,0x28,0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,
+0x83,0x0E,0x1C,0x28,0x02,0x06,0x14,0x30,0x80,0x0F,0x02,0x7A,0xFE,0x0C,0x18,0x18,
+0x02,0x12,0x14,0x30,0x02,0x06,0x18,0x30,0xFF,0x11,0x22,0x8C,0x08,0x0C,0x1C,0x98,
+0x01,0x0D,0x1E,0xB0,0x02,0x0A,0x26,0xB0,0x00,0x00,0x26,0xB8,0x10,0x12,0xC0,0x30,
+0xF0,0x0C,0x18,0x98,0x20,0x00,0xBC,0x38,0x49,0x11,0xB8,0x84,0xD4,0x01,0x1C,0x38,
+0x01,0x0E,0x1A,0x30,0x01,0x0C,0x1C,0xB0,0x01,0x0D,0x18,0xB0,0x03,0x11,0x48,0x80,
+0x00,0x0C,0x5A,0xDA,0xB3,0x00,0xCE,0x2A,0x04,0x12,0x50,0x30,0x04,0x28,0x26,0xB0,
+0x00,0x00,0x48,0x38,0xA3,0x00,0xD8,0x2A,0xD4,0x01,0x1C,0x38,0x03,0x11,0x48,0x80,
+0x00,0x0C,0x5A,0xDA,0x11,0x12,0x22,0xA8,0x00,0x0C,0x4A,0xD2,0x02,0x0C,0x0C,0x30,
+0x02,0x0E,0x18,0xB0,0x02,0x05,0x0A,0x00,0x04,0x12,0x50,0x30,0x02,0x06,0x18,0x30,
+0xFC,0x0C,0x18,0x98,0x04,0x12,0x50,0x30,0xFF,0x11,0x22,0x20,0x11,0x2B,0x22,0xA8,
+0xFD,0x05,0x0A,0x88,0x00,0x00,0x48,0xBC,0x00,0x0C,0x5A,0xDA,0x11,0x12,0x22,0xA8,
+0x00,0x11,0x4A,0x0C,0x00,0x0C,0x5A,0xDA,0x02,0x0C,0x1C,0xB0,0x00,0x11,0x26,0x88,
+0x00,0x11,0x4A,0x0C,0x02,0x11,0x4A,0x80,0x01,0x11,0x1A,0x04,0x10,0x30,0x14,0xB8,
+0x00,0x0C,0x7C,0x5C,0x20,0xCE,0x6F,0x7A,0x20,0x9D,0x6F,0x7A,0xB2,0x00,0x02,0x2E,
+0x00,0x0C,0x6E,0xCA,0x04,0x9E,0x3D,0x03,0x28,0x11,0x70,0x42,0x29,0x11,0x70,0xC2,
+0x00,0x0C,0x82,0xDA,0x00,0x0C,0x38,0x41,0x40,0xC0,0x14,0xB8,0x00,0x0C,0x7C,0x5C,
+0x1C,0x11,0x86,0xDA,0x00,0x0C,0x38,0x41,0x04,0xC8,0x91,0x03,0x01,0x0C,0x14,0x30,
+0x10,0x11,0x92,0xC2,0x01,0x0C,0x14,0x30,0x30,0x11,0x92,0x42,0x01,0x0C,0x14,0x30,
+0x60,0x11,0x92,0x42,0x01,0x0C,0x14,0x30,0x20,0x11,0x92,0xC2,0x01,0x0C,0x14,0x30,
+0x24,0x11,0x92,0x42,0x01,0x05,0x16,0xB0,0x02,0x05,0x0A,0x00,0x02,0xCA,0x9D,0xEA,
+0xF0,0x44,0x9E,0x6A,0x08,0x44,0xA2,0x7A,0x08,0x11,0x88,0x00,0x00,0x0C,0xBA,0x5A,
+0x00,0x0C,0xB8,0x4A,0xFF,0x21,0xAC,0xF2,0x81,0x0A,0xAD,0xE2,0x04,0x10,0x81,0xB0,
+0x01,0x0D,0x89,0x30,0x00,0x0C,0xB8,0xC2,0x01,0x0A,0xB6,0x31,0x04,0xDC,0x80,0x30,
+0x30,0xCE,0xB5,0x7A,0x02,0x0C,0xB6,0xC2,0x01,0x0C,0x18,0x00,0x01,0x0C,0x88,0x30,
+0x01,0x0B,0x0A,0x34,0x08,0x44,0xB0,0x7C,0x0B,0xCB,0xC7,0x6A,0x55,0x11,0x02,0x00,
+0x40,0x4E,0x1B,0x88,0x01,0x01,0x22,0xB0,0xFF,0x0D,0xBA,0x7A,0x08,0x11,0x88,0x00,
+0x01,0x10,0x22,0x1C,0x4A,0x00,0x0C,0xB8,0x01,0x39,0xF8,0xEA,0x02,0x39,0x60,0xFC,
+0x04,0x67,0x14,0x08,0x80,0x5B,0xDA,0x6A,0x08,0x68,0xB0,0x33,0x30,0x67,0xA4,0x0B,
+0x00,0x0C,0xE4,0xC2,0x08,0x53,0xB0,0xB3,0x07,0x53,0x22,0x30,0x30,0x53,0xA4,0x8B,
+0x08,0xD8,0xD1,0x30,0x00,0xD2,0xCF,0x80,0xFF,0x67,0xCE,0x08,0x80,0x11,0xCC,0x00,
+0x05,0x11,0xB4,0x80,0x01,0x11,0x4A,0x80,0x22,0x0A,0x1C,0x28,0xE0,0x0E,0x1C,0x18,
+0x01,0x11,0x1E,0xA0,0x08,0xD8,0x27,0x30,0x07,0x11,0x26,0xB0,0x01,0xD2,0x27,0xB4,
+0xFF,0x65,0x02,0x7B,0xBF,0xE4,0xC9,0x8B,0x0F,0x53,0xC0,0xB0,0x01,0x53,0xFA,0x33,
+0x00,0x0C,0x0A,0x43,0x80,0x5B,0x0E,0x7B,0x40,0xE4,0x0F,0xEB,0x40,0xE4,0xC9,0x03,
+0x0F,0x11,0xC0,0xB0,0x01,0xFD,0xC1,0x30,0x01,0x11,0x72,0x84,0x10,0x53,0xC0,0x30,
+0x01,0x11,0x72,0x84,0x4A,0x00,0x0C,0xB8,0x20,0x11,0xBC,0xDC,0x00,0x0C,0xAC,0x5B,
+0xFF,0x00,0x60,0xEC,0x30,0xCE,0x61,0x7C,0x40,0x11,0x90,0x84,0x4A,0x00,0x0C,0xB8,
+0x01,0x48,0x47,0x7B,0x88,0x49,0x33,0xEB,0x20,0x48,0x31,0x6B,0xB3,0x00,0x74,0x2B,
+0x00,0x0C,0x32,0x4B,0x00,0x0C,0x6E,0xDB,0xA2,0x00,0xC0,0xBB,0x40,0xCA,0x95,0x87,
+0x20,0x11,0xBA,0xDC,0x00,0x0C,0x6A,0x5B,0x1B,0x48,0x15,0x88,0x01,0x0A,0x60,0xE4,
+0x04,0x11,0x80,0x32,0xB2,0x00,0x16,0x2D,0x80,0x4C,0x61,0xFC,0xB3,0x00,0x74,0x2B,
+0x00,0x0C,0x60,0x4C,0xC5,0x00,0xC0,0x3B,0x40,0xCA,0x95,0x87,0x80,0x11,0xBC,0xDC,
+0x00,0x0C,0x6A,0x5B,0x80,0xCE,0x51,0x7B,0x80,0x49,0xB1,0xEC,0x00,0x0C,0x52,0xC3,
+0x40,0x9E,0xB1,0xEC,0x00,0x0C,0x64,0x5C,0x80,0xE1,0x69,0x7B,0xFF,0x21,0x64,0xF3,
+0xB3,0x00,0x74,0x2B,0x00,0x0C,0x60,0xD3,0x00,0x0C,0x6E,0x5C,0x01,0x11,0x22,0x9C,
+0x00,0x0C,0x2C,0xDB,0x01,0x10,0x22,0x1C,0xD1,0x00,0xC0,0x3B,0x40,0xCA,0x95,0x03,
+0x01,0x10,0x22,0x1C,0x00,0x0C,0xB4,0xDC,0x18,0x11,0xB8,0x04,0x04,0x40,0x99,0xB0,
+0x04,0x0C,0xE1,0x30,0x04,0x24,0x31,0x31,0x20,0x10,0xBC,0xB8,0x11,0x00,0x80,0xF3,
+0x20,0x0B,0x85,0x7B,0xF0,0x04,0x14,0x88,0x60,0x0A,0x84,0x73,0x20,0x11,0x86,0x43,
+0x01,0xCD,0x85,0xEB,0x05,0x11,0x86,0xC3,0x00,0x11,0x86,0xC3,0x01,0x05,0x14,0x30,
+0x82,0x05,0x0A,0x80,0x30,0x50,0xC1,0x30,0x01,0x0C,0xB8,0x30,0x01,0x0A,0x0A,0x30,
+0x40,0xE4,0xC9,0x03,0x20,0x0C,0x96,0x63,0x02,0xC3,0x86,0x01,0x40,0x61,0x60,0xEC,
+0x5F,0x01,0x18,0xB8,0x80,0x5F,0x9F,0xEB,0x6F,0x01,0x18,0xB8,0x04,0x12,0x1C,0x08,
+0x22,0x0E,0x1C,0xA8,0xE0,0x0E,0x1C,0x18,0x01,0x11,0x1E,0xA0,0x01,0x11,0x4A,0x80,
+0x10,0x12,0x26,0xB0,0x00,0x11,0x4A,0x0C,0x40,0x61,0xB2,0xFB,0x30,0x60,0xA0,0x32,
+0x00,0x0C,0xC4,0xC3,0x20,0x60,0xA0,0xB2,0x80,0x6F,0xDF,0x02,0x04,0x6F,0x19,0x08,
+0x22,0x0C,0x18,0xA8,0xE0,0x0C,0x18,0x18,0x01,0x11,0x1A,0x20,0x01,0x11,0x4A,0x80,
+0x10,0x12,0xE0,0x32,0x00,0x11,0x4A,0x88,0x11,0x00,0xDE,0x73,0x30,0xCE,0xDF,0xFB,
+0x0C,0x3F,0xD5,0x7B,0x01,0x7F,0xD4,0xFB,0x0C,0x3F,0xB1,0x0B,0x2E,0xD8,0xB1,0xAB,
+0x03,0x11,0xB2,0xB3,0x04,0xD8,0xE1,0x30,0x03,0x3F,0xDF,0x7B,0x01,0x93,0xDE,0x7B,
+0x03,0x3F,0xB1,0x0B,0x03,0x11,0xB2,0xB3,0x04,0xD8,0x99,0x30,0x04,0x70,0x18,0x32,
+0x04,0x98,0x48,0x32,0x04,0x4C,0x80,0xB2,0x11,0x00,0x02,0x74,0x01,0x7F,0xEC,0x7B,
+0x20,0x11,0xBA,0xDC,0x00,0x0C,0xB4,0xDC,0xFF,0xFF,0xC4,0xB8,0x00,0x0C,0x62,0x5C,
+0x01,0x93,0x14,0x30,0x48,0x11,0xB8,0x80,0x30,0xCE,0x17,0xFC,0x02,0x0A,0x14,0x6C,
+0x20,0x49,0x15,0x6C,0x01,0x0A,0x16,0x7C,0x80,0x11,0xBC,0xDC,0x00,0x0C,0xB4,0xDC,
+0x00,0x0C,0x14,0xC4,0x01,0x7F,0x14,0xB0,0x08,0x11,0xB8,0x00,0x04,0x0A,0x0E,0xEC,
+0x20,0x48,0x17,0xFC,0x80,0x11,0xBC,0xDC,0x00,0x0C,0x16,0x44,0xFF,0xFB,0x18,0xB8,
+0xB3,0x00,0xF6,0xAA,0x30,0xCE,0x17,0xFC,0xB2,0x00,0x16,0x2D,0x80,0xE4,0xC9,0x87,
+0x40,0x01,0x18,0x38,0xB3,0x00,0x46,0x2A,0x00,0x0C,0x26,0xCC,0x94,0x00,0x18,0xB8,
+0xB3,0x00,0x46,0x2A,0x00,0x0C,0x26,0xD4,0x04,0x94,0x80,0x36,0x80,0x11,0xBC,0xC4,
+0x04,0x10,0x80,0xB2,0xB3,0x00,0x74,0x2B,0x00,0x0C,0x60,0x4C,0xFF,0xFF,0x0C,0xBA,
+0xFF,0xC1,0x37,0x64,0x02,0x20,0x80,0x33,0x02,0x20,0x84,0x37,0x02,0x20,0x14,0xB0,
+0x02,0xC2,0x41,0xB0,0x02,0x0A,0x0C,0xB2,0x02,0x0A,0x84,0x33,0x02,0x0A,0x40,0x34,
+0x4A,0x00,0x0C,0xB8,0x08,0x39,0x4E,0x6C,0x04,0x39,0x48,0x6C,0x10,0x3A,0x60,0xFC,
+0x00,0x0C,0xAC,0x5B,0x04,0x11,0x72,0x00,0x10,0x11,0x74,0x84,0xFF,0x63,0x56,0xF4,
+0xC0,0x11,0x18,0x80,0xB0,0x00,0xAE,0x2F,0x80,0xE5,0xCB,0x03,0x08,0x11,0x72,0x84,
+0xB0,0x00,0x18,0x28,0x0F,0x00,0x14,0x08,0x01,0x0A,0x14,0x18,0x00,0x7C,0xE4,0x78,
+0xFF,0x11,0x22,0x8C,0x80,0xE1,0x61,0xEC,0x08,0xE4,0x61,0xEC,0x04,0x3C,0xEC,0xB3,
+0x00,0x11,0x78,0x08,0x5F,0x3D,0x7A,0x08,0x08,0xE4,0xC9,0x87,0x02,0x05,0x0A,0x00,
+0x08,0xE4,0x61,0x7C,0x40,0x3D,0x14,0x08,0xBF,0xF7,0xEF,0x8B,0x00,0xF7,0xEF,0x83,
+0x04,0xF6,0x79,0xB0,0xF7,0xE4,0xC9,0x0F,0x02,0x05,0x0A,0x00,0x00,0xC8,0x91,0x83,
+0x01,0x0B,0x14,0xB0,0x00,0xC8,0x17,0x88,0x00,0x0B,0x8A,0x64,0xBF,0x3D,0x7A,0x88,
+0x00,0x11,0xC0,0x89,0xA3,0x00,0xB2,0xAB,0x00,0x0C,0x9C,0xDC,0x00,0x0C,0x60,0x4C,
+0xC0,0xC8,0x69,0xEB,0x10,0x48,0x69,0x7B,0x80,0xCC,0x15,0x08,0x80,0x0B,0x17,0x08,
+0x00,0x0B,0x68,0x73,0x01,0x11,0x22,0x9C,0x02,0x20,0x18,0xB0,0x02,0xF4,0x15,0x30,
+0xB3,0x00,0x6E,0x2A,0x80,0x0F,0x68,0xFB,0xFF,0x0A,0x69,0x73,0xC0,0x0A,0x15,0x88,
+0x80,0x0A,0x68,0x73,0xC0,0x0A,0x68,0xF3,0x01,0x49,0x69,0x6B,0x40,0x49,0x69,0x6B,
+0x01,0x11,0x22,0x9C,0xA3,0x00,0xBE,0x2A,0x08,0x5E,0xBC,0x00,0xFF,0x21,0x60,0xF4,
+0x08,0x11,0xBA,0xC4,0xA3,0x00,0xDE,0x2A,0xA3,0x00,0xE2,0x2A,0x02,0xC9,0x93,0x03,
+0x04,0x5D,0x60,0x7C,0xFF,0xFB,0xDD,0x6C,0x30,0xCE,0xCB,0xEC,0xB0,0x00,0xC6,0xAF,
+0x00,0x0C,0xDA,0x44,0xB2,0x00,0x32,0x2E,0x00,0x0C,0x60,0x4C,0x0B,0x0A,0xD7,0xE4,
+0x04,0x1F,0xDB,0x7C,0x04,0x11,0x60,0x33,0x00,0x0C,0xDA,0x44,0x08,0x48,0xDB,0xFC,
+0xB2,0x00,0x26,0xAF,0x49,0x11,0xB8,0x84,0x01,0x11,0xB8,0x84,0xA3,0x00,0x54,0xAA,
+0x7F,0x06,0x0C,0xB8,0x02,0xE0,0x14,0xB0,0x81,0x80,0xB0,0xAB,0x02,0xE2,0x14,0x30,
+0x81,0x82,0xB4,0xAB,0x02,0xE4,0x14,0x30,0x81,0x84,0xB8,0xAB,0x02,0xE6,0x14,0xB0,
+0x81,0x86,0xBC,0xAB,0x01,0x88,0x00,0xED,0x10,0x88,0xA8,0x6D,0x08,0x88,0xB6,0x6D,
+0x04,0x88,0xD0,0x6D,0x02,0x88,0xDC,0x6D,0x02,0x06,0x22,0x30,0x01,0x11,0x74,0x84,
+0x04,0xDB,0x0F,0xED,0x08,0xDB,0x8B,0xED,0xF0,0xDA,0x91,0x6D,0xFF,0xD8,0x7F,0xED,
+0x03,0xDB,0x4B,0x6D,0x10,0xDB,0x9F,0xED,0x00,0x0C,0xF4,0x44,0xA4,0x06,0x0C,0xB8,
+0x01,0xCD,0x61,0x6C,0x11,0x11,0x00,0x80,0x01,0xC8,0x19,0xED,0x00,0x11,0x8C,0x8D,
+0x04,0x9E,0x1F,0x7D,0xFB,0x9E,0x3D,0x8B,0x02,0x9E,0x3D,0x03,0x70,0x0B,0x15,0x88,
+0x80,0x80,0xB1,0x0B,0x00,0xD8,0x15,0x00,0x08,0xA0,0xB0,0x0B,0x00,0xD8,0x15,0x00,
+0x01,0x0A,0x14,0x00,0x00,0x0C,0xE6,0xD8,0x00,0x0C,0xBE,0xDC,0xB0,0x00,0xBE,0xAF,
+0x00,0x11,0x2A,0x8B,0x00,0x11,0x7E,0x0B,0xB3,0x00,0x5C,0xAA,0x40,0xCE,0x45,0x7D,
+0x01,0x11,0x00,0x00,0x02,0x20,0x40,0x30,0x00,0x11,0x00,0x08,0xE3,0x11,0x52,0xDA,
+0xF7,0x06,0xC0,0xBB,0x40,0xCA,0x95,0x87,0x80,0xCC,0x61,0xEC,0xA3,0x00,0x72,0x29,
+0x04,0x11,0x06,0x05,0x01,0xCD,0x7D,0x6D,0xF7,0xA0,0x40,0x89,0x11,0x11,0x00,0x80,
+0xFE,0xC8,0x91,0x8B,0x10,0xE4,0xC9,0x03,0x01,0x83,0x5E,0xED,0x0F,0x8C,0x14,0x88,
+0x90,0x0A,0xF4,0x03,0xB0,0x00,0xBE,0xAF,0x00,0x0C,0x78,0x45,0x4C,0x8C,0x14,0xA8,
+0x80,0x0A,0xF4,0x83,0x80,0x8C,0x6E,0xED,0xF0,0x8C,0x0E,0x08,0x0C,0x07,0x6E,0x6D,
+0xB0,0x00,0xC2,0x2F,0xC2,0x07,0x72,0x6D,0x31,0x07,0x78,0x6D,0xB0,0x00,0xBE,0xAF,
+0x00,0x0C,0x78,0x45,0x01,0x95,0x2B,0x1B,0x00,0x0C,0x78,0xD5,0xFF,0x11,0x2A,0x03,
+0xBF,0x3D,0x7A,0x88,0x00,0x11,0xC0,0x89,0x03,0x11,0x06,0x85,0x01,0xCD,0x89,0xED,
+0x11,0x11,0x00,0x80,0x02,0xC8,0x87,0x6D,0x08,0xE4,0xC9,0x03,0xE8,0x11,0x16,0x5A,
+0xFF,0x11,0x00,0x85,0x80,0xCE,0x8F,0x7D,0x08,0xC8,0x91,0x03,0x08,0x11,0x06,0x05,
+0x60,0xCE,0x99,0xED,0x80,0xCE,0x9D,0x7D,0x0C,0xC8,0xB1,0x8B,0x0C,0xD8,0x9D,0x65,
+0x20,0x30,0x14,0xB8,0x00,0x0C,0x7C,0x5C,0xF0,0x11,0x04,0x05,0x10,0x45,0xA6,0x6D,
+0x03,0xC8,0xA7,0xFD,0x80,0xC0,0x14,0xB8,0x00,0x0C,0x7C,0x5C,0x10,0x11,0x06,0x05,
+0x1E,0xDC,0xF7,0x7C,0x18,0xDC,0xB5,0xFD,0x87,0x11,0x8E,0xDA,0x22,0x11,0x00,0x80,
+0x80,0xE4,0xC9,0x03,0xE7,0xE4,0xC8,0x09,0x1E,0x11,0x08,0x05,0x80,0xDC,0xBD,0x6D,
+0x02,0xDE,0xC7,0x6D,0x00,0x0C,0xF8,0x44,0x01,0xCD,0xC5,0x6D,0x30,0xCB,0xC5,0x7D,
+0x80,0xCB,0xC5,0x6D,0x80,0xCB,0x97,0x03,0x80,0x11,0x08,0x85,0x01,0xA1,0xCE,0x7D,
+0xFD,0xE6,0xCC,0x89,0x00,0x11,0x00,0x08,0x00,0x0C,0x52,0xC3,0x02,0x11,0x0C,0x05,
+0xFF,0xD9,0xFB,0x7C,0x81,0x11,0xB0,0x03,0xFF,0x81,0xB2,0x0B,0xFF,0x11,0x02,0x81,
+0x01,0xA1,0x60,0xEC,0x00,0x0C,0xE8,0x45,0x0E,0xDA,0xE3,0xED,0x01,0xDA,0xFD,0xFC,
+0xFE,0xE2,0xC4,0x89,0x82,0x11,0xB0,0x03,0x0F,0x82,0xB2,0x0B,0x0F,0x11,0x04,0x81,
+0x04,0x3A,0xE8,0x7D,0x0C,0x00,0x68,0xB8,0x02,0xD8,0x6D,0x34,0xB0,0x00,0x18,0x28,
+0x02,0x05,0x0A,0x00,0x10,0xE4,0x15,0x6E,0x0F,0xCB,0x09,0xEE,0x20,0xE4,0x0D,0x6E,
+0x80,0xC8,0x0B,0xEE,0x20,0xC8,0x0D,0xEE,0xFD,0x05,0x0A,0x88,0xDC,0x01,0x1C,0xB8,
+0xE3,0x11,0x2E,0x5A,0x00,0x0C,0xE4,0xD0,0x10,0xC9,0x93,0x03,0x15,0x11,0x0E,0x46,
+0x08,0x11,0x0E,0x46,0x05,0x11,0x0E,0xC6,0x16,0x11,0x0E,0x46,0xFD,0x05,0x0A,0x88,
+0x00,0x0C,0xB2,0xDC,0x14,0x11,0x1C,0xC6,0xFD,0x05,0x0A,0x88,0x00,0x0C,0x58,0x5C,
+0xB3,0x00,0x92,0xAB,0x0D,0x11,0x1C,0x46,0x00,0x0C,0xAC,0xD9,0xA0,0x00,0x5C,0x2A,
+0x10,0xE4,0x47,0xEE,0xB3,0x00,0x82,0x2B,0x02,0x58,0x19,0x30,0xFC,0xFF,0x14,0x38,
+0x83,0x90,0x14,0x28,0x8A,0x0C,0x3E,0xAE,0xB3,0x00,0x6E,0x2A,0x80,0x0F,0x3A,0xEE,
+0x04,0x0C,0x78,0xB2,0x01,0x11,0xB2,0x5C,0xFC,0xFF,0x14,0x38,0x83,0x90,0xB0,0x2A,
+0x00,0x0C,0x3E,0xC6,0x04,0x11,0x78,0xB2,0x02,0x11,0xB2,0x5C,0x10,0x50,0xC1,0xB0,
+0x20,0x00,0xBC,0x38,0x69,0x11,0xB8,0x80,0x10,0xE4,0xC9,0x87,0x18,0x11,0xB8,0x04,
+0x01,0x30,0x14,0x30,0xFF,0x0A,0x5E,0x7E,0x01,0x0A,0x5E,0x76,0x15,0x0A,0x5C,0xF6,
+0x0A,0x0A,0x1C,0x77,0x02,0x0A,0x2C,0xF7,0xF8,0x0A,0x14,0x88,0xC0,0x0A,0x02,0x77,
+0xD0,0x0A,0x04,0xF7,0x16,0x11,0x2A,0x80,0xA3,0x00,0xD2,0x29,0x04,0x30,0xB0,0xB3,
+0x11,0x11,0x00,0x80,0x02,0x22,0x0C,0x30,0x02,0x20,0x0C,0xB0,0x02,0xDA,0x41,0xB0,
+0x02,0x46,0x45,0x30,0x03,0xC8,0xA3,0xEE,0xC0,0xCA,0xA3,0x6E,0x3F,0xCB,0xA3,0xEE,
+0x04,0x06,0x22,0x30,0x01,0xD8,0xF7,0xB3,0x02,0x20,0xDC,0x33,0x20,0x0B,0xAD,0x7E,
+0x40,0x9E,0xA9,0x6E,0x08,0x48,0x15,0x08,0xF7,0x9E,0x3D,0x8B,0x00,0x9E,0x3D,0x83,
+0xB2,0x00,0x20,0xAF,0x01,0x9D,0x9D,0xEE,0x01,0x02,0x90,0x3B,0x80,0x11,0x94,0x83,
+0x01,0xCD,0x9B,0x03,0x01,0x45,0x9C,0xB3,0xB3,0x00,0x32,0xAB,0xB3,0x00,0x5C,0xAA,
+0x01,0xFB,0x9B,0xF6,0xB0,0x00,0xFA,0xAA,0x10,0xCE,0x99,0xFE,0x00,0x0C,0xC4,0x5C,
+0xB6,0x01,0xC0,0xBF,0x2F,0x02,0xC0,0xBF,0x02,0x9E,0xAD,0xEE,0x04,0x9E,0x3D,0x03,
+0x00,0x0C,0xAC,0x46,0xB3,0x00,0xEA,0xAB,0x02,0x06,0x40,0xB0,0x02,0x06,0x44,0x30,
+0x04,0x3A,0xA8,0xFE,0x04,0xD8,0x69,0xB4,0x70,0x0B,0x15,0x88,0xFF,0x0A,0xB6,0x7E,
+0x80,0x80,0xBD,0x6E,0x02,0x82,0xE5,0xB3,0x00,0x0C,0xC0,0x46,0x01,0x7C,0xB6,0x7E,
+0xFF,0xFF,0xE4,0x3B,0x00,0x0C,0xC0,0x46,0x01,0x23,0xE4,0xB3,0x01,0x22,0xE6,0xB3,
+0x08,0x11,0xB8,0x00,0x00,0x00,0x90,0xB9,0x8F,0x80,0x17,0x08,0x00,0x0B,0x94,0x01,
+0x09,0x0B,0x15,0x08,0x55,0x11,0x00,0x80,0x01,0x43,0xD1,0xFE,0x08,0x11,0x14,0x00,
+0x11,0x11,0x00,0x80,0xF6,0x81,0x17,0x08,0x00,0x0B,0x94,0x01,0x02,0xF2,0x95,0x31,
+0x08,0x84,0x95,0xB1,0x08,0xA8,0x94,0xB1,0x08,0x94,0x95,0x31,0x09,0x0A,0xE8,0x76,
+0x55,0x11,0x00,0x80,0x01,0x43,0xE7,0x6E,0x08,0x11,0x40,0x01,0x11,0x11,0x00,0x80,
+0x10,0x04,0xBC,0xB8,0x1C,0x11,0xDE,0x5C,0x49,0x11,0xB8,0x00,0x01,0xC8,0x91,0x03,
+0x80,0xCA,0x95,0x03,0xB3,0x00,0x32,0xAB,0x02,0x96,0x71,0xB1,0x01,0xBA,0x74,0x01,
+0xFE,0x9E,0x3D,0x8B,0xE8,0x11,0x16,0x5A,0x02,0x7C,0xFC,0xFE,0x02,0xE4,0xC9,0x03,
+0x00,0x0C,0x90,0x46,0x02,0x11,0x06,0x47,0x01,0x11,0x06,0x47,0x01,0x0C,0x48,0x30,
+0x04,0xCE,0x1B,0xF7,0xC8,0xCD,0x1D,0x98,0x01,0x11,0x1E,0x00,0x01,0x30,0x26,0xB0,
+0x11,0xCD,0x15,0xA8,0x03,0x0E,0x9A,0x8B,0x01,0xCE,0x9D,0x1B,0xC0,0x0A,0x1C,0x18,
+0x02,0x32,0x26,0xB4,0x1D,0x11,0x2A,0x00,0x04,0x30,0xB0,0xB3,0x30,0xCB,0xA9,0xEE,
+0x44,0x11,0x00,0x80,0x02,0xDA,0xE1,0xB3,0x10,0xCB,0x97,0x03,0x80,0xE1,0x61,0x7C,
+0xB3,0x00,0x32,0xAB,0x2F,0x08,0xC0,0xBF,0x04,0x30,0x22,0x30,0x44,0x11,0x00,0x80,
+0xB2,0x00,0xC8,0x28,0xA3,0x00,0x32,0x2B,0xB2,0x00,0xB6,0xAA,0xEB,0x00,0xF4,0xBB,
+0xB2,0x00,0x4E,0x2A,0xA0,0x00,0x22,0xA8,0x01,0xC7,0x14,0xB0,0x00,0xC5,0x14,0x08,
+0x80,0x0A,0x50,0x6F,0x40,0x0A,0x54,0xEF,0x20,0x0A,0x58,0xEF,0x08,0x0A,0x70,0xEF,
+0x04,0x0A,0x86,0xEF,0x02,0x0A,0x90,0x6F,0x01,0x0A,0x9A,0x6F,0xFF,0x11,0x22,0x8C,
+0x80,0x11,0x8E,0x81,0x20,0xC9,0x93,0x87,0x40,0x11,0x8E,0x81,0xE4,0x11,0x5C,0xC7,
+0x20,0x11,0x8E,0x81,0xE0,0x11,0x5C,0x47,0x01,0x11,0x4A,0x80,0x01,0x11,0x1A,0x80,
+0x02,0x0C,0x1C,0xB0,0x04,0x12,0xB0,0xB3,0x01,0x00,0x14,0xB8,0x83,0xD8,0xB1,0x2B,
+0x00,0x00,0x14,0x38,0x84,0xDA,0xB5,0xAB,0x00,0x0C,0x60,0x4C,0x04,0xD8,0x27,0xB4,
+0x01,0xC7,0x19,0x88,0x01,0xCB,0x14,0x08,0x00,0x0C,0x7E,0xF7,0xFE,0xC7,0x8F,0x8B,
+0x00,0xC7,0x8F,0x83,0x01,0x0A,0x80,0x7F,0xEF,0x11,0x52,0xDA,0x08,0x11,0x8E,0x05,
+0x08,0x11,0x8E,0x81,0xEC,0x11,0x16,0xDA,0xE8,0x11,0x5C,0xC7,0x04,0x11,0x8E,0x81,
+0x04,0xC9,0x93,0x03,0x59,0x11,0x7C,0x5A,0xB1,0x00,0x9E,0xAF,0x09,0x11,0xE4,0x85,
+0x02,0x11,0x8E,0x81,0x08,0xC9,0x93,0x03,0x58,0x11,0x7C,0xDA,0xB1,0x00,0x9E,0xAF,
+0x05,0x11,0xE4,0x85,0x01,0x11,0x8E,0x81,0x40,0xC9,0x93,0x87,0x80,0x11,0x8E,0x81,
+0xDF,0xC9,0x93,0x0F,0x02,0x48,0x15,0xB0,0x01,0x0B,0x68,0xEB,0x02,0x05,0x0A,0x00,
+0x01,0x0A,0x04,0xB0,0x01,0x0B,0x06,0x80,0xE1,0x48,0xB3,0xAF,0xFD,0x05,0x0A,0x88,
+0x01,0x11,0x22,0x9C,0xFD,0x05,0x0A,0x88,0x02,0x48,0x91,0x32,0x00,0x0C,0xA2,0x47,
+0x02,0x06,0x44,0x30,0xFF,0x11,0x22,0x8C,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x01,0x4E,0x15,0xB0,0x01,0x4C,0x17,0xB0,0x81,0x5A,0x15,0x28,0x02,0x0B,0x0C,0xF8,
+0xB1,0x00,0x6A,0x29,0x00,0x0C,0x5C,0x40,0x20,0x0A,0x14,0x78,0x30,0xE4,0xC9,0x83,
+0x22,0x11,0x9E,0x82,0xDD,0x5A,0xB5,0x0A,0x02,0x0A,0x1A,0xF8,0x20,0xE4,0xC9,0x03,
+0x02,0x11,0x9E,0x02,0x10,0x0A,0x20,0xF8,0x40,0xE4,0xC9,0x03,0x10,0x11,0x9E,0x02,
+0x40,0x0A,0x26,0xF8,0xFD,0x4D,0x9B,0x8A,0xFD,0x5B,0xB7,0x8A,0x10,0xCB,0x3D,0xE8,
+0xEB,0x0A,0x14,0x08,0xFF,0x0A,0x5A,0xF8,0x20,0xCB,0x5B,0xE8,0x20,0xCB,0x97,0x03,
+0x97,0xC5,0x8A,0x89,0x82,0x08,0xC0,0xBB,0x00,0x0C,0xB6,0x5A,0x40,0x0A,0x44,0x78,
+0x01,0xCB,0x97,0x03,0x00,0x0C,0x44,0x40,0x40,0x4E,0x9F,0x0A,0x20,0x0A,0x44,0xE8,
+0xA9,0x44,0x15,0x88,0xFF,0x0A,0x5A,0xF8,0xA9,0x0A,0x48,0xF8,0x80,0xE4,0xC9,0x03,
+0x01,0x0A,0xDC,0xB3,0x00,0x0C,0x0C,0x5B,0x40,0xEF,0x51,0x78,0x01,0xCA,0x95,0x03,
+0x20,0xE4,0x55,0x78,0x02,0xEE,0xDD,0x03,0x40,0xE4,0x59,0x78,0x10,0xEE,0xDD,0x03,
+0xFE,0x3F,0x7E,0x88,0xFF,0x11,0x9E,0x82,0x01,0x11,0x76,0x04,0x02,0xF0,0x41,0x30,
+0x80,0x0A,0x79,0x70,0x81,0x0A,0x4F,0xF3,0x00,0x0C,0x5E,0xC3,0xB2,0x00,0x66,0x2F,
+0x00,0x0C,0x24,0x5B,0xFF,0xF1,0x5F,0x60,0x02,0x05,0x0A,0x00,0x0F,0xCB,0x97,0x0B,
+0x40,0x3D,0x7A,0x00,0x01,0x3F,0x7E,0x00,0xB3,0x00,0x32,0xAB,0xA0,0x00,0x22,0xA8,
+0xF4,0xCB,0x97,0x8B,0x01,0x0C,0x15,0xB0,0x01,0x0A,0x8A,0x70,0x81,0x0A,0x8E,0x70,
+0x02,0x0A,0x92,0x70,0xFF,0x0A,0xC6,0xF8,0x03,0x0A,0x8A,0xF0,0x04,0x0A,0x8A,0x70,
+0x00,0x0C,0xEC,0xC0,0x01,0x11,0xE8,0x03,0x00,0x0C,0xA8,0xC0,0x02,0x11,0xE8,0x03,
+0x00,0x0C,0xA8,0xC0,0x54,0x11,0x02,0x80,0x02,0x05,0x0A,0x00,0x01,0x0D,0x85,0xB2,
+0x55,0x11,0x00,0x80,0x20,0x11,0x9E,0x02,0x20,0x11,0x88,0x82,0x20,0x11,0x9C,0x82,
+0x22,0x5A,0xB5,0x82,0xFD,0x05,0x0A,0x88,0x01,0x01,0x22,0xB0,0x00,0x0C,0xAA,0x40,
+0x00,0x0C,0x2A,0x5A,0x00,0x0C,0xCA,0xDA,0x01,0x11,0xB5,0xF8,0x03,0x11,0x48,0x80,
+0x04,0xD8,0x81,0x33,0x00,0x11,0x48,0x08,0x00,0x0C,0xBE,0xC8,0x34,0x08,0x0C,0x38,
+0x20,0xEE,0x4F,0xEF,0x02,0x11,0x4F,0x7F,0x00,0x0C,0xC8,0xC0,0x00,0x0C,0x24,0x5B,
+0xFF,0xFF,0x40,0xB8,0x40,0xEF,0xA5,0xE9,0x00,0x0C,0x2A,0x41,0x7F,0x08,0x0C,0x38,
+0x55,0x11,0x02,0x00,0x02,0x05,0x0A,0x00,0x00,0x00,0xB0,0x3A,0x00,0x00,0xB4,0xBA,
+0xFE,0x3F,0x7E,0x88,0x08,0x11,0x80,0x02,0x00,0x11,0x82,0x8A,0x00,0x11,0x80,0x0A,
+0xC2,0x60,0xC1,0x02,0xFF,0xFF,0x94,0x3A,0xFF,0x11,0x9E,0x82,0x01,0x01,0x22,0xB0,
+0xB3,0x00,0x82,0xAA,0x97,0xC5,0x8A,0x89,0xB2,0x00,0x12,0xAB,0x03,0x11,0x90,0xB3,
+0x08,0x11,0x96,0x03,0xA3,0x00,0xB2,0xAB,0x10,0x0D,0xF5,0xF8,0x55,0x11,0x00,0x80,
+0xEF,0x5A,0xB5,0x8A,0x44,0x11,0x00,0x80,0x00,0x0C,0x6A,0xDA,0x10,0x0D,0xFF,0x68,
+0x55,0x11,0x00,0x80,0x10,0x5A,0xB5,0x02,0x44,0x11,0x00,0x80,0x00,0x11,0x78,0x8A,
+0x03,0x11,0x7A,0xB2,0x11,0x11,0x66,0x40,0x40,0xEE,0x11,0xF9,0xB1,0x00,0xAE,0xA9,
+0x00,0x0C,0x1A,0xDB,0x00,0x0A,0x54,0x5F,0xBF,0xEE,0xDD,0x8B,0xA9,0xEE,0x6B,0x78,
+0x14,0xCB,0x97,0x83,0xF4,0xCB,0x97,0x8B,0x01,0x11,0xE8,0x03,0xFF,0xFF,0x40,0xB8,
+0x00,0x0C,0xCA,0xDA,0xB1,0x00,0xAE,0xA9,0x00,0x0C,0x1A,0xDB,0x00,0x0A,0x54,0x5F,
+0x08,0xEE,0x27,0xF9,0x00,0x0C,0x4E,0xDA,0x00,0x0C,0x6A,0x40,0x80,0xEE,0x6B,0xF8,
+0x40,0xEF,0xA5,0xE9,0x00,0x11,0x68,0x5F,0x91,0x00,0x40,0xB9,0x02,0x00,0x40,0xB9,
+0x01,0x11,0x56,0x5F,0xB0,0x00,0x5C,0xAF,0xB0,0x00,0x18,0x28,0xC0,0xCA,0x61,0x6F,
+0x02,0xF4,0x6F,0xF1,0x00,0x0C,0x2C,0xDB,0xE4,0x11,0x50,0xDF,0x11,0x11,0x4A,0xDB,
+0xB1,0x00,0x58,0xAC,0x44,0x11,0x4A,0xDB,0xB0,0x00,0x18,0x28,0x40,0xCB,0x57,0x69,
+0x80,0xCB,0x67,0x69,0x00,0x0C,0x18,0xDA,0x00,0x0C,0xF6,0x49,0x02,0xCB,0xF9,0xE9,
+0xE7,0x11,0x4C,0x5F,0x00,0x0C,0xFA,0x49,0x00,0x0C,0x60,0xC7,0x00,0x11,0x4A,0xDB,
+0xB1,0x00,0x58,0xAC,0x00,0x00,0x90,0xB9,0x00,0x11,0xB2,0x89,0x1C,0xD8,0x94,0x31,
+0x40,0x11,0x72,0x00,0x1C,0xF0,0xF4,0x3B,0x00,0x0C,0xD4,0xC1,0x84,0x80,0x40,0x38,
+0x0C,0x11,0x54,0x5F,0xFF,0xFF,0x40,0xB8,0x00,0x0C,0x6A,0x40,0x00,0x0C,0xB6,0x5A,
+0x55,0x11,0x00,0x80,0x10,0x11,0x80,0x02,0x44,0x11,0x00,0x80,0x2D,0x11,0x58,0x5F,
+0x02,0x05,0x0A,0x00,0x0F,0xCB,0x97,0x0B,0xB3,0x00,0x32,0xAB,0xFD,0x05,0x0A,0x88,
+0xB0,0x00,0x18,0x28,0x00,0x0C,0x18,0xDA,0x00,0x0C,0x90,0x49,0x08,0xC7,0x8C,0xF9,
+0x08,0x11,0x8E,0x81,0x01,0xCB,0x90,0x79,0xFF,0xF1,0x6B,0xE0,0x00,0x0C,0x60,0xC7,
+0x40,0x11,0x72,0x00,0xB0,0x00,0x18,0x28,0x55,0x11,0x00,0x80,0x40,0x48,0x9F,0x69,
+0x44,0x11,0x00,0x80,0xFF,0xF1,0x6B,0xE0,0x00,0x0C,0x60,0xC7,0x90,0x11,0x80,0x82,
+0x44,0x11,0x00,0x80,0x00,0x0C,0x6A,0x40,0x02,0xCC,0x0D,0xB0,0xB1,0x11,0x14,0x80,
+0xB1,0x00,0xE6,0x28,0x02,0x06,0x14,0x30,0x01,0x0B,0xB2,0x79,0xB0,0x00,0x18,0x28,
+0x01,0xCD,0x61,0x6F,0xFE,0xCD,0x9B,0x8B,0xB0,0x00,0x18,0x28,0x40,0xCA,0x61,0xEF,
+0xD0,0x01,0x1C,0xB8,0xE8,0x11,0x5A,0xDF,0xB0,0x00,0x18,0x28,0x40,0xCB,0xCF,0xE9,
+0x00,0x0C,0x18,0xDA,0x00,0x0C,0xF6,0x49,0x02,0xCB,0xF9,0xE9,0xD0,0x01,0x1C,0xB8,
+0xEB,0x11,0x4A,0x5F,0x00,0x0C,0xFC,0x49,0x00,0x0C,0x60,0xC7,0x00,0x11,0x4A,0xDB,
+0x20,0x11,0xB8,0x00,0x14,0x20,0xF4,0x3B,0xB1,0x00,0xAE,0xA9,0x01,0x0A,0xC4,0xB3,
+0x01,0xFA,0x15,0xB0,0x00,0x11,0x16,0x88,0xB1,0x00,0xEA,0xA9,0xB1,0x00,0x06,0x2A,
+0x02,0x0C,0x1C,0x98,0xFF,0xC6,0x27,0x08,0x01,0xFB,0x27,0xB0,0x02,0x0A,0x26,0xB0,
+0xB1,0x00,0x58,0xAC,0x00,0xE2,0x55,0xDF,0xFF,0xFF,0x40,0xB8,0x44,0x11,0x4A,0xDB,
+0xFB,0xCB,0x97,0x8B,0x01,0xF6,0xEB,0x33,0x00,0x0C,0x6A,0x40,0x01,0x11,0xFE,0xC1,
+0x02,0x11,0xFE,0xC1,0x00,0x11,0xFE,0x41,0x03,0x11,0xFE,0x41,0x01,0x0C,0xE4,0x33,
+0xB1,0x00,0xAE,0xA9,0x03,0xF2,0x07,0x62,0x00,0x11,0xEA,0x8B,0x02,0x0C,0x1C,0x98,
+0x18,0xC6,0x27,0x80,0x01,0xF2,0x27,0xB0,0x01,0xF5,0x27,0x30,0x00,0x0A,0x54,0x5F,
+0x35,0x08,0x0C,0xB8,0xFF,0xF5,0xC9,0xF8,0xFF,0xF5,0xEB,0x9B,0x00,0x0C,0x4E,0xC2,
+0x55,0x11,0x02,0x00,0x40,0x4E,0x27,0xFA,0x00,0x11,0x82,0x8A,0xC0,0x11,0x9E,0x82,
+0x01,0x11,0x76,0x80,0x01,0x01,0x22,0xB0,0x01,0x10,0x22,0x1C,0x01,0x01,0x22,0xB0,
+0x01,0x11,0x22,0x9C,0x00,0x0C,0xB6,0x5A,0x00,0x0C,0x6A,0xDA,0x01,0x10,0x9F,0xB3,
+0x01,0x16,0xED,0xB3,0x01,0x16,0xEB,0xB3,0x01,0x11,0x3D,0x7A,0x03,0x11,0x48,0x80,
+0x04,0x12,0x81,0x33,0x00,0x11,0x48,0x08,0x55,0x11,0x00,0x80,0x03,0x0A,0x7C,0x72,
+0x04,0x0A,0x7C,0xF2,0xFD,0x11,0x9E,0x02,0xEB,0x00,0xF4,0xBB,0x10,0x42,0x4B,0x6A,
+0x10,0xFA,0xF5,0x03,0xFD,0x60,0xC1,0x8A,0x44,0x11,0x00,0x80,0xE3,0x11,0x5E,0xDF,
+0x00,0x0C,0x5A,0x52,0xB0,0x00,0x18,0x28,0xD8,0x01,0x1C,0x38,0xE3,0x11,0x4A,0xDF,
+0x00,0x0C,0x60,0x57,0x55,0x11,0x02,0x00,0x00,0x11,0x82,0x8A,0x10,0x11,0x80,0x02,
+0x90,0x11,0x80,0x82,0x02,0xFA,0xB5,0x32,0x01,0x01,0x22,0xB0,0xD8,0x01,0x1C,0x38,
+0xE0,0x11,0x5A,0x47,0x54,0x11,0x02,0x80,0x01,0x0F,0xA1,0x32,0x01,0x0D,0x85,0xB2,
+0x01,0x0E,0x8B,0x32,0x06,0x11,0xE2,0x02,0x00,0x11,0xE4,0x8A,0x29,0x11,0xE6,0x02,
+0x01,0x11,0xD8,0x82,0x01,0x01,0x22,0x34,0x01,0xA2,0x18,0x38,0x03,0x02,0x1C,0x38,
+0x03,0x0A,0x88,0xF2,0x08,0xA1,0x18,0x38,0x11,0x10,0x1C,0x38,0x01,0xCA,0x95,0x03,
+0x00,0x11,0x8C,0x0A,0x3D,0x60,0xC1,0x8A,0x01,0x0C,0x82,0xB2,0x50,0x11,0x80,0x82,
+0x08,0x11,0xC4,0x83,0xFF,0xE2,0xC5,0x9B,0xFF,0xE2,0x93,0xEA,0xA0,0x41,0x83,0x82,
+0x01,0x0E,0x14,0xB0,0x00,0x49,0xC5,0x8B,0xFF,0xE2,0x9B,0xFA,0x01,0x0D,0x82,0x32,
+0x01,0x0F,0x14,0x30,0x00,0xE2,0xA7,0x6A,0x00,0x49,0xA5,0xFA,0x80,0x11,0x9C,0x82,
+0xE0,0x11,0x82,0x82,0x03,0x11,0x8C,0x82,0xA0,0xE4,0xC9,0x83,0x82,0x11,0xDC,0x03,
+0x00,0x0C,0x0C,0x5B,0xFF,0x11,0x9E,0x82,0x44,0x11,0x00,0x04,0x04,0xCB,0x97,0x03,
+0x22,0x11,0x02,0x00,0x97,0xC5,0x8A,0x89,0xEF,0x11,0x5C,0x5F,0xFE,0xC7,0x8F,0x8B,
+0x01,0x01,0x22,0xB0,0x08,0x11,0x88,0x00,0x02,0x00,0x40,0xB9,0x00,0x11,0x8A,0x88,
+0x00,0x11,0x56,0xC7,0x01,0x3F,0x7E,0x00,0xC0,0x01,0x1C,0x38,0xEC,0x11,0x5A,0x5F,
+0xB0,0x00,0x18,0x28,0x80,0xE4,0xE3,0x7A,0x80,0xEE,0xDF,0x7A,0x02,0xF4,0xDF,0x72,
+0xB2,0x00,0x12,0xAB,0x68,0xC5,0x8A,0x01,0xB1,0x00,0x74,0x29,0xB3,0x00,0x8C,0x2A,
+0x00,0x0C,0xF6,0xC2,0x20,0xE4,0x61,0xEF,0xC0,0x01,0x1C,0x38,0xEF,0x11,0x4A,0xDF,
+0x00,0x0C,0x60,0x57,0x55,0x11,0x02,0x00,0xFE,0x3F,0x7E,0x88,0x01,0x44,0xDD,0x33,
+0x00,0x0C,0x0C,0x5B,0xFF,0x11,0x9E,0x82,0x01,0x01,0x22,0xB0,0x1F,0xE4,0xC9,0x8B,
+0xFF,0x21,0x04,0xF3,0x11,0x11,0x66,0xDF,0x00,0x11,0x78,0x8A,0x01,0xEE,0x7B,0xB2,
+0x01,0xEF,0x7D,0x32,0x01,0xF3,0x7F,0x32,0x01,0xCB,0x14,0x08,0xFE,0xC7,0x8F,0x8B,
+0x00,0xC7,0x8F,0x83,0x11,0xEE,0x23,0xAC,0x01,0x43,0xDF,0x33,0x80,0x48,0xE7,0x8B,
+0xFF,0x11,0x94,0x06,0x06,0x11,0x96,0x01,0x68,0xC7,0x4E,0x7F,0x68,0x11,0x8E,0x81,
+0x80,0x11,0x74,0x84,0x02,0x0C,0x1C,0x98,0x10,0xC6,0x27,0x00,0x01,0xEE,0x27,0x30,
+0x01,0xEF,0x27,0xB0,0x01,0xF3,0x27,0xB4,0x02,0x00,0xE1,0x33,0xFF,0xF1,0x2B,0x63,
+0x11,0x11,0x54,0x47,0x12,0x11,0x54,0x47,0x11,0x11,0x02,0x00,0x08,0x11,0xB8,0x00,
+0x01,0xC0,0x23,0xB0,0x02,0x11,0x4A,0x80,0x03,0xE0,0x15,0x08,0x1C,0x00,0x98,0x38,
+0xFC,0xE0,0xC1,0x08,0x07,0xE1,0xC1,0xB0,0x1C,0x11,0xC0,0x00,0x06,0x11,0xC0,0xB0,
+0x44,0x0A,0xC0,0xA8,0x00,0x11,0x4A,0x88,0x10,0x04,0xBC,0xB8,0x49,0x11,0xB8,0x00,
+0x01,0x01,0x22,0x34,0x80,0xE1,0xC3,0x03,0x01,0x0C,0x00,0xB4,0xB1,0x00,0x92,0xAA,
+0x00,0x0C,0x5C,0xCB,0xF0,0x0D,0x5B,0xFB,0x01,0x0C,0x5B,0xFB,0xB1,0x00,0xBA,0xAA,
+0x00,0x0C,0x5C,0xCB,0x00,0x11,0x66,0x40,0x09,0x11,0x66,0x40,0x01,0x0C,0x15,0xB0,
+0xFF,0x0A,0x66,0xFB,0x01,0x0A,0x7C,0x73,0x00,0x0C,0x8E,0x43,0x02,0x05,0x0A,0x00,
+0x22,0x11,0x02,0x00,0x01,0x11,0x4A,0x80,0x42,0x11,0x00,0x80,0x0C,0xE0,0x21,0xB2,
+0x22,0x11,0x00,0x80,0x00,0x11,0x4A,0x88,0x45,0x11,0x00,0x00,0x04,0x3C,0x39,0xB2,
+0x01,0x01,0x22,0xB0,0x0A,0x11,0x66,0x40,0x02,0x05,0x0A,0x00,0x22,0x11,0x02,0x00,
+0x01,0x11,0x4A,0x80,0x0C,0x11,0xC0,0xB3,0x00,0x11,0x4A,0x88,0x55,0x11,0x00,0x80,
+0x04,0x11,0x78,0xB2,0x01,0x01,0x22,0xB0,0x00,0x11,0x66,0x40,0x01,0x11,0x04,0x01,
+0x01,0xE2,0xC4,0x01,0x00,0x11,0x66,0x40,0x04,0x4C,0xAD,0x7B,0xFB,0xFF,0x18,0xB8,
+0xB3,0x00,0x24,0x2B,0x08,0x11,0x64,0xDF,0x00,0x0C,0xBE,0xDC,0xCA,0x11,0xDA,0xDB,
+0x0C,0x28,0x95,0x31,0x10,0x3F,0xA7,0xFB,0x04,0x34,0x95,0x31,0x10,0x00,0xBC,0x38,
+0x00,0xC8,0x52,0xDF,0x00,0x0C,0xD4,0x43,0x80,0x9E,0xB1,0xFB,0xA0,0x00,0xDA,0x2B,
+0x10,0x4C,0xB9,0x7B,0xDF,0x9D,0x3B,0x8B,0x20,0x4C,0x15,0x88,0x00,0x9D,0x3B,0x83,
+0x00,0x0C,0x18,0x5E,0x00,0x0C,0xB6,0x5C,0x14,0x10,0x95,0xB1,0x00,0xC8,0x52,0xDF,
+0x08,0x48,0xD1,0xEB,0x02,0x20,0x4C,0x33,0x10,0x00,0xBC,0x38,0x11,0x48,0x15,0x88,
+0x11,0x0A,0xD2,0xE3,0x04,0x0C,0x81,0xB2,0x00,0x0C,0x1C,0xDE,0x00,0x0C,0xD4,0x43,
+0x10,0x20,0xBC,0xB8,0x04,0x11,0x80,0x32,0x00,0x11,0x94,0x88,0x04,0x11,0xA4,0xB0,
+0x04,0x11,0x24,0x05,0x01,0x0C,0x1C,0xB0,0x00,0x11,0x1E,0x08,0x46,0x11,0x26,0x80,
+0x0F,0x11,0x27,0x08,0x00,0x00,0x26,0x3C,0x4A,0x00,0x0C,0xB8,0x01,0xCA,0xED,0x7B,
+0xFE,0xCA,0x95,0x8B,0x40,0xCB,0x97,0x87,0xB0,0x00,0xC6,0xAF,0x02,0x38,0x0D,0xB4,
+0xB1,0x00,0x46,0x2B,0x00,0x0C,0xFA,0x43,0x18,0x11,0xB8,0x80,0x40,0x11,0x90,0x00,
+0xFD,0xE4,0xC9,0x8B,0xFF,0xFF,0xC4,0xB8,0xFF,0x11,0x22,0x8C,0x04,0x11,0x64,0xDF,
+0x00,0x0C,0x9E,0xDD,0x0C,0x94,0x06,0x74,0x10,0x3F,0x7F,0x02,0xB1,0x00,0x2A,0xAC,
+0x00,0x0C,0xF4,0xC3,0x00,0x0C,0xAE,0xDD,0x80,0xB5,0xF5,0x6B,0xFD,0x09,0x0C,0xB8,
+0x08,0x48,0x25,0x7C,0x21,0xB5,0x1B,0x6C,0x18,0x11,0xB8,0x80,0x1B,0x48,0x15,0x88,
+0x00,0x0C,0xD0,0x44,0x02,0x20,0x0C,0xB0,0xF8,0x1C,0x17,0x08,0x00,0x0C,0xF4,0xDE,
+0x02,0x06,0x40,0xB0,0x00,0x0C,0x2E,0xC4,0xFF,0xFF,0x4C,0xBB,0x21,0xB5,0x2F,0xEC,
+0x0B,0x0A,0x2F,0xF4,0x40,0x48,0x31,0xEC,0xA0,0x00,0xF6,0x29,0x0C,0x11,0x32,0x44,
+0x0B,0x11,0x32,0xC4,0xA0,0x00,0xFA,0x29,0x00,0x0C,0x42,0x5D,0x01,0x48,0x3F,0x6C,
+0x00,0x0C,0x9E,0xDD,0x04,0xE4,0xC9,0x03,0x00,0x0C,0xBA,0xC5,0x00,0x0C,0x9E,0xDD,
+0x00,0x0C,0xCA,0x45,0x40,0x4C,0x55,0x7C,0x01,0xB6,0x6B,0x33,0x1B,0x48,0x15,0x88,
+0x01,0x0A,0x54,0x64,0x80,0x11,0x64,0xDF,0xFF,0xFF,0x4C,0xBB,0x02,0x11,0x48,0x00,
+0x0C,0xD4,0x51,0xB2,0x00,0x11,0x48,0x08,0xB1,0x00,0x22,0xAB,0x08,0x49,0xFB,0xEB,
+0x00,0x0C,0xFC,0x43,0xFA,0x09,0x0C,0x38,0xB1,0x00,0x2A,0xAC,0x08,0x48,0x73,0x6E,
+0x04,0x0C,0xB1,0x33,0x00,0x0C,0x22,0x5E,0x00,0x0C,0x0E,0xC5,0x4A,0x00,0x0C,0xB8,
+0x02,0xE4,0xF5,0xEB,0xB0,0x00,0xC6,0xAF,0x00,0x11,0x94,0x88,0x01,0x52,0x14,0xB0,
+0xA1,0x0A,0xA2,0xF4,0x34,0x0A,0x0A,0x74,0x46,0x0A,0x96,0x74,0x39,0x0A,0xA0,0xF4,
+0x41,0x0A,0x62,0xF6,0x5F,0x0A,0x80,0x74,0x27,0x0A,0xF0,0x73,0x00,0x0C,0xF4,0xC3,
+0x18,0x48,0x15,0x88,0xFF,0x0A,0xF0,0x6B,0x01,0x11,0x94,0x80,0x20,0x52,0x14,0x08,
+0x5B,0x0A,0x14,0x28,0x01,0x0A,0x14,0x18,0x03,0x0A,0x14,0x10,0x00,0x48,0xF1,0x7B,
+0x01,0x0A,0x36,0xFC,0x46,0x3A,0x37,0x64,0x00,0x0C,0xF0,0x43,0x00,0x11,0x86,0x09,
+0x46,0x3A,0xF1,0xE3,0x01,0x48,0xF1,0xFB,0xB1,0x00,0x30,0xAB,0x00,0x0C,0xFA,0x43,
+0x00,0x0C,0xF0,0x43,0x02,0x11,0x94,0x80,0x77,0x52,0x14,0x88,0x88,0xB5,0x6B,0x0B,
+0x00,0xB5,0x6B,0x83,0x4A,0x0B,0xC0,0x3B,0x50,0xCA,0x95,0x83,0xB1,0x00,0x64,0xAC,
+0x02,0x11,0x4A,0x80,0x02,0x22,0xF8,0xB3,0x00,0x0C,0xFA,0x43,0x09,0x0A,0xBF,0x74,
+0x0A,0x0A,0xD9,0x74,0x04,0x1F,0xDF,0xFC,0x01,0x00,0x74,0xBE,0x0B,0x48,0xDF,0x7C,
+0x1B,0x48,0x15,0x88,0x08,0x0A,0xDE,0x6C,0x01,0x0A,0xEA,0xF4,0x02,0x0A,0xE4,0x74,
+0x03,0x0A,0xF0,0xF4,0x11,0x0A,0x08,0xF5,0x12,0x0A,0x0E,0xF5,0x13,0x0A,0x14,0xF5,
+0x19,0x0A,0xFC,0x74,0x1A,0x0A,0xF6,0x74,0x1B,0x0A,0x02,0xF5,0x17,0x11,0x2A,0x00,
+0x02,0x00,0x74,0x3A,0xFF,0x20,0x9C,0x3A,0xFF,0x09,0x70,0xBE,0x34,0x00,0x74,0x3A,
+0xFF,0x00,0x9C,0xBA,0x05,0x0A,0x70,0xBE,0x5F,0x00,0x74,0xBA,0xFF,0x20,0x9C,0x3A,
+0x1C,0x0A,0x70,0x3E,0x5F,0x20,0x74,0x3A,0xFF,0x20,0x9C,0x3A,0x1F,0x0A,0x70,0x3E,
+0x5F,0x00,0x74,0xBA,0xFF,0x00,0x9C,0xBA,0x1A,0x0A,0x70,0x3E,0x41,0x00,0x74,0xBA,
+0xFF,0x20,0x9C,0x3A,0x2A,0x0B,0x70,0xBE,0x41,0x20,0x74,0x3A,0xFF,0x20,0x9C,0x3A,
+0x2E,0x0B,0x70,0x3E,0x41,0x00,0x74,0xBA,0xFF,0x00,0x9C,0xBA,0x28,0x0B,0x70,0x3E,
+0x46,0x00,0x74,0x3A,0xFF,0x00,0x9C,0xBA,0x21,0x0A,0x70,0xBE,0x39,0x00,0x74,0xBA,
+0xFF,0x00,0x9C,0xBA,0x2D,0x0A,0x70,0xBE,0x03,0x00,0x74,0x3E,0x20,0x48,0x37,0x6D,
+0x40,0x4C,0x37,0xED,0x1B,0x48,0x15,0x88,0x08,0x0A,0x30,0x7D,0x40,0x01,0x18,0x38,
+0x01,0x0A,0x24,0xED,0x28,0x01,0x18,0xB8,0xB3,0x00,0x46,0x2A,0x00,0x0C,0x4E,0x4F,
+0x7F,0x9E,0x3D,0x8B,0x1B,0x48,0x15,0x88,0x01,0x0A,0xC4,0xEC,0xFF,0x11,0x22,0x8C,
+0x10,0x0A,0x4E,0x6F,0x01,0xB6,0x6B,0x33,0x00,0x0C,0xC4,0x44,0x1B,0x48,0x15,0x88,
+0x01,0x0A,0x3C,0x65,0x0A,0x0A,0x15,0x65,0x08,0x0A,0xDE,0xFC,0x7F,0x9E,0x3D,0x8B,
+0x00,0x0C,0x14,0x45,0x01,0x11,0x94,0x80,0x20,0x52,0x18,0x08,0x5B,0x0C,0x18,0x28,
+0x01,0x0C,0x18,0x18,0xB0,0x00,0x82,0xAF,0x00,0x0C,0xBE,0xC4,0x00,0x00,0x90,0x38,
+0x02,0x3A,0x5B,0x75,0x01,0x3A,0x45,0xF7,0x03,0x3A,0x45,0x77,0x02,0x3A,0xA1,0xB0,
+0x00,0x0C,0x5C,0x45,0x5F,0x00,0xA0,0x38,0x02,0x4E,0xA3,0x30,0x16,0x11,0xA0,0x30,
+0x16,0x11,0xA2,0xB0,0x00,0x11,0x90,0x08,0x41,0x50,0x4E,0x67,0x10,0x10,0x90,0x38,
+0x04,0x24,0xA1,0xB0,0x04,0x10,0xA2,0xB4,0x00,0x11,0x94,0x88,0x01,0x52,0x14,0xB0,
+0xA1,0x0A,0x90,0xF5,0x08,0xCE,0x95,0xFD,0x34,0x0A,0x94,0x75,0x41,0x0A,0x8C,0x65,
+0x02,0xA4,0x45,0x30,0x1F,0x54,0x14,0x08,0x00,0x0A,0x14,0x98,0x80,0x01,0x18,0x38,
+0x00,0x0C,0x18,0x98,0x02,0x12,0x40,0xB0,0xFF,0x21,0x9C,0x75,0x02,0x46,0x45,0x30,
+0x02,0x20,0x70,0x33,0x00,0x0C,0x98,0xC5,0x02,0xB8,0x41,0x30,0x00,0x0C,0x96,0x45,
+0xFF,0xFF,0x40,0xB8,0x00,0x0C,0x9A,0x45,0x02,0xA6,0x41,0x30,0xFF,0x21,0x9C,0x75,
+0x02,0x20,0x14,0x31,0x01,0x11,0x22,0x9C,0x01,0x10,0x22,0x1C,0x0F,0x11,0x94,0x00,
+0x01,0x52,0x6C,0xB3,0x04,0x4C,0xAF,0x6D,0x01,0x48,0xAF,0x7D,0x88,0xB6,0xAF,0xED,
+0x40,0x11,0x64,0xDF,0x00,0x11,0x94,0x88,0x14,0x52,0x20,0x32,0x02,0x11,0x94,0x80,
+0x01,0x52,0x6A,0xB3,0xFB,0xE4,0xC9,0x8B,0x01,0x11,0x94,0x80,0x80,0x52,0x4E,0x7F,
+0x04,0xE4,0xC9,0x87,0xB1,0x00,0x18,0x2C,0x80,0x48,0xC3,0x7D,0xB1,0x00,0x28,0x2C,
+0x00,0x0C,0xF4,0xC3,0xFA,0x09,0x0C,0x38,0x04,0xE4,0x0F,0x7D,0x08,0x48,0x5D,0xEC,
+0xA1,0x00,0x2A,0x2C,0xB1,0x00,0x18,0x2C,0x80,0x48,0xF5,0xEB,0x00,0x0C,0x1C,0xDE,
+0x00,0x0C,0x08,0xDD,0x00,0x0C,0xF4,0xC3,0xCC,0x01,0x1C,0x38,0xEC,0x11,0x5A,0x5F,
+0xB0,0x00,0x18,0x28,0xCC,0x01,0x1C,0x38,0xEF,0x11,0x4A,0xDF,0x00,0x0C,0x60,0x57,
+0xFB,0x1F,0x3F,0x8A,0xA0,0x00,0x6A,0xAB,0x11,0x11,0x02,0x00,0x10,0x02,0xE0,0x39,
+0xFF,0x11,0x22,0x20,0x04,0x11,0xD0,0x31,0x0F,0x02,0xE0,0xB9,0xFF,0x11,0x22,0x20,
+0x04,0x11,0xD0,0x31,0x00,0x00,0xE0,0x39,0x00,0x11,0xB0,0x88,0x32,0x11,0x00,0x00,
+0x02,0xF2,0x91,0x30,0x01,0x01,0x22,0x34,0x20,0x84,0x4E,0xFF,0x20,0x11,0x08,0x01,
+0x1C,0x11,0x66,0x47,0x01,0x9E,0x1D,0xB0,0x08,0x0E,0x0A,0xFE,0xB0,0x01,0x18,0x38,
+0xA3,0x00,0x46,0xAA,0xFF,0xA7,0x25,0x62,0x01,0x11,0x22,0x9C,0x03,0x0C,0x14,0x08,
+0xFF,0x0A,0x14,0x10,0x01,0x0A,0x14,0x18,0x04,0x0A,0x14,0x18,0x03,0x0A,0x14,0x8C,
+0x00,0x0C,0x0F,0x5E,0x22,0x0A,0x7E,0xAE,0x00,0x40,0x0F,0xDE,0xFC,0x3F,0x7F,0x0A,
+0x00,0x3F,0x7F,0x06,0xFF,0xFF,0x14,0x38,0x89,0xDA,0x2D,0xAE,0x00,0xE0,0x14,0xB8,
+0x89,0xD8,0x2D,0x2E,0x04,0xD8,0x81,0x36,0x00,0x20,0x80,0xBA,0x00,0x00,0x84,0x3E,
+0x02,0xCA,0x95,0x87,0x08,0x4C,0x29,0x6A,0x0B,0x0A,0x39,0x66,0x04,0x1F,0x29,0xFA,
+0x88,0xB5,0x3D,0xFE,0x01,0x10,0x22,0x1C,0x80,0xB5,0x6B,0x03,0x02,0x20,0x4C,0x33,
+0x01,0x11,0x22,0x9C,0x00,0x0C,0x46,0xDE,0x77,0xB5,0x6B,0x8F,0x08,0x48,0x4F,0xFE,
+0x02,0x0C,0x0C,0x30,0xB2,0x00,0x2E,0x2F,0x02,0x06,0x18,0x30,0xFF,0xFF,0x4C,0x3F,
+0x00,0x0C,0x42,0x5D,0x01,0x48,0x5D,0x6E,0x80,0x9E,0x3D,0x03,0x00,0x0C,0xB2,0x5D,
+0x04,0x94,0x50,0x32,0x00,0x0C,0xBA,0xC5,0x80,0x9E,0x3D,0x03,0x00,0x0C,0xB2,0x5D,
+0x00,0x0C,0xCA,0x45,0xFF,0xC0,0xF0,0x6B,0xFF,0xC1,0xF0,0xEB,0xF0,0xC2,0xF0,0xEB,
+0x02,0x48,0xF1,0xFB,0x01,0x11,0x94,0x80,0x20,0x52,0xF0,0x6B,0xB1,0x00,0x28,0x2C,
+0x00,0x0C,0xF0,0x43,0x04,0x28,0xB1,0x33,0xB2,0x00,0x22,0xAE,0xFF,0xFF,0x14,0x38,
+0x82,0x40,0xB1,0x2B,0x82,0x42,0xB5,0x2B,0x01,0x00,0x14,0xB8,0x83,0xD8,0xB1,0x2B,
+0x00,0x00,0x14,0x38,0x84,0xDA,0xB5,0xAB,0x02,0xD8,0x15,0xB0,0x83,0x28,0x51,0x2A,
+0x02,0xDA,0x15,0x30,0x84,0x2A,0x55,0xAA,0x28,0x01,0x18,0xB8,0xB3,0x00,0x46,0x2A,
+0x00,0x0C,0xF6,0x54,0x00,0x0C,0x0E,0xC5,0x02,0x11,0x4A,0x80,0x02,0xFC,0x45,0xB0,
+0x10,0x9E,0xD5,0xEE,0x00,0x11,0xFE,0x8B,0xFF,0xB4,0x15,0x90,0x01,0x0A,0xFC,0x1B,
+0x04,0x11,0x94,0x80,0x01,0x52,0xF6,0xB3,0xFF,0xFB,0xBF,0xFE,0x44,0xFF,0x0F,0xA8,
+0x01,0x07,0x14,0xB0,0x00,0xFB,0xC5,0x7E,0xFF,0x0A,0x14,0x10,0x00,0xFB,0xF7,0x0B,
+0x33,0xFF,0x17,0xA8,0x00,0x11,0x4A,0x88,0x00,0x0C,0xF4,0xDE,0x00,0x0C,0xBA,0x4E,
+0xB0,0x00,0x52,0xAD,0x02,0x11,0x4A,0x80,0xFF,0xFB,0xC5,0xEE,0xF8,0xFF,0xFF,0x8B,
+0x08,0xFF,0xFF,0x1B,0x00,0x0C,0xC6,0x46,0x01,0xFF,0xFF,0x1B,0x01,0xFE,0x15,0x30,
+0x00,0xFF,0x15,0x18,0x80,0x0A,0xD0,0xFE,0x07,0xFF,0xA7,0x6E,0x00,0x0C,0xA2,0xC6,
+0x00,0x11,0x4A,0x88,0x01,0xB5,0xEF,0x7E,0x00,0x11,0x4A,0x88,0xB1,0x00,0xAE,0xA9,
+0x02,0x0C,0x1C,0x98,0x10,0x9E,0xE9,0xEE,0xF2,0x11,0x26,0x80,0x10,0x9E,0x3D,0x03,
+0x04,0x11,0x60,0x33,0xF5,0x45,0x8A,0x08,0xF5,0xCE,0x9D,0x0B,0x00,0x0C,0xEA,0xC6,
+0xF3,0x11,0x26,0x00,0x02,0x22,0x26,0xB0,0x00,0x0A,0x54,0x5F,0x18,0x11,0xB8,0x80,
+0xEF,0xCA,0x95,0x8B,0xA0,0x00,0x5C,0x2A,0x00,0x0C,0x38,0x5F,0x00,0x12,0x24,0x7A,
+0xFF,0x0C,0x18,0x98,0x00,0x12,0x26,0x90,0x02,0x22,0x0C,0x30,0x02,0xA4,0x45,0x30,
+0x2E,0x0B,0x14,0x28,0x80,0x01,0x18,0x38,0x00,0x0C,0x18,0x98,0x02,0x0C,0x1C,0xB0,
+0x02,0x12,0x40,0xB0,0xFF,0xFF,0x26,0xB8,0x02,0x06,0x44,0x30,0x02,0x0A,0x0C,0x30,
+0xB1,0x00,0x9C,0x2C,0x02,0x06,0x14,0x30,0x00,0x0C,0x4E,0x4F,0xF8,0x1C,0x15,0x88,
+0x00,0x0B,0x1E,0xE7,0x02,0x46,0x15,0x30,0x8A,0x22,0x28,0xAA,0x19,0x11,0x2A,0x80,
+0x08,0x9E,0x25,0xFF,0x02,0x45,0x8A,0x84,0xF5,0x45,0x8A,0x8C,0xF8,0x1C,0x17,0x08,
+0xB2,0x00,0x38,0xAF,0x00,0x12,0x26,0x00,0x00,0x0C,0x36,0xC7,0xF8,0x1C,0x17,0x08,
+0xB2,0x00,0x38,0xAF,0xFF,0x0A,0x14,0x10,0x00,0x12,0x26,0x88,0xFF,0x11,0x22,0x8C,
+0x6A,0x0B,0x14,0x28,0xB0,0x01,0x18,0x38,0x00,0x0C,0x18,0x98,0x02,0x0C,0x1C,0xB0,
+0x11,0x0B,0x0E,0xA8,0x01,0x07,0x14,0x34,0x00,0x00,0x90,0x38,0x18,0x11,0xA0,0xB0,
+0x18,0x10,0xA2,0x34,0xA1,0x00,0x2E,0xAA,0xA1,0x00,0x2C,0x2A,0xFF,0x11,0x22,0x8C,
+0xA1,0x00,0x16,0x2A,0xA3,0x00,0x54,0xAA,0xA3,0x00,0x34,0xAA,0xA1,0x00,0x0C,0xA9,
+0xA1,0x00,0x86,0x2A,0xA1,0x00,0x18,0xAA,0xA1,0x00,0x52,0x2A,0xA1,0x00,0x4C,0x2A,
+0xA0,0x00,0x06,0xA8,0xA3,0x00,0xDE,0x2A,0xA3,0x00,0x14,0xAB,0xA3,0x00,0xBE,0x2A,
+0x00,0x11,0x02,0x88,0x01,0x0C,0x8C,0x31,0x01,0x01,0x22,0x34,0x11,0x11,0x02,0x00,
+0xF5,0x45,0x8A,0x08,0xF7,0xA0,0x40,0x89,0xFB,0x9E,0x3D,0x8B,0x00,0x00,0x90,0x3B,
+0xC0,0xCA,0x95,0x0B,0x02,0x05,0x0A,0x00,0x40,0x3D,0x7A,0x00,0xFF,0xE0,0xC0,0x81,
+0xB3,0x00,0x88,0xAA,0x01,0x01,0x22,0xB0,0x01,0xE4,0xC9,0x87,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+0x00,0x0C,0x26,0x59,0x00,0x0C,0x06,0xD0,0xA0,0x00,0xFA,0xAE,0x00,0x0C,0x40,0x59,
+0x02,0x86,0xA9,0xB3,0xFF,0xD5,0x1F,0x70,0x02,0xD4,0x45,0xB0,0x84,0x01,0x18,0xB8,
+0x00,0x0C,0xB6,0xDB,0x01,0x0A,0x1A,0xE0,0x44,0xC6,0x0F,0xA8,0x01,0x07,0x14,0xB0,
+0x00,0x9C,0x69,0x68,0x02,0xAE,0xA9,0xB3,0x00,0x0C,0x0A,0x40,0x00,0x0C,0x3C,0xD9,
+0x02,0x84,0x15,0xB0,0x8B,0x10,0x72,0x28,0x83,0x10,0x08,0x2B,0x02,0x80,0xA9,0xB3,
+0x02,0xD4,0x45,0xB0,0x02,0xAE,0x15,0x30,0xFF,0xFF,0x5C,0x3B,0x00,0x00,0x44,0x38,
+0x02,0x0A,0x00,0x33,0xFF,0x0B,0x36,0x60,0x02,0x0A,0x04,0xB3,0x00,0x0C,0x52,0x59,
+0xFF,0x87,0x3F,0xE0,0x02,0xD4,0x0D,0xB3,0x00,0x0C,0x44,0x40,0x02,0x88,0x45,0xB0,
+0x02,0xD4,0x5D,0xB3,0x00,0x00,0x44,0x38,0x02,0xD4,0x11,0x33,0x02,0xD4,0x45,0xB0,
+0x00,0x11,0xB2,0x89,0x0F,0xD8,0x00,0x0B,0xF0,0xD8,0x02,0x8B,0x0C,0x11,0xB2,0x01,
+0x08,0xD8,0x08,0xB3,0x08,0xD8,0x28,0x33,0x00,0x0C,0x20,0x5A,0x01,0x0A,0x38,0xB3,
+0x01,0x0B,0x54,0x33,0x00,0x0C,0x78,0x58,0x04,0x9D,0x3B,0x03,0x01,0x11,0x14,0x00,
+0x00,0x9C,0x65,0xF8,0x01,0xA8,0x51,0x1B,0x11,0x0A,0x14,0xA8,0xFF,0x0A,0x60,0x68,
+0x02,0x11,0xB2,0x81,0x02,0xD8,0x04,0xB3,0x00,0x0C,0x56,0xD9,0x02,0xD4,0x45,0xB0,
+0xA0,0x00,0xC4,0x2E,0x00,0x0C,0x56,0xD9,0x00,0x0C,0x52,0x59,0xA0,0x00,0xFC,0xAE,
+0x00,0x00,0x44,0x38,0x02,0x86,0x15,0x30,0xFF,0x0B,0xA0,0xF0,0x8A,0xD4,0x9B,0xA8,
+0x02,0x0A,0x0C,0x30,0x02,0x0A,0x44,0x30,0x01,0x9C,0x15,0xB0,0x02,0xD4,0x45,0xB0,
+0x00,0x9C,0x99,0xF8,0x02,0x06,0x44,0x30,0x02,0xA6,0xAD,0xB3,0x08,0xB4,0xB1,0x33,
+0x02,0xD4,0x45,0xB0,0x02,0xD6,0x4D,0xB3,0x08,0xD8,0x69,0x33,0x00,0x11,0x6E,0x0F,
+0x02,0x06,0x14,0x30,0x02,0x0A,0x44,0x30,0x02,0xAE,0x15,0x30,0x00,0x0C,0x7C,0xC0,
+0x02,0xD4,0x45,0x34,0x02,0x22,0x0C,0x30,0x00,0x00,0x44,0x38,0x01,0x00,0x18,0xB8,
+0x02,0x8C,0x15,0x30,0x83,0x0C,0x04,0xA8,0xE3,0x8C,0xB1,0xA8,0x00,0x0C,0xB4,0x40,
+0x02,0x8C,0x19,0x33,0x00,0x0C,0xA8,0xC0,0x02,0x06,0x44,0x30,0x22,0x11,0x02,0x00,
+0x02,0x0A,0xEC,0xB3,0x01,0x01,0x22,0xB0,0xB1,0x00,0x64,0xAC,0x61,0x0C,0xC0,0xBB,
+0x40,0xCA,0x95,0x87,0x08,0x84,0x49,0x31,0x02,0x22,0x48,0xB1,0x40,0xCE,0xCF,0xF8,
+0x22,0x11,0x02,0x00,0x02,0xF6,0x15,0xB0,0x01,0x01,0x22,0xB0,0x02,0x0A,0x48,0xB1,
+0xFC,0xFF,0x14,0x38,0x83,0x90,0x48,0xA9,0x02,0x11,0x48,0xB1,0xB1,0x00,0xB2,0x29,
+0x01,0x0A,0xC4,0xB3,0x02,0x0C,0x0C,0x30,0x00,0x0C,0x0A,0xD9,0x02,0x06,0x18,0x30,
+0x0C,0x00,0x14,0x38,0x83,0x90,0x14,0x28,0xB1,0x00,0xEA,0xA9,0x20,0x11,0xB8,0x00,
+0xB1,0x00,0x06,0x2A,0x02,0x0A,0x0C,0x30,0x02,0x0C,0x1C,0x98,0x28,0xC6,0x27,0x80,
+0x55,0x11,0x02,0x00,0x01,0x43,0xF9,0x68,0x08,0xCC,0xF9,0xE8,0x09,0x11,0xFA,0x40,
+0x08,0x11,0xFA,0xC0,0x01,0x01,0x22,0xB0,0x30,0xCC,0x15,0x88,0x80,0x0A,0x14,0x00,
+0x00,0x0C,0x26,0x00,0x02,0x06,0x26,0xB0,0xB1,0x00,0x58,0xAC,0x00,0xE2,0x35,0xDA,
+0xA0,0x00,0x5C,0x2A,0x00,0x0C,0x26,0x59,0x00,0x0C,0xDC,0xD2,0x80,0x45,0xDC,0xFA,
+0x01,0xC9,0xDD,0x6A,0x00,0x11,0x8C,0x09,0x53,0x11,0x3A,0xD9,0x01,0xC9,0x93,0x87,
+0x02,0x0A,0x0C,0x30,0x00,0x0C,0x26,0x59,0x00,0x0C,0x22,0x51,0x00,0x0C,0x14,0xD9,
+0x00,0x11,0x18,0x08,0x02,0x06,0x14,0x30,0xA1,0x00,0x02,0x29,0x02,0x22,0x0C,0x30,
+0x00,0x00,0x44,0x38,0x02,0x90,0x15,0xB0,0x82,0x10,0x14,0x28,0x01,0x10,0x22,0x98,
+0x84,0x11,0x14,0xA8,0x83,0x8E,0x15,0xA8,0x02,0x06,0x44,0x30,0x80,0x0B,0x80,0xEB,
+0x01,0x11,0x22,0x9C,0xA1,0x00,0x7E,0xAA,0x00,0x80,0x18,0xB8,0x00,0x0C,0x42,0xC1,
+0x00,0x40,0x18,0xB8,0x00,0x00,0x44,0x38,0x02,0x8A,0x15,0x30,0x89,0x0C,0x44,0xA9,
+0x80,0x0C,0x04,0xA8,0xE3,0x8A,0x4F,0xA9,0xFF,0x11,0x22,0x8C,0x02,0x8A,0x15,0x33,
+0x00,0x0C,0x44,0xC1,0xFF,0x7F,0x18,0xB8,0x00,0x0C,0x58,0x41,0xFF,0xBF,0x18,0xB8,
+0x00,0x00,0x44,0x38,0x02,0x8A,0x15,0x30,0x81,0x0C,0x04,0x28,0xE3,0x8A,0x63,0x29,
+0xFF,0x11,0x22,0x8C,0x02,0x8A,0x15,0x33,0x00,0x0C,0x5A,0xC1,0x80,0xCC,0x6B,0xE9,
+0x10,0x4E,0x6D,0xE9,0x29,0x11,0x2A,0x80,0x02,0xA6,0x15,0xB0,0x8B,0x10,0xDC,0x2A,
+0x16,0x11,0x34,0xC2,0x04,0x9F,0x7B,0xF9,0x02,0xAC,0x15,0xB0,0x89,0x10,0x7A,0xA9,
+0x04,0x9F,0x79,0xE9,0x03,0xB4,0xB1,0xB3,0x00,0x11,0xB6,0x8B,0x02,0xB8,0xA5,0x33,
+0x22,0x11,0x02,0x00,0x02,0xA2,0xE8,0xB3,0x02,0xD2,0x45,0x31,0xFF,0xD8,0x91,0x69,
+0xFF,0xD9,0x91,0xE9,0xFF,0xDA,0x91,0xE9,0xF7,0x11,0x30,0x5A,0x01,0x01,0x22,0x34,
+0x04,0xD8,0x51,0xB0,0x02,0x11,0x4A,0x80,0x04,0x28,0xE8,0x33,0x00,0x0C,0xAC,0xC1,
+0x22,0x11,0x02,0x00,0x02,0x11,0x4A,0x80,0x80,0xF7,0xAD,0xF9,0x03,0xB4,0x51,0x30,
+0x00,0x11,0x56,0x08,0x04,0xF4,0x51,0x30,0xFF,0x11,0x22,0x20,0x80,0x2B,0xAC,0xF9,
+0x00,0x11,0xEE,0x0B,0x80,0xC9,0x93,0x03,0x00,0x11,0x4A,0x88,0x01,0x01,0x22,0x34,
+0xC0,0x5F,0x15,0x88,0xC0,0x0A,0xCA,0xF1,0x18,0x10,0x95,0xB1,0x18,0x00,0x14,0x38,
+0x83,0x58,0x99,0xA8,0x04,0x11,0x4E,0x5A,0x00,0x11,0x4E,0xDA,0x10,0x50,0xC1,0xB0,
+0x10,0x01,0xBC,0x3C,0x07,0x11,0x94,0x01,0x13,0x11,0x95,0xB1,0x04,0x11,0x94,0x31,
+0x00,0x0C,0xCC,0xC1,0x18,0x10,0x95,0xB1,0x18,0x11,0x94,0xB1,0x30,0x11,0x54,0x5A,
+0x10,0x01,0xBC,0x3C,0x04,0x30,0xB0,0xB3,0x02,0xDA,0x41,0xB0,0x0F,0xCB,0xFF,0x69,
+0x01,0xCD,0xFD,0xF9,0x80,0xCC,0xFD,0xE9,0x40,0xCE,0xFD,0xF9,0x02,0x44,0x15,0xB0,
+0x88,0xF6,0xFD,0xA9,0x11,0x11,0x00,0x80,0x02,0xDA,0x41,0xB0,0x02,0x46,0x45,0x30,
+0x00,0x00,0x90,0xB9,0x10,0x00,0xBC,0x38,0x04,0x58,0x99,0xB0,0x10,0x50,0xC1,0xB0,
+0x00,0x11,0xBE,0xDA,0x20,0x13,0x08,0x39,0x49,0x11,0xB8,0x00,0x00,0x0C,0x5C,0xDA,
+0x80,0xCA,0x95,0x03,0x02,0x0D,0xC0,0xBF,0x27,0x11,0x00,0xC2,0x09,0x11,0x00,0xC2,
+0x00,0x0C,0xBE,0xDA,0xA1,0x00,0xA8,0xAE,0xB0,0x00,0x18,0x28,0x02,0x05,0x0A,0x00,
+0x0F,0xCB,0x13,0xEA,0x80,0xC8,0x19,0x6A,0x08,0x5D,0x32,0xFA,0x10,0xC9,0x93,0x03,
+0x00,0x0C,0x1C,0x42,0x08,0x11,0x18,0x00,0xB0,0x00,0xB6,0xAD,0x09,0x11,0x1A,0x42,
+0x05,0x11,0x1A,0x42,0x00,0x0C,0xBE,0xDA,0x15,0x11,0x34,0xDA,0xA0,0x00,0x2C,0x2D,
+0x02,0x22,0x0C,0x30,0x00,0x00,0x44,0x38,0xB8,0x01,0x18,0xB8,0x01,0xC6,0x15,0xB0,
+0x00,0x0C,0x18,0x98,0x01,0x12,0x14,0x30,0x01,0x96,0x17,0x30,0xA1,0x00,0xB8,0xAF,
+0xA1,0x00,0x52,0x2A,0xA0,0x00,0x06,0xA8,0x01,0x0C,0xD6,0xB3,0x02,0x20,0xD8,0xB3,
+0xB0,0x00,0x18,0x28,0x02,0x05,0x0A,0x00,0x04,0x3A,0x32,0x7A,0x01,0xEB,0x69,0x30,
+0x01,0xFA,0x6B,0xB0,0x02,0xEC,0x6D,0x30,0xFD,0x05,0x0A,0x0C,0x00,0x00,0x14,0x38,
+0x88,0x12,0x80,0x2B,0x88,0x12,0x80,0x2B,0x01,0x11,0x22,0x9C,0x01,0x0C,0xF6,0x30,
+0x01,0x0A,0xF0,0x30,0x02,0x11,0xF2,0x34,0x01,0x0C,0x98,0xB0,0x03,0x11,0x9A,0xB0,
+0x01,0x0C,0x14,0x30,0x04,0x11,0x4E,0x42,0x01,0x11,0x02,0x80,0x02,0x22,0x44,0x30,
+0x21,0x11,0x00,0x80,0x00,0x0C,0x6A,0xC2,0x10,0x11,0x02,0x80,0x02,0x22,0x44,0x30,
+0x20,0x11,0x00,0x00,0x02,0x22,0x44,0x30,0x01,0x01,0x22,0x34,0x82,0x10,0x14,0x28,
+0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,0x02,0x0A,0x0C,0x30,0xFF,0xFF,0x14,0x38,
+0x84,0x11,0x1C,0x28,0x02,0x06,0x14,0x30,0x83,0x0C,0x18,0x28,0x00,0x00,0x14,0x38,
+0x84,0x0E,0x1C,0x2C,0x09,0x10,0x00,0xB1,0x01,0x11,0x74,0x00,0x00,0x0C,0xA4,0x42,
+0x00,0x0C,0x8C,0x5A,0x00,0x0C,0x96,0xC2,0x00,0x0C,0x9A,0xDA,0x10,0x11,0x06,0x81,
+0x04,0x11,0x0E,0x01,0x01,0x11,0x10,0x85,0x00,0x0C,0x9A,0xDA,0x80,0x11,0x08,0x01,
+0x08,0x11,0x10,0x85,0xFF,0x11,0x00,0x01,0xF0,0xEF,0x04,0xB9,0x7F,0xFF,0x08,0xB9,
+0xFF,0xFB,0x0C,0x39,0x10,0x11,0x10,0x01,0x00,0x11,0x02,0x88,0x00,0x0C,0xB0,0x5A,
+0x11,0x11,0x00,0x80,0x00,0x0C,0xB8,0xDA,0x01,0x01,0x22,0x34,0x11,0x00,0xB8,0xF2,
+0xFF,0x11,0x8C,0x00,0xFF,0x11,0x8E,0x80,0x7F,0x03,0x24,0x39,0x02,0x11,0x74,0x84,
+0xFF,0x11,0x8C,0x00,0xFF,0x11,0x8E,0x80,0x02,0x11,0x74,0x84,0x00,0x0C,0xCE,0x5A,
+0x02,0x4C,0x15,0x30,0x01,0x0A,0x04,0x80,0x01,0x0C,0x06,0x30,0xE3,0x4C,0xCB,0xAA,
+0x00,0x0C,0xD8,0xC2,0x02,0x4C,0x99,0x32,0x00,0x0C,0xC0,0xC2,0x02,0x06,0x14,0x30,
+0x01,0x05,0x0C,0x30,0x00,0x11,0x0C,0x08,0x02,0x05,0x0A,0x00,0x02,0x0A,0x0C,0xB4,
+0x01,0x06,0x0A,0x30,0x01,0x06,0x22,0x30,0xFF,0x11,0x22,0x8C,0x01,0x0C,0x1A,0xB0,
+0x00,0x11,0xE4,0xC2,0x00,0x11,0x1A,0x88,0x00,0x0C,0xCE,0x5A,0x02,0x48,0x15,0xB0,
+0x80,0x0C,0x04,0xA8,0xE3,0x48,0xEF,0x2A,0x00,0x0C,0xD8,0xC2,0x02,0x48,0x91,0x32,
+0x00,0x0C,0xE6,0x42,0x01,0x0C,0x1A,0xB0,0xFF,0x11,0xF6,0xC2,0x00,0x0C,0xCE,0x5A,
+0x02,0x48,0x15,0xB0,0x81,0x0C,0x04,0x28,0xE3,0x48,0x01,0xAB,0x00,0x0C,0xD8,0xC2,
+0x02,0x48,0x91,0x32,0x00,0x0C,0xF8,0x42,0x00,0x11,0x1A,0x88,0x00,0x0C,0xCE,0x5A,
+0x02,0x48,0x15,0xB0,0x82,0x0C,0x04,0x28,0xE3,0x48,0x11,0x2B,0x00,0x0C,0xD8,0xC2,
+0x02,0x48,0x91,0x32,0x00,0x0C,0x08,0xC3,0x00,0x11,0x1A,0x88,0x00,0x0C,0xCE,0x5A,
+0x02,0x4C,0x15,0x30,0x80,0x0C,0x04,0xA8,0xE3,0x4C,0x21,0xAB,0x00,0x0C,0xD8,0xC2,
+0x02,0x4C,0x99,0x32,0x00,0x0C,0x18,0x43,0x00,0x0C,0xCE,0x5A,0x02,0x4C,0x15,0x30,
+0x81,0x0C,0x04,0x28,0xE3,0x4C,0x2F,0x2B,0x00,0x0C,0xD8,0xC2,0x02,0x4C,0x99,0x32,
+0x00,0x0C,0x26,0xC3,0x00,0x0C,0xCE,0x5A,0x02,0x22,0x0C,0x30,0x00,0x00,0x44,0x38,
+0x44,0xC6,0x0F,0xA8,0x01,0x07,0x1C,0x30,0x02,0xAE,0x19,0x30,0xFF,0x0E,0x14,0x90,
+0x00,0x0C,0xB0,0x8B,0x01,0x0D,0xB2,0xB3,0x0F,0xCB,0x49,0xFB,0x00,0xD9,0xB3,0x0B,
+0x01,0x0E,0x14,0xB0,0x03,0xC8,0x53,0xEB,0xC0,0xCA,0x53,0x6B,0x30,0xCB,0x53,0xEB,
+0x00,0xD8,0xB1,0x83,0x02,0x0C,0x14,0x30,0x02,0xD8,0x05,0x30,0xE3,0xAE,0x5D,0x2B,
+0x02,0x06,0x44,0x30,0x00,0x0C,0xD8,0xC2,0x02,0xAE,0x5D,0x33,0x00,0x0C,0x3C,0x43,
+0x02,0x48,0x15,0xB0,0x02,0x0B,0x60,0x6B,0x01,0x0A,0x04,0xB0,0x02,0x0B,0x06,0x80,
+0xE3,0x48,0x6D,0xAB,0xFF,0x11,0x22,0x8C,0x02,0x48,0x91,0x32,0x00,0x0C,0x60,0x43,
+0xFF,0xFD,0x18,0xB8,0x00,0x0C,0xF6,0xC2,0x00,0x0C,0x60,0x5B,0x40,0x49,0x7F,0xEB,
+0x00,0x0C,0x82,0x5B,0x00,0x0C,0x70,0xDB,0x01,0x11,0x22,0x9C,0x00,0x0C,0x70,0xDB,
+0x01,0x10,0x22,0x1C,0x02,0x05,0x0A,0x00,0x02,0x4A,0x15,0x30,0x01,0x0A,0x04,0xB0,
+0x01,0x0B,0x06,0x98,0xE3,0x4A,0x8F,0x2B,0x00,0x0C,0xB2,0x43,0x02,0x4A,0x95,0x32,
+0x00,0x0C,0x84,0x43,0x02,0x05,0x0A,0x00,0x02,0x4A,0x15,0x30,0x01,0x0A,0x04,0xB0,
+0xFF,0x0B,0x06,0x18,0xE3,0x4A,0x9F,0xAB,0x00,0x0C,0xB2,0x43,0x02,0x4A,0x95,0x32,
+0x00,0x0C,0x94,0xC3,0x02,0x05,0x0A,0x00,0x02,0x4A,0x15,0x30,0xFF,0x0A,0x04,0x18,
+0x01,0x0B,0x06,0xB0,0xE3,0x4A,0xAF,0xAB,0x00,0x0C,0xB2,0x43,0x02,0x4A,0x95,0x32,
+0x00,0x0C,0xA4,0xC3,0xF0,0x04,0xDC,0xEA,0xFD,0x05,0x0A,0x0C,0x0C,0x11,0xB2,0x01,
+0x01,0x12,0x14,0x30,0x00,0xD8,0xC2,0x63,0x1F,0xD9,0x14,0x08,0x14,0x0A,0xB8,0xE3,
+0x01,0x11,0x14,0x84,0xFF,0xD9,0xB2,0x99,0xFF,0x0C,0x18,0x98,0xFF,0x12,0x14,0x10,
+0xFF,0x11,0x16,0x00,0x01,0x10,0x22,0x98,0x84,0x11,0x14,0xA8,0x01,0xD8,0xB0,0xB3,
+0x00,0x11,0xB2,0x0B,0x83,0xD8,0x15,0xA8,0x80,0x0B,0xD8,0x6B,0x02,0x11,0x14,0x84,
+0x00,0x11,0x14,0x8C,0xB3,0x00,0xCE,0x2A,0x02,0xA8,0x15,0x30,0x01,0x0A,0x04,0xB0,
+0x01,0x0B,0x06,0x98,0xE3,0xA8,0xE7,0xAB,0xA3,0x00,0xD8,0x2A,0x02,0xA8,0x51,0x33,
+0x00,0x0C,0xDC,0xC3,0x04,0x9D,0xDD,0x7A,0xB3,0x00,0xCE,0x2A,0x02,0xA8,0x15,0x30,
+0x01,0x0A,0x04,0xB0,0xFF,0x0B,0x06,0x18,0xE3,0xA8,0xF9,0xAB,0xA3,0x00,0xD8,0x2A,
+0x02,0xA8,0x51,0x33,0x00,0x0C,0xEE,0x43,0x00,0x00,0x01,0xB8,0x00,0x00,0x01,0xB8,
+};
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_task.c newtree/drivers/scsi/aic94xx/aic94xx_task.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_task.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_task.c	2006-04-01 05:35:45.915489500 -0500
@@ -0,0 +1,645 @@
+/*
+ * Aic94xx SAS/SATA Tasks
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_task.c#51 $
+ */
+
+#include <linux/spinlock.h>
+#include <scsi/sas/sas_task.h>
+#include <scsi/sas/sas_frames.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a);
+static void asd_unbuild_smp_ascb(struct asd_ascb *a);
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a);
+
+static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+	asd_ha->seq.can_queue += num;
+	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+}
+
+/* PCI_DMA_... to our direction translation.
+ */
+static const u8 data_dir_flags[] = {
+	[PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,	/* UNSPECIFIED */
+	[PCI_DMA_TODEVICE]      = DATA_DIR_OUT, /* OUTBOUND */
+	[PCI_DMA_FROMDEVICE]    = DATA_DIR_IN, /* INBOUND */
+	[PCI_DMA_NONE]          = DATA_DIR_NONE, /* NO TRANSFER */
+};
+
+static inline int asd_map_scatterlist(struct sas_task *task,
+				      struct sg_el *sg_arr,
+				      unsigned long gfp_flags)
+{
+	struct asd_ascb *ascb = task->lldd_task;
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct scatterlist *sc;
+	int num_sg, res;
+
+	if (task->data_dir == PCI_DMA_NONE)
+		return 0;
+
+	if (task->num_scatter == 0) {
+		void *p = task->scatter;
+		dma_addr_t dma = pci_map_single(asd_ha->pcidev, p,
+						task->total_xfer_len,
+						task->data_dir);
+		sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
+		sg_arr[0].size = cpu_to_le32(task->total_xfer_len);
+		sg_arr[0].flags |= ASD_SG_EL_LIST_EOL;
+		return 0;
+	}
+
+	num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+			    task->data_dir);
+	if (num_sg == 0)
+		return -ENOMEM;
+
+	if (num_sg > 3) {
+		int i;
+
+		ascb->sg_arr = asd_alloc_coherent(asd_ha,
+						  num_sg*sizeof(struct sg_el),
+						  gfp_flags);
+		if (!ascb->sg_arr) {
+			res = -ENOMEM;
+			goto err_unmap;
+		}
+		for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+			struct sg_el *sg =
+				&((struct sg_el *)ascb->sg_arr->vaddr)[i];
+			sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc));
+			sg->size = cpu_to_le32((u32)sg_dma_len(sc));
+			if (i == num_sg-1)
+				sg->flags |= ASD_SG_EL_LIST_EOL;
+		}
+
+		for (sc = task->scatter, i = 0; i < 2; i++, sc++) {
+			sg_arr[i].bus_addr =
+				cpu_to_le64((u64)sg_dma_address(sc));
+			sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+		}
+		sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr);
+		sg_arr[1].flags |= ASD_SG_EL_LIST_EOS;
+
+		memset(&sg_arr[2], 0, sizeof(*sg_arr));
+		sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle);
+	} else {
+		int i;
+		for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+			sg_arr[i].bus_addr =
+				cpu_to_le64((u64)sg_dma_address(sc));
+			sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+		}
+		sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL;
+	}
+
+	return 0;
+err_unmap:
+	pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+		     task->data_dir);
+	return res;
+}
+
+static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct sas_task *task = ascb->uldd_task;
+
+	if (task->data_dir == PCI_DMA_NONE)
+		return;
+
+	if (task->num_scatter == 0) {
+		dma_addr_t dma = (dma_addr_t)
+		       le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr);
+		pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len,
+				 task->data_dir);
+		return;
+	}
+
+	asd_free_coherent(asd_ha, ascb->sg_arr);
+	pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+		     task->data_dir);
+}
+
+/* ---------- Task complete tasklet ---------- */
+
+static void asd_get_response_tasklet(struct asd_ascb *ascb,
+				     struct done_list_struct *dl)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct sas_task *task = ascb->uldd_task;
+	struct task_status_struct *ts = &task->task_status;
+	unsigned long flags;
+	struct tc_resp_sb_struct {
+		__le16 index_escb;
+		u8     len_lsb;
+		u8     flags;
+	} __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+/* 	int  size   = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */
+	int  edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+	struct asd_ascb *escb;
+	struct asd_dma_tok *edb;
+	void *r;
+
+	spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+	escb = asd_tc_index_find(&asd_ha->seq,
+				 (int)le16_to_cpu(resp_sb->index_escb));
+	spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+	if (!escb) {
+		ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+		return;
+	}
+
+	ts->buf_valid_size = 0;
+	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+	r = edb->vaddr;
+	if (task->task_proto == SAS_PROTO_SSP) {
+		struct ssp_response_iu *iu =
+			r + 16 + sizeof(struct ssp_frame_hdr);
+
+		ts->residual = le32_to_cpu(*(__le32 *)r);
+		ts->resp = SAS_TASK_COMPLETE;
+		if (iu->datapres == 0)
+			ts->stat = iu->status;
+		else if (iu->datapres == 1)
+			ts->stat = iu->resp_data[3];
+		else if (iu->datapres == 2) {
+			ts->stat = SAM_CHECK_COND;
+			ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
+					 be32_to_cpu(iu->sense_data_len));
+			memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
+			if (iu->status != SAM_CHECK_COND) {
+				ASD_DPRINTK("device %llx sent sense data, but "
+					    "stat(0x%x) is not CHECK_CONDITION"
+					    "\n",
+					    SAS_ADDR(task->dev->sas_addr),
+					    ts->stat);
+			}
+		}
+	}  else {
+		struct ata_task_resp *resp = (void *) &ts->buf[0];
+
+		ts->residual = le32_to_cpu(*(__le32 *)r);
+
+		if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
+			resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
+			memcpy(&resp->ending_fis[0], r+16, 24);
+			ts->buf_valid_size = sizeof(*resp);
+		}
+	}
+
+	asd_invalidate_edb(escb, edb_id);
+}
+
+static void asd_task_tasklet_complete(struct asd_ascb *ascb,
+				      struct done_list_struct *dl)
+{
+	struct sas_task *task = ascb->uldd_task;
+	struct task_status_struct *ts = &task->task_status;
+	unsigned long flags;
+	u8 opcode = dl->opcode;
+
+	asd_can_dequeue(ascb->ha, 1);
+
+Again:
+	switch (opcode) {
+	case TC_NO_ERROR:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAM_GOOD;
+		break;
+	case TC_UNDERRUN:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_DATA_UNDERRUN;
+		ts->residual = le32_to_cpu(*(__le32 *)dl->status_block);
+		break;
+	case TC_OVERRUN:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_DATA_OVERRUN;
+		ts->residual = 0;
+		break;
+	case TC_SSP_RESP:
+	case TC_ATA_RESP:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_PROTO_RESPONSE;
+		asd_get_response_tasklet(ascb, dl);
+		break;
+	case TF_OPEN_REJECT:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_OPEN_REJECT;
+		if (dl->status_block[1] & 2)
+			ts->open_rej_reason = 1 + dl->status_block[2];
+		else if (dl->status_block[1] & 1)
+			ts->open_rej_reason = (dl->status_block[2] >> 4)+10;
+		else
+			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+		break;
+	case TF_OPEN_TO:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_OPEN_TO;
+		break;
+	case TF_PHY_DOWN:
+	case TU_PHY_DOWN:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_PHY_DOWN;
+		break;
+	case TI_PHY_DOWN:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_PHY_DOWN;
+		break;
+	case TI_BREAK:
+	case TI_PROTO_ERR:
+	case TI_NAK:
+	case TI_ACK_NAK_TO:
+	case TF_SMP_XMIT_RCV_ERR:
+	case TC_ATA_R_ERR_RECV:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_INTERRUPTED;
+		break;
+	case TF_BREAK:
+	case TU_BREAK:
+	case TU_ACK_NAK_TO:
+	case TF_SMPRSP_TO:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_DEV_NO_RESPONSE;
+		break;
+	case TF_NAK_RECV:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_NAK_R_ERR;
+		break;
+	case TA_I_T_NEXUS_LOSS:
+		opcode = dl->status_block[0];
+		goto Again;
+		break;
+	case TF_INV_CONN_HANDLE:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_DEVICE_UNKNOWN;
+		break;
+	case TF_REQUESTED_N_PENDING:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_PENDING;
+		break;
+	case TC_TASK_CLEARED:
+	case TA_ON_REQ:
+		ts->resp = SAS_TASK_COMPLETE;
+		ts->stat = SAS_ABORTED_TASK;
+		break;
+
+	case TF_NO_SMP_CONN:
+	case TF_TMF_NO_CTX:
+	case TF_TMF_NO_TAG:
+	case TF_TMF_TAG_FREE:
+	case TF_TMF_TASK_DONE:
+	case TF_TMF_NO_CONN_HANDLE:
+	case TF_IRTT_TO:
+	case TF_IU_SHORT:
+	case TF_DATA_OFFS_ERR:
+		ts->resp = SAS_TASK_UNDELIVERED;
+		ts->stat = SAS_DEV_NO_RESPONSE;
+		break;
+
+	case TC_LINK_ADM_RESP:
+	case TC_CONTROL_PHY:
+	case TC_RESUME:
+	case TC_PARTIAL_SG_LIST:
+	default:
+		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
+		break;
+	}
+
+	switch (task->task_proto) {
+	case SATA_PROTO:
+	case SAS_PROTO_STP:
+		asd_unbuild_ata_ascb(ascb);
+		break;
+	case SAS_PROTO_SMP:
+		asd_unbuild_smp_ascb(ascb);
+		break;
+	case SAS_PROTO_SSP:
+		asd_unbuild_ssp_ascb(ascb);
+	default:
+		break;
+	}
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
+			    "stat 0x%x but aborted by upper layer!\n",
+			    task, opcode, ts->resp, ts->stat);
+		complete(&ascb->completion);
+	} else {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		task->lldd_task = NULL;
+		asd_ascb_free(ascb);
+		mb();
+		task->task_done(task);
+	}
+}
+
+/* ---------- ATA ---------- */
+
+static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
+			      unsigned long gfp_flags)
+{
+	struct domain_device *dev = task->dev;
+	struct scb *scb;
+	u8     flags;
+	int    res = 0;
+
+	scb = ascb->scb;
+
+	if (unlikely(task->ata_task.device_control_reg_update))
+		scb->header.opcode = CONTROL_ATA_DEV;
+	else if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+		scb->header.opcode = INITIATE_ATA_TASK;
+	else
+		scb->header.opcode = INITIATE_ATAPI_TASK;
+
+	scb->ata_task.proto_conn_rate = (1 << 5); /* STP */
+	if (dev->port->oob_mode == SAS_OOB_MODE)
+		scb->ata_task.proto_conn_rate |= dev->linkrate;
+
+	scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+	scb->ata_task.fis = task->ata_task.fis;
+	scb->ata_task.fis.fis_type = 0x27;
+	if (likely(!task->ata_task.device_control_reg_update))
+		scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+	scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
+	if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+		memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet,
+		       16);
+	scb->ata_task.sister_scb = cpu_to_le16(0xFFFF);
+	scb->ata_task.conn_handle = cpu_to_le16(
+		(u16)(unsigned long)dev->lldd_dev);
+
+	if (likely(!task->ata_task.device_control_reg_update)) {
+		flags = 0;
+		if (task->ata_task.dma_xfer)
+			flags |= DATA_XFER_MODE_DMA;
+		if (task->ata_task.use_ncq &&
+		    dev->sata_dev.command_set != ATAPI_COMMAND_SET)
+			flags |= ATA_Q_TYPE_NCQ;
+		flags |= data_dir_flags[task->data_dir];
+		scb->ata_task.ata_flags = flags;
+
+		scb->ata_task.retry_count = task->ata_task.retry_count;
+
+		flags = 0;
+		if (task->ata_task.set_affil_pol)
+			flags |= SET_AFFIL_POLICY;
+		if (task->ata_task.stp_affil_pol)
+			flags |= STP_AFFIL_POLICY;
+		scb->ata_task.flags = flags;
+	}
+	ascb->tasklet_complete = asd_task_tasklet_complete;
+
+	if (likely(!task->ata_task.device_control_reg_update))
+		res = asd_map_scatterlist(task, scb->ata_task.sg_element,
+					  gfp_flags);
+
+	return res;
+}
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a)
+{
+	asd_unmap_scatterlist(a);
+}
+
+/* ---------- SMP ---------- */
+
+static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+			      unsigned long gfp_flags)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	struct domain_device *dev = task->dev;
+	struct scb *scb;
+
+	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
+		   PCI_DMA_FROMDEVICE);
+	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
+		   PCI_DMA_FROMDEVICE);
+
+	scb = ascb->scb;
+
+	scb->header.opcode = INITIATE_SMP_TASK;
+
+	scb->smp_task.proto_conn_rate = dev->linkrate;
+
+	scb->smp_task.smp_req.bus_addr =
+		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
+	scb->smp_task.smp_req.size =
+		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
+
+	scb->smp_task.smp_resp.bus_addr =
+		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
+	scb->smp_task.smp_resp.size =
+		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
+
+	scb->smp_task.sister_scb = cpu_to_le16(0xFFFF);
+	scb->smp_task.conn_handle = cpu_to_le16((u16)
+						(unsigned long)dev->lldd_dev);
+
+	ascb->tasklet_complete = asd_task_tasklet_complete;
+
+	return 0;
+}
+
+static void asd_unbuild_smp_ascb(struct asd_ascb *a)
+{
+	struct sas_task *task = a->uldd_task;
+
+	BUG_ON(!task);
+	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
+		     PCI_DMA_FROMDEVICE);
+	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
+		     PCI_DMA_FROMDEVICE);
+}
+
+/* ---------- SSP ---------- */
+
+static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+			      unsigned long gfp_flags)
+{
+	struct domain_device *dev = task->dev;
+	struct scb *scb;
+	int    res = 0;
+
+	scb = ascb->scb;
+
+	scb->header.opcode = INITIATE_SSP_TASK;
+
+	scb->ssp_task.proto_conn_rate  = (1 << 4); /* SSP */
+	scb->ssp_task.proto_conn_rate |= dev->linkrate;
+	scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+	scb->ssp_task.ssp_frame.frame_type = SSP_DATA;
+	memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr,
+	       HASHED_SAS_ADDR_SIZE);
+	memcpy(scb->ssp_task.ssp_frame.hashed_src_addr,
+	       dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+	scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+	memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8);
+	if (task->ssp_task.enable_first_burst)
+		scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK;
+	scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3);
+	scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7);
+	memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16);
+
+	scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF);
+	scb->ssp_task.conn_handle = cpu_to_le16(
+		(u16)(unsigned long)dev->lldd_dev);
+	scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
+	scb->ssp_task.retry_count = scb->ssp_task.retry_count;
+
+	ascb->tasklet_complete = asd_task_tasklet_complete;
+
+	res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
+
+	return res;
+}
+
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a)
+{
+	asd_unmap_scatterlist(a);
+}
+
+/* ---------- Execute Task ---------- */
+
+static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
+{
+	int res = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+	if ((asd_ha->seq.can_queue - num) < 0)
+		res = -SAS_QUEUE_FULL;
+	else
+		asd_ha->seq.can_queue -= num;
+	spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+	return res;
+}
+
+int asd_execute_task(struct sas_task *task, const int num,
+		     unsigned long gfp_flags)
+{
+	int res = 0;
+	LIST_HEAD(alist);
+	struct sas_task *t = task;
+	struct asd_ascb *ascb = NULL, *a;
+	struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+
+	res = asd_can_queue(asd_ha, num);
+	if (res)
+		return res;
+
+	res = num;
+	ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
+	if (res) {
+		res = -ENOMEM;
+		goto out_err;
+	}
+
+	__list_add(&alist, ascb->list.prev, &ascb->list);
+	list_for_each_entry(a, &alist, list) {
+		a->uldd_task = t;
+		t->lldd_task = a;
+		t = list_entry(t->list.next, struct sas_task, list);
+	}
+	list_for_each_entry(a, &alist, list) {
+		t = a->uldd_task;
+		a->uldd_timer = 1;
+		if (t->task_proto & SAS_PROTO_STP)
+			t->task_proto = SAS_PROTO_STP;
+		switch (t->task_proto) {
+		case SATA_PROTO:
+		case SAS_PROTO_STP:
+			res = asd_build_ata_ascb(a, t, gfp_flags);
+			break;
+		case SAS_PROTO_SMP:
+			res = asd_build_smp_ascb(a, t, gfp_flags);
+			break;
+		case SAS_PROTO_SSP:
+			res = asd_build_ssp_ascb(a, t, gfp_flags);
+			break;
+		default:
+			asd_printk("unknown sas_task proto: 0x%x\n",
+				   t->task_proto);
+			res = -ENOMEM;
+			break;
+		}
+		if (res)
+			goto out_err_unmap;
+	}
+	list_del_init(&alist);
+
+	res = asd_post_ascb_list(asd_ha, ascb, num);
+	if (unlikely(res)) {
+		a = NULL;
+		__list_add(&alist, ascb->list.prev, &ascb->list);
+		goto out_err_unmap;
+	}
+
+	return 0;
+out_err_unmap:
+	{
+		struct asd_ascb *b = a;
+		list_for_each_entry(a, &alist, list) {
+			if (a == b)
+				break;
+			t = a->uldd_task;
+			switch (t->task_proto) {
+			case SATA_PROTO:
+			case SAS_PROTO_STP:
+				asd_unbuild_ata_ascb(a);
+				break;
+			case SAS_PROTO_SMP:
+				asd_unbuild_smp_ascb(a);
+				break;
+			case SAS_PROTO_SSP:
+				asd_unbuild_ssp_ascb(a);
+			default:
+				break;
+			}
+			t->lldd_task = NULL;
+		}
+	}
+	list_del_init(&alist);
+out_err:
+	if (ascb)
+		asd_ascb_free_list(ascb);
+	asd_can_dequeue(asd_ha, num);
+	return res;
+}
diff -urN oldtree/drivers/scsi/aic94xx/aic94xx_tmf.c newtree/drivers/scsi/aic94xx/aic94xx_tmf.c
--- oldtree/drivers/scsi/aic94xx/aic94xx_tmf.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/aic94xx/aic94xx_tmf.c	2006-04-01 05:35:45.915489500 -0500
@@ -0,0 +1,634 @@
+/*
+ * Aic94xx Task Management Functions
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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.
+ *
+ * The aic94xx driver 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 aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_tmf.c#35 $
+ */
+
+#include <linux/spinlock.h>
+#include <scsi/sas/sas_task.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+/* ---------- Internal enqueue ---------- */
+
+static int asd_enqueue_internal(struct asd_ascb *ascb,
+		void (*tasklet_complete)(struct asd_ascb *,
+					 struct done_list_struct *),
+				void (*timed_out)(unsigned long))
+{
+	int res;
+
+	ascb->tasklet_complete = tasklet_complete;
+	ascb->uldd_timer = 1;
+
+	ascb->timer.data = (unsigned long) ascb;
+	ascb->timer.function = timed_out;
+	ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+
+	add_timer(&ascb->timer);
+
+	res = asd_post_ascb_list(ascb->ha, ascb, 1);
+	if (unlikely(res))
+		del_timer(&ascb->timer);
+	return res;
+}
+
+static inline void asd_timedout_common(unsigned long data)
+{
+	struct asd_ascb *ascb = (void *) data;
+	struct asd_seq_data *seq = &ascb->ha->seq;
+        unsigned long flags;
+
+	spin_lock_irqsave(&seq->pend_q_lock, flags);
+        seq->pending--;
+        list_del_init(&ascb->list);
+        spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+}
+
+/* ---------- CLEAR NEXUS ---------- */
+
+static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
+					     struct done_list_struct *dl)
+{
+	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	if (!del_timer(&ascb->timer)) {
+		ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
+		return;
+	}
+	ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
+	ascb->uldd_task = (void *) (unsigned long) dl->opcode;
+	complete(&ascb->completion);
+}
+
+static void asd_clear_nexus_timedout(unsigned long data)
+{
+	struct asd_ascb *ascb = (void *) data;
+
+	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	asd_timedout_common(data);
+	ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+	complete(&ascb->completion);
+}
+
+#define CLEAR_NEXUS_PRE         \
+	ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
+        res = 1;                \
+	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
+	if (!ascb)              \
+		return -ENOMEM; \
+                                \
+	scb = ascb->scb;        \
+	scb->header.opcode = CLEAR_NEXUS
+
+#define CLEAR_NEXUS_POST        \
+	ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
+	res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
+				   asd_clear_nexus_timedout);              \
+	if (res)                \
+		goto out_err;   \
+	ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
+	wait_for_completion(&ascb->completion); \
+	res = (int) (unsigned long) ascb->uldd_task; \
+	if (res == TC_NO_ERROR) \
+		res = TMF_RESP_FUNC_COMPLETE;   \
+out_err:                        \
+	asd_ascb_free(ascb);    \
+	return res
+
+int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
+{
+	struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_ADAPTER;
+	CLEAR_NEXUS_POST;
+}
+
+int asd_clear_nexus_port(struct sas_port *port)
+{
+	struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_PORT;
+	scb->clear_nexus.conn_mask = port->phy_mask;
+	CLEAR_NEXUS_POST;
+}
+
+#if 0
+static int asd_clear_nexus_I_T(struct domain_device *dev)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_I_T;
+	scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+	if (dev->tproto)
+		scb->clear_nexus.flags |= SUSPEND_TX;
+	scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+						   dev->lldd_dev);
+	CLEAR_NEXUS_POST;
+}
+#endif
+
+static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_I_T_L;
+	scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+	if (dev->tproto)
+		scb->clear_nexus.flags |= SUSPEND_TX;
+	memcpy(scb->clear_nexus.ssp_task.lun, lun, 8);
+	scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+						   dev->lldd_dev);
+	CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_tag(struct sas_task *task)
+{
+	struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+	struct asd_ascb *tascb = task->lldd_task;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_TAG;
+	memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8);
+	scb->clear_nexus.ssp_task.tag = tascb->tag;
+	if (task->dev->tproto)
+		scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+							  task->dev->lldd_dev);
+	CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_index(struct sas_task *task)
+{
+	struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+	struct asd_ascb *tascb = task->lldd_task;
+	struct asd_ascb *ascb;
+	struct scb *scb;
+	int res;
+
+	CLEAR_NEXUS_PRE;
+	scb->clear_nexus.nexus = NEXUS_TRANS_CX;
+	if (task->dev->tproto)
+		scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+							  task->dev->lldd_dev);
+	scb->clear_nexus.index = cpu_to_le16(tascb->tc_index);
+	CLEAR_NEXUS_POST;
+}
+
+/* ---------- TMFs ---------- */
+
+static void asd_tmf_timedout(unsigned long data)
+{
+	struct asd_ascb *ascb = (void *) data;
+
+	ASD_DPRINTK("tmf timed out\n");
+	asd_timedout_common(data);
+	ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+	complete(&ascb->completion);
+}
+
+static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
+				    struct done_list_struct *dl)
+{
+	struct asd_ha_struct *asd_ha = ascb->ha;
+	unsigned long flags;
+	struct tc_resp_sb_struct {
+		__le16 index_escb;
+		u8     len_lsb;
+		u8     flags;
+	} __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+	int  edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+	struct asd_ascb *escb;
+	struct asd_dma_tok *edb;
+	struct ssp_frame_hdr *fh;
+	struct ssp_response_iu   *ru;
+	int res = TMF_RESP_FUNC_FAILED;
+
+	ASD_DPRINTK("tmf resp tasklet\n");
+
+	spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+	escb = asd_tc_index_find(&asd_ha->seq,
+				 (int)le16_to_cpu(resp_sb->index_escb));
+	spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+	if (!escb) {
+		ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+		return res;
+	}
+
+	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+	ascb->tag = *(__be16 *)(edb->vaddr+4);
+	fh = edb->vaddr + 16;
+	ru = edb->vaddr + 16 + sizeof(*fh);
+	res = ru->status;
+	if (ru->datapres == 1)	  /* Response data present */
+		res = ru->resp_data[3];
+#if 0
+	ascb->tag = fh->tag;
+#endif
+	ascb->tag_valid = 1;
+
+	asd_invalidate_edb(escb, edb_id);
+	return res;
+}
+
+static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
+				     struct done_list_struct *dl)
+{
+	if (!del_timer(&ascb->timer))
+		return;
+
+	ASD_DPRINTK("tmf tasklet complete\n");
+
+	if (dl->opcode == TC_SSP_RESP)
+		ascb->uldd_task = (void *) (unsigned long)
+			asd_get_tmf_resp_tasklet(ascb, dl);
+	else
+		ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
+
+	complete(&ascb->completion);
+}
+
+static inline int asd_clear_nexus(struct sas_task *task)
+{
+	int res = TMF_RESP_FUNC_FAILED;
+	struct asd_ascb *tascb = task->lldd_task;
+	unsigned long flags;
+
+	ASD_DPRINTK("task not done, clearing nexus\n");
+	if (tascb->tag_valid)
+		res = asd_clear_nexus_tag(task);
+	else
+		res = asd_clear_nexus_index(task);
+	wait_for_completion_timeout(&tascb->completion,
+				    AIC94XX_SCB_TIMEOUT);
+	ASD_DPRINTK("came back from clear nexus\n");
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE)
+		res = TMF_RESP_FUNC_COMPLETE;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	return res;
+}
+
+/**
+ * asd_abort_task -- ABORT TASK TMF
+ * @task: the task to be aborted
+ *
+ * Before calling ABORT TASK the task state flags should be ORed with
+ * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under
+ * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called.
+ *
+ * Implements the ABORT TASK TMF, I_T_L_Q nexus.
+ * Returns: SAS TMF responses (see sas_task.h),
+ *          -ENOMEM,
+ *          -SAS_QUEUE_FULL.
+ *
+ * When ABORT TASK returns, the caller of ABORT TASK checks first the
+ * task->task_state_flags, and then the return value of ABORT TASK.
+ *
+ * If the task has task state bit SAS_TASK_STATE_DONE set, then the
+ * task was completed successfully prior to it being aborted.  The
+ * caller of ABORT TASK has responsibility to call task->task_done()
+ * xor free the task, depending on their framework.  The return code
+ * is TMF_RESP_FUNC_FAILED in this case.
+ *
+ * Else the SAS_TASK_STATE_DONE bit is not set,
+ * 	If the return code is TMF_RESP_FUNC_COMPLETE, then
+ * 		the task was aborted successfully.  The caller of
+ * 		ABORT TASK has responsibility to call task->task_done()
+ *              to finish the task, xor free the task depending on their
+ *		framework.
+ *	else
+ * 		the ABORT TASK returned some kind of error. The task
+ *              was _not_ cancelled.  Nothing can be assumed.
+ *		The caller of ABORT TASK may wish to retry.
+ */
+int asd_abort_task(struct sas_task *task)
+{
+	struct asd_ascb *tascb = task->lldd_task;
+	struct asd_ha_struct *asd_ha = tascb->ha;
+	int res = 1;
+	unsigned long flags;
+	struct asd_ascb *ascb = NULL;
+	struct scb *scb;
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		res = TMF_RESP_FUNC_COMPLETE;
+		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		goto out_done;
+	}
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+	if (!ascb)
+		return -ENOMEM;
+	scb = ascb->scb;
+
+	scb->header.opcode = ABORT_TASK;
+
+	switch (task->task_proto) {
+	case SATA_PROTO:
+	case SAS_PROTO_STP:
+		scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
+		break;
+	case SAS_PROTO_SSP:
+		scb->abort_task.proto_conn_rate  = (1 << 4); /* SSP */
+		scb->abort_task.proto_conn_rate |= task->dev->linkrate;
+		break;
+	case SAS_PROTO_SMP:
+		break;
+	default:
+		break;
+	}
+
+	if (task->task_proto == SAS_PROTO_SSP) {
+		scb->abort_task.ssp_frame.frame_type = SSP_TASK;
+		memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
+		       task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+		memcpy(scb->abort_task.ssp_frame.hashed_src_addr,
+		       task->dev->port->ha->hashed_sas_addr,
+		       HASHED_SAS_ADDR_SIZE);
+		scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+		memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8);
+		scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK;
+		scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF);
+	}
+
+	scb->abort_task.sister_scb = cpu_to_le16(0xFFFF);
+	scb->abort_task.conn_handle = cpu_to_le16(
+		(u16)(unsigned long)task->dev->lldd_dev);
+	scb->abort_task.retry_count = 1;
+	scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
+	scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+
+	res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+				   asd_tmf_timedout);
+	if (res)
+		goto out;
+	wait_for_completion(&ascb->completion);
+	ASD_DPRINTK("tmf came back\n");
+
+	res = (int) (unsigned long) ascb->uldd_task;
+	tascb->tag = ascb->tag;
+	tascb->tag_valid = ascb->tag_valid;
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		res = TMF_RESP_FUNC_COMPLETE;
+		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		goto out_done;
+	}
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	switch (res) {
+	/* The task to be aborted has been sent to the device.
+	 * We got a Response IU for the ABORT TASK TMF. */
+	case TC_NO_ERROR + 0xFF00:
+	case TMF_RESP_FUNC_COMPLETE:
+	case TMF_RESP_FUNC_FAILED:
+		res = asd_clear_nexus(task);
+		break;
+	case TMF_RESP_INVALID_FRAME:
+	case TMF_RESP_OVERLAPPED_TAG:
+	case TMF_RESP_FUNC_ESUPP:
+	case TMF_RESP_NO_LUN:
+		goto out_done; break;
+	}
+	/* In the following we assume that the managing layer
+	 * will _never_ make a mistake, when issuing ABORT TASK.
+	 */
+	switch (res) {
+	default:
+		res = asd_clear_nexus(task);
+		/* fallthrough */
+	case TC_NO_ERROR + 0xFF00:
+	case TMF_RESP_FUNC_COMPLETE:
+		break;
+	/* The task hasn't been sent to the device xor we never got
+	 * a (sane) Response IU for the ABORT TASK TMF.
+	 */
+	case TF_NAK_RECV + 0xFF00:
+		res = TMF_RESP_INVALID_FRAME;
+		break;
+	case TF_TMF_TASK_DONE + 0xFF00:	/* done but not reported yet */
+		res = TMF_RESP_FUNC_FAILED;
+		wait_for_completion_timeout(&tascb->completion,
+					    AIC94XX_SCB_TIMEOUT);
+		spin_lock_irqsave(&task->task_state_lock, flags);
+		if (task->task_state_flags & SAS_TASK_STATE_DONE)
+			res = TMF_RESP_FUNC_COMPLETE;
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		goto out_done; break;
+	case TF_TMF_NO_TAG + 0xFF00:
+	case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+	case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+	case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+		res = TMF_RESP_FUNC_COMPLETE;
+		goto out_done; break;
+	}
+out_done:
+	if (res == TMF_RESP_FUNC_COMPLETE) {
+		task->lldd_task = NULL;
+		mb();
+		asd_ascb_free(tascb);
+	}
+out:
+	asd_ascb_free(ascb);
+	ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
+	return res;
+}
+
+/**
+ * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus
+ * @dev: pointer to struct domain_device of interest
+ * @lun: pointer to u8[8] which is the LUN
+ * @tmf: the TMF to be performed (see sas_task.h or the SAS spec)
+ * @index: the transaction context of the task to be queried if QT TMF
+ *
+ * This function is used to send ABORT TASK SET, CLEAR ACA,
+ * CLEAR TASK SET, LU RESET and QUERY TASK TMFs.
+ *
+ * No SCBs should be queued to the I_T_L nexus when this SCB is
+ * pending.
+ *
+ * Returns: TMF response code (see sas_task.h or the SAS spec)
+ */
+static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
+				int tmf, int index)
+{
+	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+	struct asd_ascb *ascb;
+	int res = 1;
+	struct scb *scb;
+
+	if (!(dev->tproto & SAS_PROTO_SSP))
+		return TMF_RESP_FUNC_ESUPP;
+
+	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+	if (!ascb)
+		return -ENOMEM;
+	scb = ascb->scb;
+
+	if (tmf == TMF_QUERY_TASK)
+		scb->header.opcode = QUERY_SSP_TASK;
+	else
+		scb->header.opcode = INITIATE_SSP_TMF;
+
+	scb->ssp_tmf.proto_conn_rate  = (1 << 4); /* SSP */
+	scb->ssp_tmf.proto_conn_rate |= dev->linkrate;
+	/* SSP frame header */
+	scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK;
+	memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr,
+	       dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+	memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr,
+	       dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+	scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+	/* SSP Task IU */
+	memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8);
+	scb->ssp_tmf.ssp_task.tmf = tmf;
+
+	scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF);
+	scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long)
+					      dev->lldd_dev);
+	scb->ssp_tmf.retry_count = 1;
+	scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+	if (tmf == TMF_QUERY_TASK)
+		scb->ssp_tmf.index = cpu_to_le16(index);
+
+	res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+				   asd_tmf_timedout);
+	if (res)
+		goto out_err;
+	wait_for_completion(&ascb->completion);
+	res = (int) (unsigned long) ascb->uldd_task;
+
+	switch (res) {
+	case TC_NO_ERROR + 0xFF00:
+		res = TMF_RESP_FUNC_COMPLETE;
+		break;
+	case TF_NAK_RECV + 0xFF00:
+		res = TMF_RESP_INVALID_FRAME;
+		break;
+	case TF_TMF_TASK_DONE + 0xFF00:
+		res = TMF_RESP_FUNC_FAILED;
+		break;
+	case TF_TMF_NO_TAG + 0xFF00:
+	case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+	case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+	case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+		res = TMF_RESP_FUNC_COMPLETE;
+		break;
+	default:
+		ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n",
+			    __FUNCTION__, res);
+		res = TMF_RESP_FUNC_FAILED;
+		break;
+	}
+out_err:
+	asd_ascb_free(ascb);
+	return res;
+}
+
+int asd_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+	int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0);
+
+	if (res == TMF_RESP_FUNC_COMPLETE)
+		asd_clear_nexus_I_T_L(dev, lun);
+	return res;
+}
+
+int asd_clear_aca(struct domain_device *dev, u8 *lun)
+{
+	int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0);
+
+	if (res == TMF_RESP_FUNC_COMPLETE)
+		asd_clear_nexus_I_T_L(dev, lun);
+	return res;
+}
+
+int asd_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+	int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0);
+
+	if (res == TMF_RESP_FUNC_COMPLETE)
+		asd_clear_nexus_I_T_L(dev, lun);
+	return res;
+}
+
+int asd_lu_reset(struct domain_device *dev, u8 *lun)
+{
+	int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0);
+
+	if (res == TMF_RESP_FUNC_COMPLETE)
+		asd_clear_nexus_I_T_L(dev, lun);
+	return res;
+}
+
+/**
+ * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus
+ * task: pointer to sas_task struct of interest
+ *
+ * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set,
+ * or TMF_RESP_FUNC_SUCC if the task is in the task set.
+ *
+ * Normally the management layer sets the task to aborted state,
+ * and then calls query task and then abort task.
+ */
+int asd_query_task(struct sas_task *task)
+{
+	struct asd_ascb *ascb = task->lldd_task;
+	int index;
+
+	if (ascb) {
+		index = ascb->tc_index;
+		return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN,
+					    TMF_QUERY_TASK, index);
+	}
+	return TMF_RESP_FUNC_COMPLETE;
+}
diff -urN oldtree/drivers/scsi/arcmsr/Makefile newtree/drivers/scsi/arcmsr/Makefile
--- oldtree/drivers/scsi/arcmsr/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/arcmsr/Makefile	2006-04-01 05:35:45.851485500 -0500
@@ -0,0 +1,6 @@
+# File: drivers/arcmsr/Makefile
+# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
+
+arcmsr-objs := arcmsr_attr.o arcmsr_hba.o
+
+obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
diff -urN oldtree/drivers/scsi/arcmsr/arcmsr.h newtree/drivers/scsi/arcmsr/arcmsr.h
--- oldtree/drivers/scsi/arcmsr/arcmsr.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/arcmsr/arcmsr.h	2006-04-01 05:35:45.847485250 -0500
@@ -0,0 +1,476 @@
+/*
+*******************************************************************************
+**        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.
+*******************************************************************************
+*/
+#include <linux/interrupt.h>
+
+#define ARCMSR_MAX_OUTSTANDING_CMD 						256
+#define ARCMSR_MAX_FREECCB_NUM							288
+#define ARCMSR_DRIVER_VERSION				"Driver Version 1.20.00.13"
+#define ARCMSR_SCSI_INITIATOR_ID						255
+#define ARCMSR_MAX_XFER_SECTORS						       4096
+#define ARCMSR_MAX_TARGETID							 17
+#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
+
+/*
+*******************************************************************************
+**        split 64bits dma addressing
+*******************************************************************************
+*/
+#define dma_addr_hi32(addr)               (uint32_t) ((addr>>16)>>16)
+#define dma_addr_lo32(addr)               (uint32_t) (addr & 0xffffffff)
+/*
+*******************************************************************************
+**        MESSAGE CONTROL CODE
+*******************************************************************************
+*/
+struct CMD_MESSAGE
+{
+      uint32_t HeaderLength;
+      uint8_t  Signature[8];
+      uint32_t Timeout;
+      uint32_t ControlCode;
+      uint32_t ReturnCode;
+      uint32_t Length;
+};
+/*
+*******************************************************************************
+**        IOP Message Transfer Data for user space
+*******************************************************************************
+*/
+struct CMD_MESSAGE_FIELD
+{
+    struct CMD_MESSAGE			cmdmessage;
+    uint8_t					messagedatabuffer[1032];
+};
+/* IOP message transfer */
+#define ARCMSR_MESSAGE_FAIL             0x0001
+/* 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_MESSAGE_READ_RQBUFFER       \
+	ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
+#define ARCMSR_MESSAGE_WRITE_WQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_RQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_WQBUFFER      \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER    \
+	ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
+#define ARCMSR_MESSAGE_RETURN_CODE_3F      \
+	ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
+#define ARCMSR_MESSAGE_SAY_HELLO           \
+	ARECA_SATA_RAID | FUNCTION_SAY_HELLO
+#define ARCMSR_MESSAGE_SAY_GOODBYE         \
+	ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
+#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
+	ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
+/* ARECA IOCTL ReturnCode */
+#define ARCMSR_MESSAGE_RETURNCODE_OK              0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR           0x00000006
+#define ARCMSR_MESSAGE_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;
+};
+/*
+********************************************************************
+**      Q Buffer of IOP Message Transfer
+********************************************************************
+*/
+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*/
+};
+/* 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
+/*
+*******************************************************************************
+**    ARECA SCSI COMMAND DESCRIPTOR BLOCK 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 ARCMSR_DEV_CHECK_CONDITION          0x02
+#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 MessageUnit
+{
+	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	message_wbuffer[32];		/*0E00 0E7F  32*/
+	uint32_t	reserved5[32];			/*0E80 0EFF  32*/
+	uint32_t	message_rbuffer[32];		/*0F00 0F7F  32*/
+	uint32_t	reserved6[32];			/*0F80 0FFF  32*/
+};
+/*
+*******************************************************************************
+**                 Adapter Control Block
+*******************************************************************************
+*/
+struct AdapterControlBlock
+{
+	struct pci_dev *		pdev;
+	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 MessageUnit __iomem *		pmu;
+	/* message unit ATU inbound base address0 */
+
+	uint32_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 message data rqbuffer overflow */
+#define ACB_F_MESSAGE_WQBUFFER_CLEARED  0x0010
+	/* message clear wqbuffer */
+#define ACB_F_MESSAGE_RQBUFFER_CLEARED  0x0020
+	/* message clear rqbuffer */
+#define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
+#define ACB_F_BUS_RESET               0x0080
+#define ACB_F_IOP_INITED              0x0100
+	/* iop init */
+
+	struct CommandControlBlock *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
+	/* used for memory free */
+	struct list_head		ccb_free_list;
+	/* head of free ccb list */
+	atomic_t			ccboutstandingcount;
+
+	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  */
+	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_hd_channels;
+	char				firm_model[12];
+	char				firm_version[20];
+};/* HW_DEVICE_EXTENSION */
+/*
+*******************************************************************************
+**                   Command Control Block
+**             this CCB length must be 32 bytes boundary
+*******************************************************************************
+*/
+struct CommandControlBlock
+{
+	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 AdapterControlBlock *			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 AdapterControlBlock *			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
+	/*  ==========================================================  */
+};
+/*
+*******************************************************************************
+**    ARECA SCSI sense data
+*******************************************************************************
+*/
+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];
+};
+/*
+*******************************************************************************
+**  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
+/*
+*******************************************************************************
+**  extern field
+*******************************************************************************
+*/
+extern struct class_device_attribute *arcmsr_host_attrs[];
+extern struct raid_function_template arcmsr_transport_functions;
+
+extern void arcmsr_iop_reset(struct AdapterControlBlock *pACB);
+extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *pACB);
+extern void arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *pACB);
+extern irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *pACB);
diff -urN oldtree/drivers/scsi/arcmsr/arcmsr_attr.c newtree/drivers/scsi/arcmsr/arcmsr_attr.c
--- oldtree/drivers/scsi/arcmsr/arcmsr_attr.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/arcmsr/arcmsr_attr.c	2006-04-01 05:35:45.843485000 -0500
@@ -0,0 +1,314 @@
+/*
+*******************************************************************************
+**        O.S   : Linux
+**   FILE NAME  : arcmsr_attr.c
+**        BY    : Erich Chen
+**   Description: attributes exported to sysfs and device host
+*******************************************************************************
+** 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
+**     Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include "arcmsr.h"
+
+static ssize_t
+arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	uint8_t *pQbuffer,*ptmpQbuffer;
+	int32_t allxfer_len = 0;
+
+	if (!capable(CAP_SYS_ADMIN) || (off + count) > 1032 || (count && off) == 0)
+		return 0;
+
+	/* do message unit read. */
+	ptmpQbuffer = (uint8_t *)buf;
+	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->message_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);
+	}
+	return (allxfer_len);
+}
+
+static ssize_t
+arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+	uint8_t *pQbuffer, *ptmpuserbuffer;
+
+	if (!capable(CAP_SYS_ADMIN) || (off + count) > 1032 || (count && off) == 0)
+		return 0;
+
+	/* do message unit write. */
+	ptmpuserbuffer = (uint8_t *)buf;
+	user_len = (int32_t)count;
+	wqbuf_lastindex = pACB->wqbuf_lastindex;
+	wqbuf_firstindex = pACB->wqbuf_firstindex;
+	if (wqbuf_lastindex != wqbuf_firstindex) {
+		arcmsr_post_Qbuffer(pACB);
+		return 0;
+	} 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_MESSAGE_WQBUFFER_CLEARED) {
+				pACB->acb_flags &=
+					~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+				arcmsr_post_Qbuffer(pACB);
+			}
+			return count;
+		} else {
+			return 0;
+		}
+	}
+}
+
+static struct bin_attribute arcmsr_sysfs_message_transfer_attr = {
+	.attr = {
+		.name = "iop_message_transfer",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.read = arcmsr_sysfs_iop_message_read,
+	.write = arcmsr_sysfs_iop_message_write,
+};
+
+void
+arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *pACB) {
+	struct Scsi_Host *host = pACB->host;
+
+	sysfs_create_bin_file(&host->shost_classdev.kobj,
+							&arcmsr_sysfs_message_transfer_attr);
+}
+
+void
+arcmsr_free_sysfs_attr(struct AdapterControlBlock *pACB) {
+	struct Scsi_Host *host = pACB->host;
+
+	sysfs_remove_bin_file(&host->shost_gendev.kobj, &arcmsr_sysfs_message_transfer_attr);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) {
+	return snprintf(buf, PAGE_SIZE,
+			"ARCMSR: %s\n",
+			ARCMSR_DRIVER_VERSION);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_state(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	int len = 0;
+
+	len = snprintf(buf, PAGE_SIZE,
+				"=================================\n"
+				"Current commands posted:     %4d\n"
+				"Max commands posted:         %4d\n"
+				"Max sgl length:              %4d\n"
+				"Max sector count:            %4d\n"
+				"SCSI Host Resets:            %4d\n"
+				"SCSI Aborts/Timeouts:        %4d\n"
+				"=================================\n",
+				atomic_read(&pACB->ccboutstandingcount),
+				ARCMSR_MAX_OUTSTANDING_CMD,
+				ARCMSR_MAX_SG_ENTRIES,
+				ARCMSR_MAX_XFER_SECTORS,
+				pACB->num_resets,
+				pACB->num_aborts);
+	return len;
+}
+
+static ssize_t
+arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) {
+    struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	return snprintf(buf, PAGE_SIZE,
+			"Adapter Model: %s\n",
+			pACB->firm_model);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"Firmware Version:  %s\n",
+			pACB->firm_version);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"Reguest Lenth: %4d\n",
+			pACB->firm_request_len);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"Numbers of Queue: %4d\n",
+			pACB->firm_numbers_queue);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"SDRAM Size: %4d\n",
+			pACB->firm_sdram_size);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	return snprintf(buf, PAGE_SIZE,
+			"Hard Disk Channels: %4d\n",
+			pACB->firm_hd_channels);
+}
+
+static ssize_t
+arcmsr_attr_host_pci_info(struct class_device *cdev, char *buf) {
+	struct Scsi_Host *host = class_to_shost(cdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	int pci_type;
+
+	pci_type = pci_find_capability(pACB->pdev, PCI_CAP_ID_EXP);
+	return snprintf(buf, PAGE_SIZE,
+			"=================================\n"
+			"pci type: %s"
+			"pci name: %s\n"
+			"bus number: %d\n"
+			"function number: %4d\n"
+			"slot number: %d\n"
+			"irq: %d\n"
+			"=================================\n",
+			pci_type ? "PCI EXPRESS \n" : "PCI \n",
+			pci_name(pACB->pdev),
+			pACB->pdev->bus->number,
+			PCI_FUNC(pACB->pdev->devfn),
+			PCI_SLOT(pACB->pdev->devfn),
+			pACB->pdev->irq
+		);
+}
+
+static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
+static CLASS_DEVICE_ATTR(host_driver_state, S_IRUGO, arcmsr_attr_host_driver_state, NULL);
+static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
+static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
+static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
+static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
+static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
+static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
+static CLASS_DEVICE_ATTR(host_pci_info, S_IRUGO, arcmsr_attr_host_pci_info, NULL);
+
+struct class_device_attribute *arcmsr_host_attrs[] = {
+	&class_device_attr_host_driver_version,
+	&class_device_attr_host_driver_state,
+	&class_device_attr_host_fw_model,
+	&class_device_attr_host_fw_version,
+	&class_device_attr_host_fw_request_len,
+	&class_device_attr_host_fw_numbers_queue,
+	&class_device_attr_host_fw_sdram_size,
+	&class_device_attr_host_fw_hd_channels,
+	&class_device_attr_host_pci_info,
+	NULL,
+};
diff -urN oldtree/drivers/scsi/arcmsr/arcmsr_hba.c newtree/drivers/scsi/arcmsr/arcmsr_hba.c
--- oldtree/drivers/scsi/arcmsr/arcmsr_hba.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/arcmsr/arcmsr_hba.c	2006-04-01 05:35:45.847485250 -0500
@@ -0,0 +1,1573 @@
+/*
+*******************************************************************************
+**        O.S   : Linux
+**   FILE NAME  : arcmsr_hba.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
+**     Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/pci_ids.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/scsi_transport.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");
+MODULE_VERSION(ARCMSR_DRIVER_VERSION);
+
+static int arcmsr_initialize(struct AdapterControlBlock *pACB, struct pci_dev *pdev);
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *pACB, struct scsi_cmnd *cmd);
+static int arcmsr_cmd_abort(struct scsi_cmnd *);
+static int arcmsr_bus_reset(struct scsi_cmnd *);
+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 *pdev,
+				const struct pci_device_id *id);
+static void arcmsr_device_remove(struct pci_dev *pdev);
+static void arcmsr_device_shutdown(struct pci_dev *pdev);
+static void arcmsr_pcidev_disattach(struct AdapterControlBlock *pACB);
+static void arcmsr_iop_init(struct AdapterControlBlock *pACB);
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *pACB);
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *pACB);
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *pACB);
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *pACB);
+static const char *arcmsr_info(struct Scsi_Host *);
+
+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,
+	.name			= "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+	.info			= arcmsr_info,
+	.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,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= arcmsr_host_attrs,
+};
+
+static struct pci_device_id arcmsr_device_id_table[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
+	{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,
+	.shutdown		= arcmsr_device_shutdown
+};
+
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
+	struct pt_regs *regs)
+{
+	irqreturn_t handle_state;
+	struct AdapterControlBlock *pACB;
+	unsigned long flags;
+
+	pACB = (struct AdapterControlBlock *)dev_id;
+
+	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 *pdev,
+	const struct pci_device_id *id)
+{
+	struct Scsi_Host *host;
+	struct AdapterControlBlock *pACB;
+	uint8_t bus, dev_fun;
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_NOTICE
+		"arcmsr: adapter probe pci_enable_device error \n");
+		return -ENODEV;
+	}
+	host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof (struct AdapterControlBlock));
+	if (!host) {
+		printk(KERN_NOTICE
+		"arcmsr: adapter probe scsi_host_alloc error \n");
+		pci_disable_device(pdev);
+		return -ENODEV;
+	}
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+		printk(KERN_INFO
+		"ARECA RAID ADAPTER%d: 64BITS PCI BUS DMA ADDRESSING SUPPORTED\n"
+		, host->host_no);
+	else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
+		printk(KERN_INFO
+		"ARECA RAID ADAPTER%d: 32BITS PCI BUS DMA ADDRESSING SUPPORTED\n"
+		, host->host_no);
+	else {
+		printk(KERN_NOTICE
+		"ARECA RAID ADAPTER%d: No suitable DMA available.\n"
+		, host->host_no);
+		pci_disable_device(pdev);
+		scsi_host_put(host);
+		return -ENOMEM;
+	}
+	if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_NOTICE
+		"ARECA RAID ADAPTER%d:"
+		" No 32BIT coherent DMA adressing available\n"
+		, host->host_no);
+		pci_disable_device(pdev);
+		scsi_host_put(host);
+		return -ENOMEM;
+	}
+	bus = pdev->bus->number;
+	dev_fun = pdev->devfn;
+	pACB = (struct AdapterControlBlock *) host->hostdata;
+	memset(pACB, 0, sizeof (struct AdapterControlBlock));
+	pACB->host = host;
+	pACB->pdev = pdev;
+	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 = pdev->irq;
+	pci_set_master(pdev);
+	if (arcmsr_initialize(pACB, pdev)) {
+		printk(KERN_NOTICE
+		"arcmsr%d: initialize got error \n"
+		, host->host_no);
+		pci_disable_device(pdev);
+		scsi_host_put(host);
+		return -ENODEV;
+	}
+	if (pci_request_regions(pdev, "arcmsr")) {
+		printk(KERN_NOTICE
+		"arcmsr%d: adapter probe: pci_request_regions failed \n"
+		, host->host_no);
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+	if (request_irq(pdev->irq, arcmsr_do_interrupt, SA_INTERRUPT | SA_SHIRQ,
+		"arcmsr", pACB)) {
+		printk(KERN_NOTICE
+		"arcmsr%d: request IRQ=%d failed !\n"
+		, host->host_no, pdev->irq);
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+	arcmsr_iop_init(pACB);
+	if (scsi_add_host(host, &pdev->dev)) {
+		printk(KERN_NOTICE
+		"arcmsr%d: scsi_add_host got error \n"
+		, host->host_no);
+		arcmsr_pcidev_disattach(pACB);
+		return -ENODEV;
+	}
+	arcmsr_alloc_sysfs_attr(pACB);
+	pci_set_drvdata(pdev, host);
+	scsi_scan_host(host);
+	return 0;
+}
+
+static void arcmsr_device_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host * host = pci_get_drvdata(pdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	arcmsr_pcidev_disattach(pACB);
+}
+
+static void arcmsr_device_shutdown(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+
+	arcmsr_stop_adapter_bgrb(pACB);
+	arcmsr_flush_adapter_cache(pACB);
+}
+
+static int arcmsr_module_init(void)
+{
+	int error = 0;
+
+	error = pci_register_driver(&arcmsr_pci_driver);
+	return error;
+}
+
+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 CommandControlBlock *pCCB)
+{
+	struct AdapterControlBlock *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->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
+	}
+	else if (pcmd->request_bufflen != 0)
+		pci_unmap_single(pACB->pdev,
+			(dma_addr_t)(unsigned long)pcmd->SCp.ptr,
+			pcmd->request_bufflen, pcmd->sc_data_direction);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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->host->host_no);
+}
+
+static void arcmsr_ccb_complete(struct CommandControlBlock *pCCB, int stand_flag)
+{
+	struct AdapterControlBlock *pACB = pCCB->pACB;
+	struct scsi_cmnd *pcmd = pCCB->pcmd;
+
+	arcmsr_pci_unmap_dma(pCCB);
+	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);
+	pcmd->scsi_done(pcmd);
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *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;
+	}
+}
+
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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->host->host_no);
+}
+
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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;
+}
+
+void arcmsr_iop_reset(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct CommandControlBlock *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);
+	}
+	atomic_set(&pACB->ccboutstandingcount, 0);
+}
+
+static void arcmsr_build_ccb(struct AdapterControlBlock *pACB, struct CommandControlBlock *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->pdev, 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->pdev, 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->sc_data_direction == DMA_TO_DEVICE ) {
+		pARCMSR_CDB->Flags |= ARCMSR_CDB_FLAG_WRITE;
+		pCCB->ccb_flags |= CCB_FLAG_WRITE;
+	}
+}
+
+static void arcmsr_post_ccb(struct AdapterControlBlock *pACB, struct CommandControlBlock *pCCB)
+{
+	struct MessageUnit __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);
+}
+
+void arcmsr_post_Qbuffer(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
+	uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
+	int32_t allxfer_len = 0;
+
+	if (pACB->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+		pACB->acb_flags &= (~ACB_F_MESSAGE_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 AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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->host->host_no);
+}
+
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *pACB)
+{
+	dma_free_coherent(&pACB->pdev->dev
+		, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
+		pACB->dma_coherent,
+		pACB->dma_coherent_handle);
+}
+
+irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct CommandControlBlock *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->message_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_MESSAGE_WQBUFFER_READED;
+			if (pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) {
+				struct QBUFFER __iomem * pwbuffer =
+						(struct QBUFFER __iomem *) &reg->message_wbuffer;
+				uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
+				int32_t allxfer_len = 0;
+
+				pACB->acb_flags &= (~ACB_F_MESSAGE_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_MESSAGE_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 CommandControlBlock *)(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->host->host_no, 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->host->host_no
+					, 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 ARCMSR_DEV_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->host->host_no
+						, 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;
+	return IRQ_HANDLED;
+}
+
+static void arcmsr_iop_parking(struct AdapterControlBlock *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_message_xfer(struct AdapterControlBlock *pACB, struct scsi_cmnd *cmd)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
+	int retvalue = 0, transfer_len = 0;
+	char *buffer;
+	uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
+						(uint32_t ) cmd->cmnd[6] << 16 |
+						(uint32_t ) cmd->cmnd[7] << 8  |
+						(uint32_t ) cmd->cmnd[8];
+					/* 4 bytes: Areca io control code */
+	if (cmd->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
+
+		buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+		if (cmd->use_sg > 1) {
+			retvalue = ARCMSR_MESSAGE_FAIL;
+			goto message_out;
+		}
+		transfer_len += sg->length;
+	} else {
+		buffer = cmd->request_buffer;
+		transfer_len = cmd->request_bufflen;
+	}
+	if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
+		retvalue = ARCMSR_MESSAGE_FAIL;
+		goto message_out;
+	}
+	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
+	switch(controlcode) {
+	case ARCMSR_MESSAGE_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->pdev, 1032, &buf_handle);
+			if (!ver_addr) {
+				retvalue = ARCMSR_MESSAGE_FAIL;
+				goto message_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->message_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(pcmdmessagefld->messagedatabuffer,
+				(uint8_t *)ver_addr, allxfer_len);
+			pcmdmessagefld->cmdmessage.Length = allxfer_len;
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+			pci_free_consistent(pACB->pdev, 1032, ver_addr, buf_handle);
+		}
+		break;
+	case ARCMSR_MESSAGE_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->pdev, 1032, &buf_handle);
+			if (!ver_addr) {
+				retvalue = ARCMSR_MESSAGE_FAIL;
+				goto message_out;
+			}
+			ptmpuserbuffer = (uint8_t *)ver_addr;
+			user_len = pcmdmessagefld->cmdmessage.Length;
+			memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+			wqbuf_lastindex = pACB->wqbuf_lastindex;
+			wqbuf_firstindex = pACB->wqbuf_firstindex;
+			if (wqbuf_lastindex != wqbuf_firstindex) {
+				struct SENSE_DATA *sensebuffer =
+					(struct SENSE_DATA *)cmd->sense_buffer;
+				arcmsr_post_Qbuffer(pACB);
+				/* has error report sensedata */
+				sensebuffer->ErrorCode = 0x70;
+				sensebuffer->SenseKey = ILLEGAL_REQUEST;
+				sensebuffer->AdditionalSenseLength = 0x0A;
+				sensebuffer->AdditionalSenseCode = 0x20;
+				sensebuffer->Valid = 1;
+				retvalue = ARCMSR_MESSAGE_FAIL;
+			} 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_MESSAGE_WQBUFFER_CLEARED) {
+						pACB->acb_flags &=
+							~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+						arcmsr_post_Qbuffer(pACB);
+					}
+				} else {
+					/* has error report sensedata */
+					struct SENSE_DATA *sensebuffer =
+						(struct SENSE_DATA *)cmd->sense_buffer;
+					sensebuffer->ErrorCode = 0x70;
+					sensebuffer->SenseKey = ILLEGAL_REQUEST;
+					sensebuffer->AdditionalSenseLength = 0x0A;
+					sensebuffer->AdditionalSenseCode = 0x20;
+					sensebuffer->Valid = 1;
+					retvalue = ARCMSR_MESSAGE_FAIL;
+				}
+			}
+			pci_free_consistent(pACB->pdev, 1032, ver_addr, buf_handle);
+		}
+		break;
+	case ARCMSR_MESSAGE_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_MESSAGE_RQBUFFER_CLEARED;
+			pACB->rqbuf_firstindex = 0;
+			pACB->rqbuf_lastindex = 0;
+			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
+		break;
+	case ARCMSR_MESSAGE_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_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED);
+			pACB->wqbuf_firstindex = 0;
+			pACB->wqbuf_lastindex = 0;
+			memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
+		break;
+	case ARCMSR_MESSAGE_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_MESSAGE_WQBUFFER_CLEARED
+				| ACB_F_MESSAGE_RQBUFFER_CLEARED
+				| ACB_F_MESSAGE_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));
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
+		break;
+	case ARCMSR_MESSAGE_RETURN_CODE_3F: {
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+		}
+		break;
+	case ARCMSR_MESSAGE_SAY_HELLO: {
+			int8_t * hello_string = "Hello! I am ARCMSR";
+
+			memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+				, (int16_t)strlen(hello_string));
+			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		}
+		break;
+	case ARCMSR_MESSAGE_SAY_GOODBYE:
+		arcmsr_iop_parking(pACB);
+		break;
+	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
+		arcmsr_flush_adapter_cache(pACB);
+		break;
+	default:
+		retvalue = ARCMSR_MESSAGE_FAIL;
+	}
+message_out:
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+	}
+	return retvalue;
+}
+
+static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *pACB)
+{
+	struct list_head *head = &pACB->ccb_free_list;
+	struct CommandControlBlock *pCCB = NULL;
+
+	if (!list_empty(head)) {
+		pCCB = list_entry(head->next, struct CommandControlBlock, list);
+		list_del(head->next);
+	}
+	return pCCB;
+}
+
+static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = cmd->device->host;
+	struct AdapterControlBlock *pACB = (struct AdapterControlBlock *) host->hostdata;
+	struct CommandControlBlock *pCCB;
+	int target = cmd->device->id;
+	int lun = cmd->device->lun;
+	uint8_t scsicmd = cmd->cmnd[0];
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+	cmd->result = 0;
+	if (scsicmd == 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->host->host_no);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+	if(target == 16) {
+		/* virtual device for iop message transfer */
+		switch(scsicmd) {
+		case INQUIRY: {
+				unsigned char inqdata[36];
+				char *buffer;
+
+				if(lun != 0) {
+					cmd->result = (DID_TIME_OUT << 16);
+					cmd->scsi_done(cmd);
+					return 0;
+				}
+				inqdata[0] = TYPE_PROCESSOR;
+				/* Periph Qualifier & Periph Dev Type */
+				inqdata[1] = 0;
+				/* rem media bit & Dev Type Modifier */
+				inqdata[2] = 0;
+				/* ISO,ECMA,& ANSI versions */
+				inqdata[4] = 31;
+				/* length of additional data */
+				strncpy(&inqdata[8], "Areca   ", 8);
+				/* Vendor Identification */
+				strncpy(&inqdata[16], "RAID controller ", 16);
+				/* Product Identification */
+				strncpy(&inqdata[32], "R001", 4); /* Product Revision */
+				if (cmd->use_sg) {
+					struct scatterlist *sg;
+
+					sg = (struct scatterlist *) cmd->request_buffer;
+					buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+				} else {
+					buffer = cmd->request_buffer;
+				}
+				memcpy(buffer, inqdata, sizeof(inqdata));
+				if (cmd->use_sg) {
+					struct scatterlist *sg;
+
+					sg = (struct scatterlist *) cmd->request_buffer;
+					kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+				}
+				cmd->scsi_done(cmd);
+				return 0;
+			}
+		case WRITE_BUFFER:
+		case READ_BUFFER: {
+				if (arcmsr_iop_message_xfer(pACB, cmd)) {
+    					cmd->result = (DID_ERROR << 16);
+				}
+				cmd->scsi_done(cmd);
+				return 0;
+			}
+		default:
+			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->host->host_no
+				, cmd->cmnd[0]
+				, target
+				, lun);
+			cmd->result = (DID_NO_CONNECT << 16);
+			cmd->scsi_done(cmd);
+			return 0;
+		}
+	}
+	if (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD) {
+		pCCB = arcmsr_get_freeccb(pACB);
+		if (pCCB) {
+			arcmsr_build_ccb(pACB, pCCB, cmd);
+			arcmsr_post_ccb(pACB, pCCB);
+			return 0;
+		}
+	}
+	return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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->host->host_no);
+	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->host->host_no
+		, 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_hd_channels = readl(&reg->message_rwbuffer[4]);
+}
+
+static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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->host->host_no);
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *pACB, struct CommandControlBlock 	*poll_ccb)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct CommandControlBlock *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 CommandControlBlock *)(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->host->host_no
+					, 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->host->host_no
+				, 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 ARCMSR_DEV_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->host->host_no
+					, 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 AdapterControlBlock *pACB)
+{
+	struct MessageUnit __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 AdapterControlBlock *pACB;
+	int retry = 0;
+
+	pACB = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+	printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", pACB->host->host_no);
+	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 AdapterControlBlock *pACB = (struct AdapterControlBlock *)
+			abortcmd->device->host->hostdata;
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct CommandControlBlock *pCCB;
+	uint32_t intmask_org, mask;
+	int i = 0;
+
+	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->host->host_no
+					, abortcmd->device->id
+					, abortcmd->device->lun
+					, pCCB);
+					goto abort_outstanding_cmd;
+				}
+			}
+		}
+	}
+	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 AdapterControlBlock *pACB = (struct AdapterControlBlock *)
+			 cmd->device->host->hostdata;
+	int error;
+
+	printk(KERN_NOTICE
+		"arcmsr%d: abort device command of scsi id=%d lun=%d \n"
+		, pACB->host->host_no
+		, 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->host->host_no
+		, cmd->device->id
+		, cmd->device->lun);
+	return error;
+}
+
+static const char *arcmsr_info(struct Scsi_Host *host)
+{
+	static char buf[256];
+	struct AdapterControlBlock *pACB;
+	uint16_t device_id;
+
+	pACB = (struct AdapterControlBlock *) host->hostdata;
+	device_id = pACB->pdev->device;
+	switch(device_id) {
+	case PCI_DEVICE_ID_ARECA_1110: {
+			sprintf(buf,
+			"ARECA ARC1110 PCI-X 4 PORTS SATA RAID CONTROLLER "
+			"\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1120: {
+			sprintf(buf,
+			"ARECA ARC1120 PCI-X 8 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1130: {
+			sprintf(buf,
+			"ARECA ARC1130 PCI-X 12 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1160: {
+			sprintf(buf,
+			"ARECA ARC1160 PCI-X 16 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1170: {
+			sprintf(buf,
+			"ARECA ARC1170 PCI-X 24 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1210: {
+			sprintf(buf,
+			"ARECA ARC1210 PCI-EXPRESS 4 PORTS SATA RAID CONTROLLER "
+			"\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1220: {
+			sprintf(buf,
+			"ARECA ARC1220 PCI-EXPRESS 8 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1230: {
+			sprintf(buf,
+			"ARECA ARC1230 PCI-EXPRESS 12 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1260: {
+			sprintf(buf,
+			"ARECA ARC1260 PCI-EXPRESS 16 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1270: {
+			sprintf(buf,
+			"ARECA ARC1270 PCI-EXPRESS 24 PORTS SATA RAID CONTROLLER "
+			"(RAID6-ENGINE Inside)\n        %s"
+			, ARCMSR_DRIVER_VERSION);
+			break;
+		}
+	case PCI_DEVICE_ID_ARECA_1280:
+	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 AdapterControlBlock *pACB, struct pci_dev *pdev)
+{
+	struct MessageUnit __iomem *reg;
+	uint32_t intmask_org, ccb_phyaddr_hi32;
+	dma_addr_t dma_coherent_handle, dma_addr;
+	uint8_t pcicmd;
+	void *dma_coherent;
+	void __iomem *page_remapped;
+	int i, j;
+	struct CommandControlBlock *pccb_tmp;
+
+	pci_read_config_byte(pdev, PCI_COMMAND, &pcicmd);
+	pci_write_config_byte(pdev, PCI_COMMAND,
+		pcicmd | PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	page_remapped = ioremap(pci_resource_start(pdev, 0),
+		pci_resource_len(pdev, 0));
+	if ( !page_remapped ) {
+		printk(KERN_NOTICE "arcmsr%d: memory"
+			" mapping region fail \n", pACB->host->host_no);
+		return -ENXIO;
+	}
+	pACB->pmu = (struct MessageUnit __iomem *)(page_remapped);
+	pACB->acb_flags |=
+		(ACB_F_MESSAGE_WQBUFFER_CLEARED
+		| ACB_F_MESSAGE_RQBUFFER_CLEARED
+		| ACB_F_MESSAGE_WQBUFFER_READED);
+	pACB->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+	INIT_LIST_HEAD(&pACB->ccb_free_list);
+	dma_coherent = dma_alloc_coherent(&pdev->dev
+		, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20
+		, &dma_coherent_handle, GFP_KERNEL);
+	if (!dma_coherent) {
+		printk(KERN_NOTICE
+			"arcmsr%d: dma_alloc_coherent got error \n"
+			, pACB->host->host_no);
+		return -ENOMEM;
+	}
+	pACB->dma_coherent = dma_coherent;
+	pACB->dma_coherent_handle = dma_coherent_handle;
+	memset(dma_coherent, 0, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) +
+			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 CommandControlBlock *)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 CommandControlBlock);
+		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"
+				, pACB->host->host_no);
+	}
+	intmask_org = readl(&reg->outbound_intmask);
+	writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE
+			, &reg->outbound_intmask);
+	return 0;
+}
+
+static void arcmsr_pcidev_disattach(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit __iomem *reg = pACB->pmu;
+	struct pci_dev *pdev;
+	struct CommandControlBlock *pCCB;
+	struct Scsi_Host *host;
+	uint32_t intmask_org;
+	int i = 0, poll_count = 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);
+				}
+			}
+		}
+	}
+	host = pACB->host;
+	pdev = pACB->pdev;
+	iounmap(pACB->pmu);
+	arcmsr_free_ccb_pool(pACB);
+	scsi_remove_host(host);
+	scsi_host_put(host);
+	free_irq(pdev->irq, pACB);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
diff -urN oldtree/drivers/scsi/constants.c newtree/drivers/scsi/constants.c
--- oldtree/drivers/scsi/constants.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/constants.c	2006-04-01 05:35:42.971305500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/hosts.c	2006-04-01 05:35:45.871486750 -0500
@@ -264,6 +264,11 @@
 	if (shost->work_q)
 		destroy_workqueue(shost->work_q);
 
+	if (shost->uspace_req_q) {
+		kfree(shost->uspace_req_q->queuedata);
+		scsi_free_queue(shost->uspace_req_q);
+	}
+
 	scsi_destroy_command_freelist(shost);
 	kfree(shost->shost_data);
 
diff -urN oldtree/drivers/scsi/pcmcia/aha152x_stub.c newtree/drivers/scsi/pcmcia/aha152x_stub.c
--- oldtree/drivers/scsi/pcmcia/aha152x_stub.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/aha152x_stub.c	2006-04-01 05:35:44.299388500 -0500
@@ -89,29 +89,29 @@
 /*====================================================================*/
 
 typedef struct scsi_info_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t		node;
     struct Scsi_Host	*host;
 } scsi_info_t;
 
-static void aha152x_release_cs(dev_link_t *link);
+static void aha152x_release_cs(struct pcmcia_device *link);
 static void aha152x_detach(struct pcmcia_device *p_dev);
-static void aha152x_config_cs(dev_link_t *link);
+static int aha152x_config_cs(struct pcmcia_device *link);
 
-static dev_link_t *dev_list;
+static struct pcmcia_device *dev_list;
 
-static int aha152x_attach(struct pcmcia_device *p_dev)
+static int aha152x_probe(struct pcmcia_device *link)
 {
     scsi_info_t *info;
-    dev_link_t *link;
-    
+
     DEBUG(0, "aha152x_attach()\n");
 
     /* Create new SCSI device */
     info = kmalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
     memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
+    info->p_dev = link;
+    link->priv = info;
 
     link->io.NumPorts1 = 0x20;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
@@ -119,41 +119,22 @@
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.Present = PRESENT_OPTION;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    aha152x_config_cs(link);
-
-    return 0;
+    return aha152x_config_cs(link);
 } /* aha152x_attach */
 
 /*====================================================================*/
 
-static void aha152x_detach(struct pcmcia_device *p_dev)
+static void aha152x_detach(struct pcmcia_device *link)
 {
-    dev_link_t *link = dev_to_instance(p_dev);
-    dev_link_t **linkp;
-
     DEBUG(0, "aha152x_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
 
-    if (link->state & DEV_CONFIG)
-	aha152x_release_cs(link);
+    aha152x_release_cs(link);
 
     /* Unlink device structure, free bits */
-    *linkp = link->next;
     kfree(link->priv);
-    
 } /* aha152x_detach */
 
 /*====================================================================*/
@@ -161,9 +142,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void aha152x_config_cs(dev_link_t *link)
+static int aha152x_config_cs(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     scsi_info_t *info = link->priv;
     struct aha152x_setup s;
     tuple_t tuple;
@@ -178,19 +158,16 @@
     tuple.TupleData = tuple_data;
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (1) {
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 	    goto next_entry;
 	/* For New Media T&J, look for a SCSI window */
 	if (parse.cftable_entry.io.win[0].len >= 0x20)
@@ -201,15 +178,15 @@
 	if ((parse.cftable_entry.io.nwin > 0) &&
 	    (link->io.BasePort1 < 0xffff)) {
 	    link->conf.ConfigIndex = parse.cftable_entry.index;
-	    i = pcmcia_request_io(handle, &link->io);
+	    i = pcmcia_request_io(link, &link->io);
 	    if (i == CS_SUCCESS) break;
 	}
     next_entry:
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
     }
     
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
     
     /* Set configuration options for the aha152x driver */
     memset(&s, 0, sizeof(s));
@@ -231,53 +208,30 @@
     }
 
     sprintf(info->node.dev_name, "scsi%d", host->host_no);
-    link->dev = &info->node;
+    link->dev_node = &info->node;
     info->host = host;
 
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
+    return 0;
+
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
     aha152x_release_cs(link);
-    return;
+    return -ENODEV;
 }
 
-static void aha152x_release_cs(dev_link_t *link)
+static void aha152x_release_cs(struct pcmcia_device *link)
 {
 	scsi_info_t *info = link->priv;
 
 	aha152x_release(info->host);
-	link->dev = NULL;
-    
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-    
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 }
 
-static int aha152x_suspend(struct pcmcia_device *dev)
+static int aha152x_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int aha152x_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
 	scsi_info_t *info = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		aha152x_host_reset_host(info->host);
-	}
+	aha152x_host_reset_host(info->host);
 
 	return 0;
 }
@@ -297,10 +251,9 @@
 	.drv		= {
 		.name	= "aha152x_cs",
 	},
-	.probe		= aha152x_attach,
+	.probe		= aha152x_probe,
 	.remove		= aha152x_detach,
 	.id_table       = aha152x_ids,
-	.suspend	= aha152x_suspend,
 	.resume		= aha152x_resume,
 };
 
@@ -317,4 +270,3 @@
 
 module_init(init_aha152x_cs);
 module_exit(exit_aha152x_cs);
- 
diff -urN oldtree/drivers/scsi/pcmcia/fdomain_stub.c newtree/drivers/scsi/pcmcia/fdomain_stub.c
--- oldtree/drivers/scsi/pcmcia/fdomain_stub.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/fdomain_stub.c	2006-04-01 05:35:44.303388750 -0500
@@ -73,57 +73,48 @@
 /*====================================================================*/
 
 typedef struct scsi_info_t {
-    dev_link_t		link;
+	struct pcmcia_device	*p_dev;
     dev_node_t		node;
     struct Scsi_Host	*host;
 } scsi_info_t;
 
 
-static void fdomain_release(dev_link_t *link);
+static void fdomain_release(struct pcmcia_device *link);
 static void fdomain_detach(struct pcmcia_device *p_dev);
-static void fdomain_config(dev_link_t *link);
+static int fdomain_config(struct pcmcia_device *link);
 
-static int fdomain_attach(struct pcmcia_device *p_dev)
+static int fdomain_probe(struct pcmcia_device *link)
 {
-    scsi_info_t *info;
-    dev_link_t *link;
+	scsi_info_t *info;
 
-    DEBUG(0, "fdomain_attach()\n");
+	DEBUG(0, "fdomain_attach()\n");
 
-    /* Create new SCSI device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
-    if (!info) return -ENOMEM;
-    memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
-    link->io.NumPorts1 = 0x10;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-    link->io.IOAddrLines = 10;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.Present = PRESENT_OPTION;
+	/* Create new SCSI device */
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->p_dev = link;
+	link->priv = info;
+	link->io.NumPorts1 = 0x10;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.IOAddrLines = 10;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.Present = PRESENT_OPTION;
 
-    link->handle = p_dev;
-    p_dev->instance = link;
-
-    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-    fdomain_config(link);
-
-    return 0;
+	return fdomain_config(link);
 } /* fdomain_attach */
 
 /*====================================================================*/
 
-static void fdomain_detach(struct pcmcia_device *p_dev)
+static void fdomain_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "fdomain_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		fdomain_release(link);
+	fdomain_release(link);
 
 	kfree(link->priv);
 } /* fdomain_detach */
@@ -133,9 +124,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void fdomain_config(dev_link_t *link)
+static int fdomain_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     scsi_info_t *info = link->priv;
     tuple_t tuple;
     cisparse_t parse;
@@ -150,103 +140,75 @@
     tuple.TupleData = tuple_data;
     tuple.TupleDataMax = 64;
     tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
 
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-    
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
     while (1) {
-	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 	    goto next_entry;
 	link->conf.ConfigIndex = parse.cftable_entry.index;
 	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
-	i = pcmcia_request_io(handle, &link->io);
+	i = pcmcia_request_io(link, &link->io);
 	if (i == CS_SUCCESS) break;
     next_entry:
-	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
     }
 
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
-    
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+
     /* A bad hack... */
     release_region(link->io.BasePort1, link->io.NumPorts1);
 
     /* Set configuration options for the fdomain driver */
     sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
     fdomain_setup(str);
-    
+
     host = __fdomain_16x0_detect(&fdomain_driver_template);
     if (!host) {
         printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
 	goto cs_failed;
     }
- 
-    scsi_add_host(host, NULL); /* XXX handle failure */
+
+    if (scsi_add_host(host, NULL))
+	    goto cs_failed;
     scsi_scan_host(host);
 
     sprintf(info->node.dev_name, "scsi%d", host->host_no);
-    link->dev = &info->node;
+    link->dev_node = &info->node;
     info->host = host;
-    
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
+
+    return 0;
+
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
     fdomain_release(link);
-    return;
-    
+    return -ENODEV;
 } /* fdomain_config */
 
 /*====================================================================*/
 
-static void fdomain_release(dev_link_t *link)
+static void fdomain_release(struct pcmcia_device *link)
 {
-    scsi_info_t *info = link->priv;
-
-    DEBUG(0, "fdomain_release(0x%p)\n", link);
-
-    scsi_remove_host(info->host);
-    link->dev = NULL;
-    
-    pcmcia_release_configuration(link->handle);
-    pcmcia_release_io(link->handle, &link->io);
-    pcmcia_release_irq(link->handle, &link->irq);
+	scsi_info_t *info = link->priv;
 
-    scsi_unregister(info->host);
+	DEBUG(0, "fdomain_release(0x%p)\n", link);
 
-    link->state &= ~DEV_CONFIG;
+	scsi_remove_host(info->host);
+	pcmcia_disable_device(link);
+	scsi_unregister(info->host);
 }
 
 /*====================================================================*/
 
-static int fdomain_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int fdomain_resume(struct pcmcia_device *dev)
+static int fdomain_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-		fdomain_16x0_bus_reset(NULL);
-	}
+	fdomain_16x0_bus_reset(NULL);
 
 	return 0;
 }
@@ -264,10 +226,9 @@
 	.drv		= {
 		.name	= "fdomain_cs",
 	},
-	.probe		= fdomain_attach,
+	.probe		= fdomain_probe,
 	.remove		= fdomain_detach,
 	.id_table       = fdomain_ids,
-	.suspend	= fdomain_suspend,
 	.resume		= fdomain_resume,
 };
 
diff -urN oldtree/drivers/scsi/pcmcia/nsp_cs.c newtree/drivers/scsi/pcmcia/nsp_cs.c
--- oldtree/drivers/scsi/pcmcia/nsp_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/nsp_cs.c	2006-04-01 05:35:44.303388750 -0500
@@ -1593,11 +1593,11 @@
     configure the card at this point -- we wait until we receive a
     card insertion event.
 ======================================================================*/
-static int nsp_cs_attach(struct pcmcia_device *p_dev)
+static int nsp_cs_probe(struct pcmcia_device *link)
 {
 	scsi_info_t  *info;
-	dev_link_t   *link;
 	nsp_hw_data  *data = &nsp_data_base;
+	int ret;
 
 	nsp_dbg(NSP_DEBUG_INIT, "in");
 
@@ -1605,7 +1605,7 @@
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL) { return -ENOMEM; }
 	memset(info, 0, sizeof(*info));
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 	data->ScsiInfo = info;
 
@@ -1627,18 +1627,13 @@
 
 	/* General socket configuration */
 	link->conf.Attributes	 = CONF_ENABLE_IRQ;
-	link->conf.Vcc		 = 50;
 	link->conf.IntType	 = INT_MEMORY_AND_IO;
 	link->conf.Present	 = PRESENT_OPTION;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	nsp_cs_config(link);
+	ret = nsp_cs_config(link);
 
 	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
-	return 0;
+	return ret;
 } /* nsp_cs_attach */
 
 
@@ -1648,16 +1643,12 @@
     structures are freed.  Otherwise, the structures will be freed
     when the device is released.
 ======================================================================*/
-static void nsp_cs_detach(struct pcmcia_device *p_dev)
+static void nsp_cs_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
 
-	if (link->state & DEV_CONFIG) {
-		((scsi_info_t *)link->priv)->stop = 1;
-		nsp_cs_release(link);
-	}
+	((scsi_info_t *)link->priv)->stop = 1;
+	nsp_cs_release(link);
 
 	kfree(link->priv);
 	link->priv = NULL;
@@ -1672,9 +1663,9 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 /*====================================================================*/
-static void nsp_cs_config(dev_link_t *link)
+static int nsp_cs_config(struct pcmcia_device *link)
 {
-	client_handle_t	  handle = link->handle;
+	int		  ret;
 	scsi_info_t	 *info	 = link->priv;
 	tuple_t		  tuple;
 	cisparse_t	  parse;
@@ -1698,26 +1689,22 @@
 	tuple.TupleData	      = tuple_data;
 	tuple.TupleDataMax    = sizeof(tuple_data);
 	tuple.TupleOffset     = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData,	pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple,	pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData,	pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple,	pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present    = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state	      |= DEV_CONFIG;
-
 	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-	link->conf.Vcc = conf.Vcc;
+	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
 
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
 
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
@@ -1743,10 +1730,10 @@
 		}
 
 		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		} else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		}
 
@@ -1773,7 +1760,7 @@
 				link->io.NumPorts2 = io->win[1].len;
 			}
 			/* This reserves IO space but doesn't actually enable it */
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
+			if (pcmcia_request_io(link, &link->io) != 0)
 				goto next_entry;
 		}
 
@@ -1788,7 +1775,7 @@
 				req.Size = 0x1000;
 			}
 			req.AccessSpeed = 0;
-			if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
+			if (pcmcia_request_window(&link, &req, &link->win) != 0)
 				goto next_entry;
 			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
 			if (pcmcia_map_mem_page(link->win, &map) != 0)
@@ -1802,17 +1789,14 @@
 
 	next_entry:
 		nsp_dbg(NSP_DEBUG_INIT, "next");
-
-		if (link->io.NumPorts1) {
-			pcmcia_release_io(link->handle, &link->io);
-		}
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		pcmcia_disable_device(link);
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 
 	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 	}
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	if (free_ports) {
 		if (link->io.BasePort1) {
@@ -1854,16 +1838,19 @@
 
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
-	scsi_add_host (host, NULL);
+	ret = scsi_add_host (host, NULL);
+	if (ret)
+		goto cs_failed;
+
 	scsi_scan_host(host);
 
 	snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
-	link->dev  = &info->node;
+	link->dev_node  = &info->node;
 	info->host = host;
 
 #else
 	nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
-	tail = &link->dev;
+	tail = &link->dev_node;
 	info->ndev = 0;
 
 	nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
@@ -1908,11 +1895,10 @@
 #endif
 
 	/* Finally, report what we've done */
-	printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d",
-	       link->conf.ConfigIndex,
-	       link->conf.Vcc/10, link->conf.Vcc%10);
-	if (link->conf.Vpp1) {
-		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	printk(KERN_INFO "nsp_cs: index 0x%02x: ",
+	       link->conf.ConfigIndex);
+	if (link->conf.Vpp) {
+		printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
 	}
 	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
 		printk(", irq %d", link->irq.AssignedIRQ);
@@ -1929,15 +1915,14 @@
 		       req.Base+req.Size-1);
 	printk("\n");
 
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	return 0;
 
  cs_failed:
 	nsp_dbg(NSP_DEBUG_INIT, "config fail");
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	nsp_cs_release(link);
 
-	return;
+	return -ENODEV;
 } /* nsp_cs_config */
 #undef CS_CHECK
 
@@ -1947,7 +1932,7 @@
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
 ======================================================================*/
-static void nsp_cs_release(dev_link_t *link)
+static void nsp_cs_release(struct pcmcia_device *link)
 {
 	scsi_info_t *info = link->priv;
 	nsp_hw_data *data = NULL;
@@ -1968,22 +1953,15 @@
 #else
 	scsi_unregister_host(&nsp_driver_template);
 #endif
-	link->dev = NULL;
+	link->dev_node = NULL;
 
 	if (link->win) {
 		if (data != NULL) {
 			iounmap((void *)(data->MmioAddress));
 		}
-		pcmcia_release_window(link->win);
-	}
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1) {
-		pcmcia_release_io(link->handle, &link->io);
 	}
-	if (link->irq.AssignedIRQ) {
-		pcmcia_release_irq(link->handle, &link->irq);
-	}
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
 	if (info->host != NULL) {
 		scsi_host_put(info->host);
@@ -1991,14 +1969,11 @@
 #endif
 } /* nsp_cs_release */
 
-static int nsp_cs_suspend(struct pcmcia_device *dev)
+static int nsp_cs_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	scsi_info_t *info = link->priv;
 	nsp_hw_data *data;
 
-	link->state |= DEV_SUSPEND;
-
 	nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
 
 	if (info->host != NULL) {
@@ -2011,25 +1986,16 @@
 
 	info->stop = 1;
 
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
 	return 0;
 }
 
-static int nsp_cs_resume(struct pcmcia_device *dev)
+static int nsp_cs_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	scsi_info_t *info = link->priv;
 	nsp_hw_data *data;
 
 	nsp_dbg(NSP_DEBUG_INIT, "event: resume");
 
-	link->state &= ~DEV_SUSPEND;
-
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
 	info->stop = 0;
 
 	if (info->host != NULL) {
@@ -2065,7 +2031,7 @@
 	.drv		= {
 		.name	= "nsp_cs",
 	},
-	.probe		= nsp_cs_attach,
+	.probe		= nsp_cs_probe,
 	.remove		= nsp_cs_detach,
 	.id_table	= nsp_cs_ids,
 	.suspend	= nsp_cs_suspend,
@@ -2098,19 +2064,7 @@
 static void __exit nsp_cs_exit(void)
 {
 	nsp_msg(KERN_INFO, "unloading...");
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
 	pcmcia_unregister_driver(&nsp_driver);
-#else
-	unregister_pcmcia_driver(&dev_info);
-	/* XXX: this really needs to move into generic code.. */
-	while (dev_list != NULL) {
-		if (dev_list->state & DEV_CONFIG) {
-			nsp_cs_release(dev_list);
-		}
-		nsp_cs_detach(dev_list);
-	}
-#endif
 }
 
 
diff -urN oldtree/drivers/scsi/pcmcia/nsp_cs.h newtree/drivers/scsi/pcmcia/nsp_cs.h
--- oldtree/drivers/scsi/pcmcia/nsp_cs.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/nsp_cs.h	2006-04-01 05:35:44.303388750 -0500
@@ -225,7 +225,7 @@
 /*====================================================================*/
 
 typedef struct scsi_info_t {
-	dev_link_t             link;
+	struct pcmcia_device	*p_dev;
 	struct Scsi_Host      *host;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
 	dev_node_t             node;
@@ -297,8 +297,8 @@
 
 /* Card service functions */
 static void        nsp_cs_detach (struct pcmcia_device *p_dev);
-static void        nsp_cs_release(dev_link_t *link);
-static void        nsp_cs_config (dev_link_t *link);
+static void        nsp_cs_release(struct pcmcia_device *link);
+static int        nsp_cs_config (struct pcmcia_device *link);
 
 /* Linux SCSI subsystem specific functions */
 static struct Scsi_Host *nsp_detect     (struct scsi_host_template *sht);
@@ -450,7 +450,7 @@
 	return host;
 }
 
-static void cs_error(client_handle_t handle, int func, int ret)
+static void cs_error(struct pcmcia_device *handle, int func, int ret)
 {
 	error_info_t err = { func, ret };
 	pcmcia_report_error(handle, &err);
diff -urN oldtree/drivers/scsi/pcmcia/qlogic_stub.c newtree/drivers/scsi/pcmcia/qlogic_stub.c
--- oldtree/drivers/scsi/pcmcia/qlogic_stub.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/qlogic_stub.c	2006-04-01 05:35:44.303388750 -0500
@@ -91,18 +91,18 @@
 /*====================================================================*/
 
 typedef struct scsi_info_t {
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 	struct Scsi_Host *host;
 	unsigned short manf_id;
 } scsi_info_t;
 
-static void qlogic_release(dev_link_t *link);
+static void qlogic_release(struct pcmcia_device *link);
 static void qlogic_detach(struct pcmcia_device *p_dev);
-static void qlogic_config(dev_link_t * link);
+static int qlogic_config(struct pcmcia_device * link);
 
 static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host,
-				dev_link_t *link, int qbase, int qlirq)
+				struct pcmcia_device *link, int qbase, int qlirq)
 {
 	int qltyp;		/* type of chip */
 	int qinitid;
@@ -156,10 +156,9 @@
 err:
 	return NULL;
 }
-static int qlogic_attach(struct pcmcia_device *p_dev)
+static int qlogic_probe(struct pcmcia_device *link)
 {
 	scsi_info_t *info;
-	dev_link_t *link;
 
 	DEBUG(0, "qlogic_attach()\n");
 
@@ -168,7 +167,7 @@
 	if (!info)
 		return -ENOMEM;
 	memset(info, 0, sizeof(*info));
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 	link->io.NumPorts1 = 16;
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
@@ -176,30 +175,19 @@
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	link->conf.Present = PRESENT_OPTION;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	qlogic_config(link);
-
-	return 0;
+	return qlogic_config(link);
 }				/* qlogic_attach */
 
 /*====================================================================*/
 
-static void qlogic_detach(struct pcmcia_device *p_dev)
+static void qlogic_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "qlogic_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		qlogic_release(link);
-
+	qlogic_release(link);
 	kfree(link->priv);
 
 }				/* qlogic_detach */
@@ -209,9 +197,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void qlogic_config(dev_link_t * link)
+static int qlogic_config(struct pcmcia_device * link)
 {
-	client_handle_t handle = link->handle;
 	scsi_info_t *info = link->priv;
 	tuple_t tuple;
 	cisparse_t parse;
@@ -225,38 +212,35 @@
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 
 	tuple.DesiredTuple = CISTPL_MANFID;
-	if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
+	if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS))
 		info->manf_id = le16_to_cpu(tuple.TupleData[0]);
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 		link->conf.ConfigIndex = parse.cftable_entry.index;
 		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
 		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
 		if (link->io.BasePort1 != 0) {
-			i = pcmcia_request_io(handle, &link->io);
+			i = pcmcia_request_io(link, &link->io);
 			if (i == CS_SUCCESS)
 				break;
 		}
 	      next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
 		/* set ATAcmd */
@@ -275,82 +259,54 @@
 	
 	if (!host) {
 		printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
-		goto out;
+		goto cs_failed;
 	}
 
 	sprintf(info->node.dev_name, "scsi%d", host->host_no);
-	link->dev = &info->node;
+	link->dev_node = &info->node;
 	info->host = host;
 
-out:
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
-	link->dev = NULL;
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
-	return;
+	cs_error(link, last_fn, last_ret);
+	pcmcia_disable_device(link);
+	return -ENODEV;
 
 }				/* qlogic_config */
 
 /*====================================================================*/
 
-static void qlogic_release(dev_link_t *link)
+static void qlogic_release(struct pcmcia_device *link)
 {
 	scsi_info_t *info = link->priv;
 
 	DEBUG(0, "qlogic_release(0x%p)\n", link);
 
 	scsi_remove_host(info->host);
-	link->dev = NULL;
 
 	free_irq(link->irq.AssignedIRQ, info->host);
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
+	pcmcia_disable_device(link);
 
 	scsi_host_put(info->host);
-
-	link->state &= ~DEV_CONFIG;
 }
 
 /*====================================================================*/
 
-static int qlogic_suspend(struct pcmcia_device *dev)
+static int qlogic_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int qlogic_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
+	scsi_info_t *info = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		scsi_info_t *info = link->priv;
-
-		pcmcia_request_configuration(link->handle, &link->conf);
-		if ((info->manf_id == MANFID_MACNICA) ||
-		    (info->manf_id == MANFID_PIONEER) ||
-		    (info->manf_id == 0x0098)) {
-			outb(0x80, link->io.BasePort1 + 0xd);
-			outb(0x24, link->io.BasePort1 + 0x9);
-			outb(0x04, link->io.BasePort1 + 0xd);
-		}
-		/* Ugggglllyyyy!!! */
-		qlogicfas408_bus_reset(NULL);
+	pcmcia_request_configuration(link, &link->conf);
+	if ((info->manf_id == MANFID_MACNICA) ||
+	    (info->manf_id == MANFID_PIONEER) ||
+	    (info->manf_id == 0x0098)) {
+		outb(0x80, link->io.BasePort1 + 0xd);
+		outb(0x24, link->io.BasePort1 + 0x9);
+		outb(0x04, link->io.BasePort1 + 0xd);
 	}
+	/* Ugggglllyyyy!!! */
+	qlogicfas408_bus_reset(NULL);
 
 	return 0;
 }
@@ -382,10 +338,9 @@
 	.drv		= {
 	.name		= "qlogic_cs",
 	},
-	.probe		= qlogic_attach,
+	.probe		= qlogic_probe,
 	.remove		= qlogic_detach,
 	.id_table       = qlogic_ids,
-	.suspend	= qlogic_suspend,
 	.resume		= qlogic_resume,
 };
 
diff -urN oldtree/drivers/scsi/pcmcia/sym53c500_cs.c newtree/drivers/scsi/pcmcia/sym53c500_cs.c
--- oldtree/drivers/scsi/pcmcia/sym53c500_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/pcmcia/sym53c500_cs.c	2006-04-01 05:35:44.303388750 -0500
@@ -202,7 +202,7 @@
 /* ================================================================== */
 
 struct scsi_info_t {
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 	struct Scsi_Host *host;
 	unsigned short manf_id;
@@ -527,7 +527,7 @@
 }
 
 static void
-SYM53C500_release(dev_link_t *link)
+SYM53C500_release(struct pcmcia_device *link)
 {
 	struct scsi_info_t *info = link->priv;
 	struct Scsi_Host *shost = info->host;
@@ -550,13 +550,7 @@
 	if (shost->io_port && shost->n_io_port)
 		release_region(shost->io_port, shost->n_io_port);
 
-	link->dev = NULL;
-
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 
 	scsi_host_put(shost);
 } /* SYM53C500_release */
@@ -713,10 +707,9 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void
-SYM53C500_config(dev_link_t *link)
+static int
+SYM53C500_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	struct scsi_info_t *info = link->priv;
 	tuple_t tuple;
 	cisparse_t parse;
@@ -733,40 +726,37 @@
 	tuple.TupleDataMax = 64;
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 
 	tuple.DesiredTuple = CISTPL_MANFID;
-	if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
-	    (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
+	if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) &&
+	    (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS))
 		info->manf_id = le16_to_cpu(tuple.TupleData[0]);
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-		    pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+		    pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 		link->conf.ConfigIndex = parse.cftable_entry.index;
 		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
 		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
 
 		if (link->io.BasePort1 != 0) {
-			i = pcmcia_request_io(handle, &link->io);
+			i = pcmcia_request_io(link, &link->io);
 			if (i == CS_SUCCESS)
 				break;
 		}
 next_entry:
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	/*
 	*  That's the trouble with copying liberally from another driver.
@@ -835,7 +825,7 @@
 	data->fast_pio = USE_FAST_PIO;
 
 	sprintf(info->node.dev_name, "scsi%d", host->host_no);
-	link->dev = &info->node;
+	link->dev_node = &info->node;
 	info->host = host;
 
 	if (scsi_add_host(host, NULL))
@@ -843,7 +833,7 @@
 
 	scsi_scan_host(host);
 
-	goto out;	/* SUCCESS */
+	return 0;
 
 err_free_irq:
 	free_irq(irq_level, host);
@@ -852,74 +842,50 @@
 err_release:
 	release_region(port_base, 0x10);
 	printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n");
-
-out:
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	return -ENODEV;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	SYM53C500_release(link);
-	return;
+	return -ENODEV;
 } /* SYM53C500_config */
 
-static int sym53c500_suspend(struct pcmcia_device *dev)
+static int sym53c500_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int sym53c500_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
 	struct scsi_info_t *info = link->priv;
 
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG) {
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-		/* See earlier comment about manufacturer IDs. */
-		if ((info->manf_id == MANFID_MACNICA) ||
-		    (info->manf_id == MANFID_PIONEER) ||
-		    (info->manf_id == 0x0098)) {
-			outb(0x80, link->io.BasePort1 + 0xd);
-			outb(0x24, link->io.BasePort1 + 0x9);
-			outb(0x04, link->io.BasePort1 + 0xd);
-		}
-		/*
-		 *  If things don't work after a "resume",
-		 *  this is a good place to start looking.
-		 */
-		SYM53C500_int_host_reset(link->io.BasePort1);
+	/* See earlier comment about manufacturer IDs. */
+	if ((info->manf_id == MANFID_MACNICA) ||
+	    (info->manf_id == MANFID_PIONEER) ||
+	    (info->manf_id == 0x0098)) {
+		outb(0x80, link->io.BasePort1 + 0xd);
+		outb(0x24, link->io.BasePort1 + 0x9);
+		outb(0x04, link->io.BasePort1 + 0xd);
 	}
+	/*
+	 *  If things don't work after a "resume",
+	 *  this is a good place to start looking.
+	 */
+	SYM53C500_int_host_reset(link->io.BasePort1);
 
 	return 0;
 }
 
 static void
-SYM53C500_detach(struct pcmcia_device *p_dev)
+SYM53C500_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "SYM53C500_detach(0x%p)\n", link);
 
-	if (link->state & DEV_CONFIG)
-		SYM53C500_release(link);
+	SYM53C500_release(link);
 
 	kfree(link->priv);
 	link->priv = NULL;
 } /* SYM53C500_detach */
 
 static int
-SYM53C500_attach(struct pcmcia_device *p_dev)
+SYM53C500_probe(struct pcmcia_device *link)
 {
 	struct scsi_info_t *info;
-	dev_link_t *link;
 
 	DEBUG(0, "SYM53C500_attach()\n");
 
@@ -928,7 +894,7 @@
 	if (!info)
 		return -ENOMEM;
 	memset(info, 0, sizeof(*info));
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 	link->io.NumPorts1 = 16;
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
@@ -936,17 +902,10 @@
 	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
 	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	link->conf.Present = PRESENT_OPTION;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	SYM53C500_config(link);
-
-	return 0;
+	return SYM53C500_config(link);
 } /* SYM53C500_attach */
 
 MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
@@ -966,10 +925,9 @@
 	.drv		= {
 		.name	= "sym53c500_cs",
 	},
-	.probe		= SYM53C500_attach,
+	.probe		= SYM53C500_probe,
 	.remove		= SYM53C500_detach,
 	.id_table       = sym53c500_ids,
-	.suspend	= sym53c500_suspend,
 	.resume		= sym53c500_resume,
 };
 
diff -urN oldtree/drivers/scsi/sas/Kconfig newtree/drivers/scsi/sas/Kconfig
--- oldtree/drivers/scsi/sas/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/Kconfig	2006-04-01 05:35:45.919489750 -0500
@@ -0,0 +1,45 @@
+#
+# Kernel configuration file for the SAS Class
+#
+# Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# $Id: //depot/sas-class/Kconfig#6 $
+#
+
+config SAS_CLASS
+	tristate "SAS Layer and Discovery"
+	depends on SCSI
+	help
+		If you wish to use a SAS Low Level Device Driver (LLDD)
+		say Y or M here.  Otherwise, say N.
+
+		SAS LLDDs which can make use of the SAS Transport Layer
+		are LLDDs who do not hide the transport in firmware.
+		Such LLDDs expose the transport to a management layer.
+		E.g. aic94xx SAS LLDD is such a LLDD.
+
+config SAS_DEBUG
+	bool "Compile the SAS Layer in debug mode"
+	default y
+	depends on SAS_CLASS
+	help
+		Compiles the SAS Layer in debug mode.  In debug mode, the
+		SAS Layer prints diagnostic and debug messages.
diff -urN oldtree/drivers/scsi/sas/Makefile newtree/drivers/scsi/sas/Makefile
--- oldtree/drivers/scsi/sas/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/Makefile	2006-04-01 05:35:45.919489750 -0500
@@ -0,0 +1,42 @@
+#
+# Kernel Makefile for the SAS Class
+#
+# Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# $Id: //depot/sas-class/Makefile#20 $
+#
+
+ifeq ($(CONFIG_SAS_DEBUG),y)
+	EXTRA_CFLAGS += -DSAS_DEBUG -g
+endif
+
+clean-files += expander_conf
+
+obj-$(CONFIG_SAS_CLASS) += sas_class.o
+sas_class-y +=  sas_init.o     \
+		sas_common.o   \
+		sas_phy.o      \
+		sas_port.o     \
+		sas_event.o    \
+		sas_dump.o     \
+		sas_discover.o \
+		sas_expander.o \
+		sas_scsi_host.o
diff -urN oldtree/drivers/scsi/sas/README newtree/drivers/scsi/sas/README
--- oldtree/drivers/scsi/sas/README	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/README	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,484 @@
+SAS Layer
+---------
+
+The SAS Layer is a management infrastructure which manages
+SAS LLDDs.  It sits between SCSI Core and SAS LLDDs.  The
+layout is as follows: while SCSI Core is concerned with
+SAM/SPC issues, and a SAS LLDD+sequencer is concerned with
+phy/OOB/link management, the SAS layer is concerned with:
+
+      * SAS Phy/Port/HA event management (LLDD generates,
+        SAS Layer processes),
+      * SAS Port management (creation/destruction),
+      * SAS Domain discovery and revalidation,
+      * SAS Domain device management,
+      * SCSI Host registration/unregistration,
+      * Device registration with SCSI Core (SAS) or libata
+        (SATA), and
+      * Expander management and exporting expander control
+        to user space.
+
+A SAS LLDD is a PCI device driver.  It is concerned with
+phy/OOB management, and vendor specific tasks and generates
+events to the SAS layer.
+
+The SAS Layer does most SAS tasks as outlined in the SAS 1.1
+spec.
+
+The sas_ha_struct describes the SAS LLDD to the SAS layer.
+Most of it is used by the SAS Layer but a few fields need to
+be initialized by the LLDDs.
+
+After initializing your hardware, from the probe() function
+you call sas_register_ha(). It will register your LLDD with
+the SCSI subsystem, creating a SCSI host and it will
+register your SAS driver with the sysfs SAS tree it creates.
+It will then return.  Then you enable your phys to actually
+start OOB (at which point your driver will start calling the
+notify_* event callbacks).
+
+Structure descriptions:
+
+struct sas_phy --------------------
+Normally this is statically embedded to your driver's
+phy structure:
+	struct my_phy {
+	       blah;
+	       struct sas_phy sas_phy;
+	       bleh;
+	};
+And then all the phys are an array of my_phy in your HA
+struct (shown below).
+
+Then as you go along and initialize your phys you also
+initialize the sas_phy struct, along with your own
+phy structure.
+
+In general, the phys are managed by the LLDD and the ports
+are managed by the SAS layer.  So the phys are initialized
+and updated by the LLDD and the ports are initialized and
+updated by the SAS layer.
+
+There is a scheme where the LLDD can RW certain fields,
+and the SAS layer can only read such ones, and vice versa.
+The idea is to avoid unnecessary locking.
+
+enabled -- must be set (0/1)
+id -- must be set [0,MAX_PHYS)
+class, proto, type, role, oob_mode, linkrate -- must be set
+oob_mode --  you set this when OOB has finished and then notify
+the SAS Layer.
+
+sas_addr -- this normally points to an array holding the sas
+address of the phy, possibly somewhere in your my_phy
+struct.
+
+attached_sas_addr -- set this when you (LLDD) receive an
+IDENTIFY frame or a FIS frame, _before_ notifying the SAS
+layer.  The idea is that sometimes the LLDD may want to fake
+or provide a different SAS address on that phy/port and this
+allows it to do this.  At best you should copy the sas
+address from the IDENTIFY frame or maybe generate a SAS
+address for SATA directly attached devices.  The Discover
+process may later change this.
+
+frame_rcvd -- this is where you copy the IDENTIFY/FIS frame
+when you get it; you lock, copy, set frame_rcvd_size and
+unlock the lock, and then call the event.  It is a pointer
+since there's no way to know your hw frame size _exactly_,
+so you define the actual array in your phy struct and let
+this pointer point to it.  You copy the frame from your
+DMAable memory to that area holding the lock.
+
+sas_prim -- this is where primitives go when they're
+received.  See sas.h. Grab the lock, set the primitive,
+release the lock, notify.
+
+port -- this points to the sas_port if the phy belongs
+to a port -- the LLDD only reads this. It points to the
+sas_port this phy is part of.  Set by the SAS Layer.
+
+ha -- may be set; the SAS layer sets it anyway.
+
+lldd_phy -- you should set this to point to your phy so you
+can find your way around faster when the SAS layer calls one
+of your callbacks and passes you a phy.  If the sas_phy is
+embedded you can also use container_of -- whatever you
+prefer.
+
+
+struct sas_port --------------------
+The LLDD doesn't set any fields of this struct -- it only
+reads them.  They should be self explanatory.
+
+phy_mask is 32 bit, this should be enough for now, as I
+haven't heard of a HA having more than 8 phys.
+
+lldd_port -- I haven't found use for that -- maybe other
+LLDD who wish to have internal port representation can make
+use of this.
+
+
+struct sas_ha_struct --------------------
+It normally is statically declared in your own LLDD
+structure describing your adapter:
+struct my_sas_ha {
+       blah;
+       struct sas_ha_struct sas_ha;
+       struct my_phy phys[MAX_PHYS];
+       struct sas_port sas_ports[MAX_PHYS]; /* (1) */
+       bleh;
+};
+
+(1) If your LLDD doesn't have its own port representation.
+
+What needs to be initialized (sample function given below).
+
+pcidev
+sas_addr -- since the SAS layer doesn't want to mess with
+	 memory allocation, etc, this points to statically
+	 allocated array somewhere (say in your host adapter
+	 structure) and holds the SAS address of the host
+	 adapter as given by you or the manufacturer, etc.
+sas_port
+sas_phy -- an array of pointers to structures. (see
+	note above on sas_addr).
+	These must be set.  See more notes below.
+num_phys -- the number of phys present in the sas_phy array,
+	 and the number of ports present in the sas_port
+	 array.  There can be a maximum num_phys ports (one per
+	 port) so we drop the num_ports, and only use
+	 num_phys.
+
+The event interface:
+
+	/* LLDD calls these to notify the class of an event. */
+	void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
+	void (*notify_port_event)(struct sas_phy *, enum port_event);
+	void (*notify_phy_event)(struct sas_phy *, enum phy_event);
+
+When sas_register_ha() returns, those are set and can be
+called by the LLDD to notify the SAS layer of such events
+the SAS layer.
+
+The port notification:
+
+	/* The class calls these to notify the LLDD of an event. */
+	void (*lldd_port_formed)(struct sas_phy *);
+	void (*lldd_port_deformed)(struct sas_phy *);
+
+If the LLDD wants notification when a port has been formed
+or deformed it sets those to a function satisfying the type.
+
+A SAS LLDD should also implement at least one of the Task
+Management Functions (TMFs) described in SAM:
+
+	/* Task Management Functions. Must be called from process context. */
+	int (*lldd_abort_task)(struct sas_task *);
+	int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
+	int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
+	int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
+	int (*lldd_I_T_nexus_reset)(struct domain_device *);
+	int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
+	int (*lldd_query_task)(struct sas_task *);
+
+For more information please read SAM from T10.org.
+
+Port and Adapter management:
+
+	/* Port and Adapter management */
+	int (*lldd_clear_nexus_port)(struct sas_port *);
+	int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
+
+A SAS LLDD should implement at least one of those.
+
+Phy management:
+
+	/* Phy management */
+	int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
+
+lldd_ha -- set this to point to your HA struct. You can also
+use container_of if you embedded it as shown above.
+
+A sample initialization and registration function
+can look like this (called last thing from probe())
+*but* before you enable the phys to do OOB:
+
+static int register_sas_ha(struct my_sas_ha *my_ha)
+{
+	int i;
+	static struct sas_phy   *sas_phys[MAX_PHYS];
+	static struct sas_port  *sas_ports[MAX_PHYS];
+
+	my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
+
+	for (i = 0; i < MAX_PHYS; i++) {
+		sas_phys[i] = &my_ha->phys[i].sas_phy;
+		sas_ports[i] = &my_ha->sas_ports[i];
+	}
+
+	my_ha->sas_ha.sas_phy  = sas_phys;
+	my_ha->sas_ha.sas_port = sas_ports;
+	my_ha->sas_ha.num_phys = MAX_PHYS;
+
+	my_ha->sas_ha.lldd_port_formed = my_port_formed;
+
+	my_ha->sas_ha.lldd_dev_found = my_dev_found;
+	my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
+
+	my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1)
+
+	my_ha->sas_ha.lldd_queue_size = ha_can_queue;
+	my_ha->sas_ha.lldd_execute_task = my_execute_task;
+
+	my_ha->sas_ha.lldd_abort_task     = my_abort_task;
+	my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
+	my_ha->sas_ha.lldd_clear_aca      = my_clear_aca;
+	my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
+	my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
+	my_ha->sas_ha.lldd_lu_reset       = my_lu_reset;
+	my_ha->sas_ha.lldd_query_task     = my_query_task;
+
+	my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
+	my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
+
+	my_ha->sas_ha.lldd_control_phy = my_control_phy;
+
+	return sas_register_ha(&my_ha->sas_ha);
+}
+
+(1) This is normally a LLDD parameter, something of the
+lines of a task collector.  What it tells the SAS Layer is
+whether the SAS layer should run in Direct Mode (default:
+value 0 or 1) or Task Collector Mode (value greater than 1).
+
+In Direct Mode, the SAS Layer calls Execute Task as soon as
+it has a command to send to the SDS, _and_ this is a single
+command, i.e. not linked.
+
+Some hardware (e.g. aic94xx) has the capability to DMA more
+than one task at a time (interrupt) from host memory.  Task
+Collector Mode is an optional feature for HAs which support
+this in their hardware.  (Again, it is completely optional
+even if your hardware supports it.)
+
+In Task Collector Mode, the SAS Layer would do _natural_
+coalescing of tasks and at the appropriate moment it would
+call your driver to DMA more than one task in a single HA
+interrupt. DMBS may want to use this by insmod/modprobe
+setting the lldd_max_execute_num to something greater than
+1.
+
+(2) SAS 1.1 does not define I_T Nexus Reset TMF.
+
+Events
+------
+
+Events are _the only way_ a SAS LLDD notifies the SAS layer
+of anything.  There is no other method or way a LLDD to tell
+the SAS layer of anything happening internally or in the SAS
+domain.
+
+Phy events:
+	PHYE_LOSS_OF_SIGNAL, (C)
+	PHYE_OOB_DONE,
+	PHYE_OOB_ERROR,      (C)
+	PHYE_SPINUP_HOLD.
+
+Port events, passed on a _phy_:
+	PORTE_BYTES_DMAED,      (M)
+	PORTE_BROADCAST_RCVD,   (E)
+	PORTE_LINK_RESET_ERR,   (C)
+	PORTE_TIMER_EVENT,      (C)
+	PORTE_HARD_RESET.
+
+Host Adapter event:
+	HAE_RESET
+
+A SAS LLDD should be able to generate
+	- at least one event from group C (choice),
+	- events marked M (mandatory) are mandatory (only one),
+	- events marked E (expander) if it wants the SAS layer
+	  to handle domain revalidation (only one such).
+	- Unmarked events are optional.
+
+Meaning:
+
+HAE_RESET -- when your HA got internal error and was reset.
+
+PORTE_BYTES_DMAED -- on receiving an IDENTIFY/FIS frame
+PORTE_BROADCAST_RCVD -- on receiving a primitive
+PORTE_LINK_RESET_ERR -- timer expired, loss of signal, loss
+of DWS, etc. (*)
+PORTE_TIMER_EVENT -- DWS reset timeout timer expired (*)
+PORTE_HARD_RESET -- Hard Reset primitive received.
+
+PHYE_LOSS_OF_SIGNAL -- the device is gone (*)
+PHYE_OOB_DONE -- OOB went fine and oob_mode is valid
+PHYE_OOB_ERROR -- Error while doing OOB, the device probably
+got disconnected. (*)
+PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
+
+(*) should set/clear the appropriate fields in the phy,
+    or alternatively call the inlined sas_phy_disconnected()
+    which is just a helper, from their tasklet.
+
+The Execute Command SCSI RPC:
+
+	int (*lldd_execute_task)(struct sas_task *, int num,
+				 unsigned long gfp_flags);
+
+Used to queue a task to the SAS LLDD.  @task is the tasks to
+be executed.  @num should be the number of tasks being
+queued at this function call (they are linked listed via
+task::list), @gfp_mask should be the gfp_mask defining the
+context of the caller.
+
+This function should implement the Execute Command SCSI RPC,
+or if you're sending a SCSI Task as linked commands, you
+should also use this function.
+
+That is, when lldd_execute_task() is called, the command(s)
+go out on the transport *immediately*.  There is *no*
+queuing of any sort and at any level in a SAS LLDD.
+
+The use of task::list is two-fold, one for linked commands,
+the other discussed below.
+
+It is possible to queue up more than one task at a time, by
+initializing the list element of struct sas_task, and
+passing the number of tasks enlisted in this manner in num.
+
+Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
+	 0, the task(s) were queued.
+
+If you want to pass num > 1, then either
+A) you're the only caller of this function and keep track
+   of what you've queued to the LLDD, or
+B) you know what you're doing and have a strategy of
+   retrying.
+
+As opposed to queuing one task at a time (function call),
+batch queuing of tasks, by having num > 1, greatly
+simplifies LLDD code, sequencer code, and _hardware design_,
+and has some performance advantages in certain situations
+(DBMS).
+
+The LLDD advertises if it can take more than one command at
+a time at lldd_execute_task(), by setting the
+lldd_max_execute_num parameter (controlled by "collector"
+module parameter in aic94xx SAS LLDD).
+
+You should leave this to the default 1, unless you know what
+you're doing.
+
+This is a function of the LLDD, to which the SAS layer can
+cater to.
+
+int lldd_queue_size
+	The host adapter's queue size.  This is the maximum
+number of commands the lldd can have pending to domain
+devices on behalf of all upper layers submitting through
+lldd_execute_task().
+
+You really want to set this to something (much) larger than
+1.
+
+This _really_ has absolutely nothing to do with queuing.
+There is no queuing in SAS LLDDs.
+
+struct sas_task {
+	dev -- the device this task is destined to
+	list -- must be initialized (INIT_LIST_HEAD)
+	task_proto -- _one_ of enum sas_proto
+	scatter -- pointer to scatter gather list array
+	num_scatter -- number of elements in scatter
+	total_xfer_len -- total number of bytes expected to be transfered
+	data_dir -- PCI_DMA_...
+	task_done -- callback when the task has finished execution
+};
+
+When an external entity, entity other than the LLDD or the
+SAS Layer, wants to work with a struct domain_device, it
+_must_ call kobject_get() when getting a handle on the
+device and kobject_put() when it is done with the device.
+
+This does two things:
+     A) implements proper kfree() for the device;
+     B) increments/decrements the kref for all players:
+     domain_device
+	all domain_device's ... (if past an expander)
+	    port
+		host adapter
+		     pci device
+			 and up the ladder, etc.
+
+DISCOVERY
+---------
+
+The sysfs tree has the following purposes:
+    a) It shows you the physical layout of the SAS domain at
+       the current time, i.e. how the domain looks in the
+       physical world right now.
+    b) Shows some device parameters _at_discovery_time_.
+
+This is a link to the tree(1) program, very useful in
+viewing the SAS domain:
+ftp://mama.indstate.edu/linux/tree/
+I expect user space applications to actually create a
+graphical interface of this.
+
+That is, the sysfs domain tree doesn't show or keep state if
+you e.g., change the meaning of the READY LED MEANING
+setting, but it does show you the current connection status
+of the domain device.
+
+Keeping internal device state changes is responsibility of
+upper layers (Command set drivers) and user space.
+
+When a device or devices are unplugged from the domain, this
+is reflected in the sysfs tree immediately, and the device(s)
+removed from the system.
+
+The structure domain_device describes any device in the SAS
+domain.  It is completely managed by the SAS layer.  A task
+points to a domain device, this is how the SAS LLDD knows
+where to send the task(s) to.  A SAS LLDD only reads the
+contents of the domain_device structure, but it never creates
+or destroys one.
+
+Expander management from User Space
+-----------------------------------
+
+In each expander directory in sysfs, there is a file called
+"smp_portal".  It is a binary sysfs attribute file, which
+implements an SMP portal (Note: this is *NOT* an SMP port),
+to which user space applications can send SMP requests and
+receive SMP responses.
+
+Functionality is deceptively simple:
+
+1. Build the SMP frame you want to send. The format and layout
+   is described in the SAS spec.  Leave the CRC field equal 0.
+open(2)
+2. Open the expander's SMP portal sysfs file in RW mode.
+write(2)
+3. Write the frame you built in 1.
+read(2)
+4. Read the amount of data you expect to receive for the frame you built.
+   If you receive different amount of data you expected to receive,
+   then there was some kind of error.
+close(2)
+All this process is shown in detail in the function do_smp_func()
+and its callers, in the file "expander_conf.c".
+
+The kernel functionality is implemented in the file
+"sas_expander.c".
+
+The program "expander_conf.c" implements this. It takes one
+argument, the sysfs file name of the SMP portal to the
+expander, and gives expander information, including routing
+tables.
+
+The SMP portal gives you complete control of the expander,
+so please be careful.
diff -urN oldtree/drivers/scsi/sas/expander_conf.c newtree/drivers/scsi/sas/expander_conf.c
--- oldtree/drivers/scsi/sas/expander_conf.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/expander_conf.c	2006-04-01 05:35:45.919489750 -0500
@@ -0,0 +1,463 @@
+/*
+ * Serial Attached SCSI (SAS) Expander communication user space program
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/expander_conf.c#7 $
+ */
+
+/* This is a simple program to show how to communicate with
+ * expander devices in a SAS domain.
+ *
+ * The process is simple:
+ * 1. Build the SMP frame you want to send. The format and layout
+ *    is described in the SAS spec.  Leave the CRC field equal 0.
+ * 2. Open the expander's SMP portal sysfs file in RW mode.
+ * 3. Write the frame you built in 1.
+ * 4. Read the amount of data you expect to receive for the frame you built.
+ *    If you receive different amount of data you expected to receive,
+ *    then there was some kind of error.
+ * All this process is shown in detail in the function do_smp_func()
+ * and its callers, below.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <string.h>
+#include <errno.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define LEFT_FIELD_SIZE 25
+
+#ifdef __LITTLE_ENDIAN
+#define be64_to_cpu(_x)  __bswap_64(*(uint64_t *)(&(_x)))
+#define be32_to_cpu(_x)  __bswap_32(*(uint32_t *)(&(_x)))
+#define be16_to_cpu(_x)  __bswap_16(*(uint16_t *)(&(_x)))
+#define cpu_to_be64(_x)  __bswap_64(*(uint64_t *)(&(_x)))
+#define cpu_to_be32(_x)  __bswap_32(*(uint32_t *)(&(_x)))
+#define cpu_to_be16(_x)  __bswap_16(*(uint16_t *)(&(_x)))
+#else
+#define be64_to_cpu(_x)  (_x)
+#define be32_to_cpu(_x)  (_x)
+#define be16_to_cpu(_x)  (_x)
+#define cpu_to_be64(_x)  (_x)
+#define cpu_to_be32(_x)  (_x)
+#define cpu_to_be16(_x)  (_x)
+#endif
+
+#define SAS_ADDR(_x) ((unsigned long long) be64_to_cpu(*(uint64_t *)(_x)))
+#define SAS_ADDR_SIZE 8
+
+const char *prog;
+
+struct route_table_entry {
+	int      disabled;
+	uint8_t  routed_sas_addr[SAS_ADDR_SIZE];
+};
+
+struct expander {
+	int     num_phys;
+	uint8_t *phy_attr;
+	int     route_indexes;
+};
+
+static int do_smp_func(char *smp_portal_name, void *smp_req, int smp_req_size,
+		       void *smp_resp, int smp_resp_size)
+{
+	int fd;
+	ssize_t res;
+
+	fd = open(smp_portal_name, O_RDWR);
+	if (fd == -1) {
+		printf("%s: opening %s: %s(%d)\n", prog, smp_portal_name,
+		       strerror(errno), errno);
+		return fd;
+	}
+
+	res = write(fd, smp_req, smp_req_size);
+	if (!res) {
+		printf("%s: nothing could be written to %s\n", prog,
+		       smp_portal_name);
+		goto out_err;
+	} else if (res == -1) {
+		printf("%s: writing to %s: %s(%d)\n", prog, smp_portal_name,
+		       strerror(errno), errno);
+		goto out_err;
+	}
+
+	res = read(fd, smp_resp, smp_resp_size);
+	if (!res) {
+		printf("%s: nothing could be read from %s\n", prog,
+		       smp_portal_name);
+		goto out_err;
+	} else if (res == -1) {
+		printf("%s: reading from %s: %s(%d)\n", prog, smp_portal_name,
+		       strerror(errno), errno);
+		goto out_err;
+	}
+	close(fd);
+	return res;
+ out_err:
+	close(fd);
+	return -1;
+}
+
+#define MI_REQ_SIZE   8
+#define MI_RESP_SIZE 64
+
+static unsigned char mi_req[MI_REQ_SIZE] = { 0x40, 1, 0, };
+static unsigned char mi_resp[MI_RESP_SIZE];
+
+#define MI_FIELD_SIZE 20
+#define MI_PRINTS(a, b) printf("%*s %*s\n",LEFT_FIELD_SIZE,a,MI_FIELD_SIZE,b)
+#define MI_PRINTD(a, b) printf("%*s %*u\n",LEFT_FIELD_SIZE,a,MI_FIELD_SIZE,b)
+#define MI_PRINTA(a, b) printf("%*s %0*llx\n",LEFT_FIELD_SIZE,a,MI_FIELD_SIZE,b)
+
+static int mi_expander(char *smp_portal_name, struct expander *ex)
+{
+	int res;
+
+	res = do_smp_func(smp_portal_name, mi_req, MI_REQ_SIZE,
+			  mi_resp, MI_RESP_SIZE);
+	if (res == MI_RESP_SIZE && mi_resp[2] == 0) {
+		char buf[20];
+
+		memcpy(buf, mi_resp+12, 8);
+		buf[8] = 0;
+		MI_PRINTS("Vendor:", buf);
+
+		memcpy(buf, mi_resp+20, 16);
+		buf[16] = 0;
+		MI_PRINTS("Product:", buf);
+
+		memcpy(buf, mi_resp+36, 4);
+		buf[4] = 0;
+		MI_PRINTS("Revision:", buf);
+
+		if (!(mi_resp[8] & 1))
+			return 0;
+
+		memcpy(buf, mi_resp+40, 8);
+		buf[8] = 0;
+		MI_PRINTS("Component:", buf);
+
+		MI_PRINTD("Component ID:", be16_to_cpu(mi_resp[48]));
+		MI_PRINTD("Component revision:", mi_resp[50]);
+	}
+	return 0;
+}
+
+#define RG_REQ_SIZE   8
+#define RG_RESP_SIZE 32
+
+static unsigned char rg_req[RG_REQ_SIZE] = { 0x40, 0, };
+static unsigned char rg_resp[RG_RESP_SIZE];
+
+static int rg_expander(char *smp_portal_name, struct expander *ex)
+{
+	int res;
+
+	res = do_smp_func(smp_portal_name, rg_req, RG_REQ_SIZE, rg_resp,
+			  RG_RESP_SIZE);
+
+	if (res == RG_RESP_SIZE && rg_resp[2] == 0) {
+		MI_PRINTD("Expander Change Count:", be16_to_cpu(rg_resp[4]));
+		MI_PRINTD("Expander Route Indexes:", be16_to_cpu(rg_resp[6]));
+		ex->route_indexes = be16_to_cpu(rg_resp[6]);
+		MI_PRINTD("Number of phys:", rg_resp[9]);
+		ex->num_phys = rg_resp[9];
+		MI_PRINTS("Configuring:", (rg_resp[10] & 2) ? "Yes" : "No");
+		MI_PRINTS("Configurable route table:",
+			  (rg_resp[10] & 1) ? "Yes" : "No");
+		MI_PRINTA("Enclosure Logical Identifier:",
+			  SAS_ADDR(rg_resp+12));
+		ex->phy_attr = malloc(ex->num_phys * sizeof(*ex->phy_attr));
+	}
+	return 0;
+}
+
+#define DISCOVER_REQ_SIZE  16
+#define DISCOVER_RESP_SIZE 56
+
+static unsigned char disc_req[DISCOVER_REQ_SIZE] = {0x40, 0x10, 0, };
+static unsigned char disc_resp[DISCOVER_RESP_SIZE];
+
+#define PHY_EEXIST 0x10
+#define PHY_VACANT 0x16
+
+static const char *attached_dev_type[8] = {
+	[0] = "none",
+	[1] = "end device",
+	[2] = "edge expander",
+	[3] = "fanout expander",
+	[4 ... 7] = "unknown",
+};
+
+static const char *phy_link_rate[16] = {
+	[0] = "unknown",
+	[1] = "disabled",
+	[2] = "phy reset problem",
+	[3] = "spinup hold",
+	[4] = "port selector",
+	[5 ... 7] = "unknown",
+	[8] = "G1 (1,5 Gb/s)",
+	[9] = "G2 (3 GB/s)",
+	[10 ... 15] = "Unknown",
+};
+
+static const char *proto_table[8] = {
+	"",
+	"SMP", "STP", "STP|SMP", "SSP",
+	"SSP|SMP", "SSP|STP", "SSP|STP|SMP",
+};
+
+#define DIRECT_ROUTING      0
+#define SUBTRACTIVE_ROUTING 1
+#define TABLE_ROUTING       2
+
+static const char *routing_attr[8] = {
+	[DIRECT_ROUTING] = "D",
+	[SUBTRACTIVE_ROUTING] = "S",
+	[TABLE_ROUTING] = "T",
+	[3 ... 7] = "x",
+};
+
+static const char *conn_type[0x80] = {
+	[0] = "No information",
+	[1] = "SAS external receptacle (i.e., SFF-8470)(see SAS-1.1)",
+	[2] = "SAS external compact receptacle (i.e., SFF-8088)(see SAS-1.1)",
+	[3 ... 0x0f ] = "External connector",
+	[0x10] = "SAS internal wide plug (i.e., SFF-8484)(see SAS-1.1)",
+	[0x11] = "SAS internal compact wide plug (i.e., SFF-8087)(see SAS-1.1)",
+	[0x12 ... 0x1f] = "Internal wide connector",
+	[0x20] = "SAS backplane receptacle (i.e., SFF-8482)(see SAS-1.1)",
+	[0x21] = "SATA-style host plug (i.e., ATA/ATAPI-7 V3)(see SAS-1.1)",
+	[0x22] = "SAS plug (i.e., SFF-8482)(see SAS-1.1)",
+	[0x23] = "SATA device plug (i.e., ATA/ATAPI-7 V3)(see SAS-1.1)",
+	[0x24 ... 0x2f] = "Internal connector to end device",
+	[0x30 ... 0x6f] = "Unknown\n",
+	[0x70 ... 0x7f] = "Vendor specific",
+};
+
+static int discover_phy(char *smp_portal_name, int phy_id, struct expander *ex)
+{
+	int res;
+	const char *dev_str;
+
+	disc_req[9] = phy_id;
+
+	res = do_smp_func(smp_portal_name, disc_req, DISCOVER_REQ_SIZE,
+			  disc_resp, DISCOVER_RESP_SIZE);
+
+	if (res != DISCOVER_RESP_SIZE) {
+		printf("%s: error disovering phy %d\n", prog, phy_id);
+		goto out;
+	}
+	switch (disc_resp[2]) {
+	case PHY_VACANT:
+		printf("phy%02d: vacant\n", phy_id);
+		goto out; break;
+	case PHY_EEXIST:
+		printf("phy%02d doesn't exist\n", phy_id);
+		goto out; break;
+	case 0:
+		break;
+	default:
+		printf("phy%02d SMP function result: 0x%x\n",
+		       phy_id, disc_resp[2]);
+		goto out;
+	}
+
+	printf("Phy%02d:%s    attached: %016llx:%02d    chg count:%02d\n",
+	       phy_id, routing_attr[disc_resp[44] & 0x0F],
+	       SAS_ADDR(disc_resp+24), disc_resp[32], disc_resp[42]);
+
+	if (ex->phy_attr)
+		ex->phy_attr[phy_id] = disc_resp[44] & 0x0F;
+
+	if (disc_resp[14] & 1)
+		dev_str = "SATA Host";
+	else if (disc_resp[15] & 0x80)
+		dev_str = "SATA Port Selector";
+	else if (disc_resp[15] & 1)
+		dev_str = "SATA device";
+	else
+		dev_str = attached_dev_type[(disc_resp[12] & 0x70) >> 4];
+	printf(" Attached device: %15s    Link rate: %15s\n",
+	       dev_str, phy_link_rate[disc_resp[13] & 0xf]);
+
+	printf(" Tproto: %15s    Iproto: %15s\n",
+	       proto_table[(disc_resp[15] & 0xe) >> 1],
+	       proto_table[(disc_resp[14] & 0xe) >> 1]);
+
+	printf(" Programmed MIN-MAX linkrate: %s - %s\n",
+	       phy_link_rate[(disc_resp[40] & 0xF0)>>4],
+	       phy_link_rate[(disc_resp[41] & 0xF0)>>4]);
+
+	printf(" Hardware   MIN-MAX linkrate: %s - %s\n",
+	       phy_link_rate[(disc_resp[40] & 0x0F)],
+	       phy_link_rate[(disc_resp[41] & 0x0F)]);
+
+	printf(" %s phy\n", (disc_resp[43] & 0x80) ? "Virtual" : "Physical");
+	printf(" Partial pathway timeout value: %d microseconds\n",
+	       disc_resp[43] & 0x0F);
+
+	printf(" Connector type: %s\n", conn_type[disc_resp[45] & 0x7F]);
+	printf(" Connector element index: %d\n", disc_resp[46]);
+	printf(" Connector physical link: %d\n", disc_resp[47]);
+out:
+	return 0;
+}
+
+#define RPEL_REQ_SIZE  16
+#define RPEL_RESP_SIZE 32
+
+static unsigned char rpel_req[RPEL_REQ_SIZE] = { 0x40, 0x11, 0, };
+static unsigned char rpel_resp[RPEL_RESP_SIZE];
+
+static int report_phy_error_log(char *smp_portal_name, int phy_id)
+{
+	int res;
+
+	rpel_req[9] = phy_id;
+
+	res = do_smp_func(smp_portal_name, rpel_req, RPEL_REQ_SIZE,
+			  rpel_resp, RPEL_RESP_SIZE);
+	if (res != RPEL_RESP_SIZE) {
+		printf("%s: error reading error log for phy %d (%d)\n",
+		       prog, phy_id, res);
+		goto out;
+	}
+	MI_PRINTD(" Invalid DW count:", be32_to_cpu(rpel_resp[12]));
+	MI_PRINTD(" RD error count:", be32_to_cpu(rpel_resp[16]));
+	MI_PRINTD(" DW sync loss count:", be32_to_cpu(rpel_resp[20]));
+	MI_PRINTD(" Reset problem count:", be32_to_cpu(rpel_resp[24]));
+out:
+	return 0;
+}
+
+#define RRI_REQ_SIZE  16
+#define RRI_RESP_SIZE 44
+
+static unsigned char rri_req[RRI_REQ_SIZE] = { 0x40, 0x13, 0, };
+static unsigned char rri_resp[RRI_RESP_SIZE];
+
+static int show_routing_table(char *smp_portal_name, int phy_id,
+			      struct expander *ex)
+{
+	struct route_table_entry *rt;
+	int res, i, last_non_zero = -1;
+
+	if (!ex->phy_attr || ex->phy_attr[phy_id] != TABLE_ROUTING)
+		return 0;
+
+	rt = malloc(sizeof(struct route_table_entry)*ex->route_indexes);
+	if (!rt)
+		return 0;
+
+	rri_req[9] = phy_id;
+
+	for (i = 0; i < ex->route_indexes; i++) {
+		*(uint16_t *)(rri_req+6) = cpu_to_be16(i);
+		res = do_smp_func(smp_portal_name, rri_req, RRI_REQ_SIZE,
+				  rri_resp, RRI_RESP_SIZE);
+		if (res != RRI_RESP_SIZE) {
+			printf("Error getting phy %d route index %d (%d)\n",
+			       phy_id, i, res);
+			goto out;
+		}
+		if (rri_resp[2] != 0)
+			break;
+		if (be16_to_cpu(rri_resp[6]) != i) {
+			printf("Expander FW error for phy %d index %d\n",
+			       phy_id, i);
+			goto out;
+		}
+		rt[i].disabled = rri_resp[12] & 0x80 ? 1 : 0;
+		memcpy(rt[i].routed_sas_addr, rri_resp+16, SAS_ADDR_SIZE);
+		if (rt[i].routed_sas_addr[0])
+			last_non_zero = i;
+	}
+	printf(" Routing Table\n");
+	if (last_non_zero == -1)
+		printf("  Empty (all zero)\n");
+	else {
+		for (i = 0; i <= last_non_zero; i++)
+			printf("  %02d %8s %016llx\n",
+			       i, rt[i].disabled ? "disabled" : "enabled",
+			       SAS_ADDR(rt[i].routed_sas_addr));
+	}
+out:
+	free(rt);
+	return 0;
+}
+
+static int discover_expander(char *smp_portal_name, struct expander *ex)
+{
+	int i;
+
+	for (i = 0; i < ex->num_phys; i++) {
+		printf("\n");
+		discover_phy(smp_portal_name, i, ex);
+		report_phy_error_log(smp_portal_name, i);
+		show_routing_table(smp_portal_name, i, ex);
+	}
+
+	return 0;
+}
+
+static void print_info(void)
+{
+	printf("%s <smp portal file>\n", prog);
+	printf("\tWhere <smp portal file> is the binary attribute file of the"
+	       "\n\texpander device in sysfs.\n");
+}
+
+int main(int argc, char *argv[])
+{
+	prog = strrchr(argv[0], '/');
+	if (prog)
+		prog++;
+	else
+		prog = argv[0];
+
+	if (argc < 2) {
+		print_info();
+		return 0;
+	} else {
+		struct expander ex;
+
+		memset(&ex, 0, sizeof(ex));
+
+		mi_expander(argv[1], &ex);
+		rg_expander(argv[1], &ex);
+		discover_expander(argv[1], &ex);
+		if (ex.phy_attr)
+			free(ex.phy_attr);
+	}
+	return 0;
+}
diff -urN oldtree/drivers/scsi/sas/sas_common.c newtree/drivers/scsi/sas/sas_common.c
--- oldtree/drivers/scsi/sas/sas_common.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_common.c	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,115 @@
+/*
+ * Serial Attached SCSI (SAS) class common functions
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_common.c#9 $
+ */
+
+#include <scsi/sas/sas_class.h>
+#include "sas_internal.h"
+
+int sas_show_class(enum sas_class class, char *buf)
+{
+	static const char *class_str[] = {
+		[SAS] = "SAS",
+		[EXPANDER] = "EXPANDER",
+	};
+	return sprintf(buf, "%s\n", class_str[class]);
+}
+
+int sas_show_proto(enum sas_proto proto, char *page)
+{
+	static const char *proto_str[] = {
+		[SATA_PROTO] = "SATA",
+		[SAS_PROTO_SMP] = "SMP",
+		[SAS_PROTO_STP] = "STP",
+		[SAS_PROTO_SSP] = "SSP",
+	};
+	int  v;
+	char *buf = page;
+
+	for (v = 1; proto != 0 && v <= SAS_PROTO_SSP; v <<= 1) {
+		if (v & proto) {
+			buf += sprintf(buf, "%s", proto_str[v]);
+
+			if (proto & ~((v<<1)-1))
+				buf += sprintf(buf, "|");
+			else
+				buf += sprintf(buf, "\n");
+		}
+	}
+	return buf-page;
+}
+
+int sas_show_linkrate(enum sas_phy_linkrate linkrate, char *page)
+{
+	static const char *phy_linkrate_str[] = {
+		[PHY_LINKRATE_NONE] = "",
+		[PHY_DISABLED] = "disabled",
+		[PHY_RESET_PROBLEM] = "phy reset problem",
+		[PHY_SPINUP_HOLD] = "phy spinup hold",
+		[PHY_PORT_SELECTOR] = "phy port selector",
+		[PHY_LINKRATE_1_5] = "1,5 GB/s",
+		[PHY_LINKRATE_3]  = "3,0 GB/s",
+		[PHY_LINKRATE_6] = "6,0 GB/s",
+	};
+	return sprintf(page, "%s\n", phy_linkrate_str[linkrate]);
+}
+
+int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf)
+{
+	switch (oob_mode) {
+	case OOB_NOT_CONNECTED:
+		return sprintf(buf, "%s", "");
+		break;
+	case SATA_OOB_MODE:
+		return sprintf(buf, "%s\n", "SATA");
+		break;
+	case SAS_OOB_MODE:
+		return sprintf(buf, "%s\n", "SAS");
+		break;
+	}
+	return 0;
+}
+
+void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
+{
+	const u32 poly = 0x00DB2777;
+	u32 	r = 0;
+	int 	i;
+
+	for (i = 0; i < 8; i++) {
+		int b;
+		for (b = 7; b >= 0; b--) {
+			r <<= 1;
+			if ((1 << b) & sas_addr[i]) {
+				if (!(r & 0x01000000))
+					r ^= poly;
+			} else if (r & 0x01000000)
+				r ^= poly;
+		}
+	}
+
+	hashed[0] = (r >> 16) & 0xFF;
+	hashed[1] = (r >> 8) & 0xFF ;
+	hashed[2] = r & 0xFF;
+}
diff -urN oldtree/drivers/scsi/sas/sas_discover.c newtree/drivers/scsi/sas/sas_discover.c
--- oldtree/drivers/scsi/sas/sas_discover.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_discover.c	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,1599 @@
+/*
+ * Serial Attached SCSI (SAS) Discover process
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_discover.c#140 $
+ */
+
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include "sas_internal.h"
+#include <scsi/sas/sas_task.h>
+#include <scsi/sas/sas_discover.h>
+
+/* ---------- Domain device attributes ---------- */
+
+ssize_t dev_show_type(struct domain_device *dev, char *page)
+{
+	static const char *dev_type[] = {
+		"no device",
+		"end device",
+		"edge expander",
+		"fanout expander",
+		"host adapter",
+		"sata device",
+		"sata port multiplier",
+		"sata port multiplier port",
+	};
+	return sprintf(page, "%s\n", dev_type[dev->dev_type]);
+}
+
+ssize_t dev_show_iproto(struct domain_device *dev, char *page)
+{
+	return sas_show_proto(dev->iproto, page);
+}
+
+ssize_t dev_show_tproto(struct domain_device *dev, char *page)
+{
+	return sas_show_proto(dev->tproto, page);
+}
+
+ssize_t dev_show_sas_addr(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%llx\n", SAS_ADDR(dev->sas_addr));
+}
+
+ssize_t dev_show_linkrate(struct domain_device *dev, char *page)
+{
+	return sas_show_linkrate(dev->linkrate, page);
+}
+
+ssize_t dev_show_min_linkrate(struct domain_device *dev, char *page)
+{
+	return sas_show_linkrate(dev->min_linkrate, page);
+}
+
+ssize_t dev_show_max_linkrate(struct domain_device *dev, char *page)
+{
+	return sas_show_linkrate(dev->max_linkrate, page);
+}
+
+ssize_t dev_show_pathways(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->pathways);
+}
+
+/* ---------- SATA specific sysfs ---------- */
+
+static ssize_t sata_show_command_set(struct domain_device *dev, char *page)
+{
+	static const char *cs[] = {
+		"ATA",
+		"ATAPI",
+	};
+	return sprintf(page, "%s\n", cs[dev->sata_dev.command_set]);
+}
+
+static ssize_t sata_show_rps_resp(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+	if ((dev->tproto & SAS_PROTO_STP) &&
+	    dev->sata_dev.rps_resp.frame_type == SMP_RESPONSE &&
+	    dev->sata_dev.rps_resp.function == SMP_REPORT_PHY_SATA &&
+	    dev->sata_dev.rps_resp.result == SMP_RESP_FUNC_ACC) {
+		int i = 0;
+		u8 *p = (u8 *) &dev->sata_dev.rps_resp;
+		for (i = 0; i < sizeof(struct smp_resp); i+=4, p+=4) {
+			buf += sprintf(buf, "%02x %02x %02x %02x\n",
+				       *(p+0), *(p+1), *(p+2), *(p+3));
+		}
+	}
+	return buf-page;
+}
+
+static inline int show_chars(__le16 *p, int start, int words, char *page)
+{
+	int i;
+	char *buf = page;
+
+	for (i = start; i < start+words; i++) {
+		u16  s = le16_to_cpu(p[i]);
+		char a = (s&0xFF00)>>8;
+		char b = s&0x00FF;
+
+		if (a == 0)
+			break;
+		buf += sprintf(buf, "%c", a);
+		if (b == 0)
+			break;
+		buf += sprintf(buf, "%c", b);
+	}
+	return buf-page;
+}
+
+static ssize_t sata_show_serial_number(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+	__le16 *identify_x = NULL;
+
+	if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+		identify_x = dev->sata_dev.identify_device;
+	else
+		identify_x = dev->sata_dev.identify_packet_device;
+
+	if (identify_x &&
+	    (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT)) {
+		buf += show_chars(identify_x, 10, 10, buf);
+		buf += sprintf(buf, "\n");
+	}
+	return buf-page;
+}
+
+static ssize_t sata_show_firmware_rev(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+	__le16 *identify_x = NULL;
+
+	if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+		identify_x = dev->sata_dev.identify_device;
+	else
+		identify_x = dev->sata_dev.identify_packet_device;
+
+	if (identify_x &&
+	    (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT)) {
+		buf += show_chars(identify_x, 23, 4, buf);
+		buf += sprintf(buf, "\n");
+	}
+	return buf-page;
+}
+
+static ssize_t sata_show_model_number(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+	__le16 *identify_x = NULL;
+
+	if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+		identify_x = dev->sata_dev.identify_device;
+	else
+		identify_x = dev->sata_dev.identify_packet_device;
+
+	if (identify_x &&
+	    (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT)) {
+		buf += show_chars(identify_x, 27, 20, buf);
+		buf += sprintf(buf, "\n");
+	}
+	return buf-page;
+}
+
+static ssize_t sata_show_identify_device(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+
+	if (dev->sata_dev.identify_device &&
+	    (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT)) {
+		__le16 *p = dev->sata_dev.identify_device;
+		int i;
+
+		for (i = 0; i < 16; i++) {
+			int k;
+			for (k = 0; k < 16; k++)
+				buf += sprintf(buf, "%04x%s",
+					      le16_to_cpu(p[i*16+k]),
+					      k==15 ? "\n" : " ");
+		}
+	}
+	return buf-page;
+}
+
+static ssize_t sata_show_identify_packet(struct domain_device *dev, char *page)
+{
+	char *buf = page;
+
+	if (dev->sata_dev.identify_packet_device &&
+	    (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT)) {
+		__le16 *p = dev->sata_dev.identify_packet_device;
+		int i;
+
+		for (i = 0; i < 16; i++) {
+			int k;
+			for (k = 0; k < 16; k++)
+				buf += sprintf(buf, "%04x%s",
+					      le16_to_cpu(p[i*16+k]),
+					      k==15 ? "\n" : " ");
+		}
+	}
+
+	return buf-page;
+}
+
+static ssize_t sata_show_port_no(struct domain_device *dev, char *page)
+{
+	int res = 0;
+
+	if (dev->dev_type == SATA_PM || dev->dev_type == SATA_PM_PORT)
+		res = sprintf(page, "%02Xh\n", dev->sata_dev.port_no);
+	return res;
+}
+
+/* ---------- SAS end device specific ---------- */
+
+static ssize_t sas_show_rled_meaning(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->end_dev.ready_led_meaning);
+}
+
+static ssize_t sas_show_itnl_timeout(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "0x%04x\n", dev->end_dev.itnl_timeout);
+}
+
+static ssize_t sas_show_iresp_timeout(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "0x%04x\n", dev->end_dev.iresp_timeout);
+}
+
+static ssize_t sas_show_rl_wlun(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->end_dev.rl_wlun);
+}
+
+/* ---------- LU specific ---------- */
+
+static ssize_t lu_show_lun(struct LU *lu, char *page)
+{
+	return sprintf(page, "%016llx\n", SAS_ADDR(lu->LUN));
+}
+
+static ssize_t lu_show_inq(struct LU *lu, char *_page)
+{
+	int i;
+	char *buf = _page;
+	if (lu->inquiry_valid_data_len <= 0)
+		return 0;
+	for (i = 0; i < lu->inquiry_valid_data_len; i += 4) {
+		buf += sprintf(buf, "%02x %02x %02x %02x\n",
+			       lu->inquiry_data[i+0], lu->inquiry_data[i+1],
+			       lu->inquiry_data[i+2], lu->inquiry_data[i+3]);
+	}
+	return buf-_page;
+}
+
+static ssize_t lu_show_tm_type(struct LU *lu, char *page)
+{
+	static const char *tm_type[] = {
+		"none",
+		"full",
+		"basic",
+	};
+	return sprintf(page, "%s\n", tm_type[lu->tm_type]);
+}
+
+static ssize_t lu_show_channel(struct LU *lu, char *page)
+{
+	if (lu->uldd_dev)
+		return sprintf(page, "%d\n", lu->map.channel);
+	return 0;
+}
+
+static ssize_t lu_show_id(struct LU *lu, char *page)
+{
+	if (lu->uldd_dev)
+		return sprintf(page, "%d\n", lu->map.id);
+	return 0;
+}
+
+/* ---------- Sysfs attribute implementation ---------- */
+
+struct lu_dev_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct LU *lu, char *);
+	ssize_t (*store)(struct LU *lu, const char *, size_t);
+};
+
+static struct lu_dev_attribute lu_attrs[] = {
+	__ATTR(lun, 0444, lu_show_lun, NULL),
+	__ATTR(inquiry_data, 0444, lu_show_inq, NULL),
+	__ATTR(channel, 0444, lu_show_channel, NULL),
+	__ATTR(id, 0444, lu_show_id, NULL),
+	__ATTR(task_management, 0444, lu_show_tm_type, NULL),
+	__ATTR_NULL,
+};
+
+static struct domain_dev_attribute dev_attrs[] = {
+	__ATTR(dev_type, 0444, dev_show_type, NULL),
+	__ATTR(iproto, 0444, dev_show_iproto, NULL),
+	__ATTR(tproto, 0444, dev_show_tproto, NULL),
+	__ATTR(sas_addr, 0444, dev_show_sas_addr, NULL),
+	__ATTR(ready_led_meaning, 0444, sas_show_rled_meaning, NULL),
+	__ATTR(itnl_timeout, 0444, sas_show_itnl_timeout, NULL),
+	__ATTR(iresp_timeout, 0444, sas_show_iresp_timeout, NULL),
+	__ATTR(rl_wlun, 0444, sas_show_rl_wlun, NULL),
+	__ATTR(linkrate, 0444, dev_show_linkrate, NULL),
+	__ATTR(min_linkrate, 0444, dev_show_min_linkrate, NULL),
+	__ATTR(max_linkrate, 0444, dev_show_max_linkrate, NULL),
+	__ATTR(pathways, 0444, dev_show_pathways, NULL),
+	__ATTR_NULL,
+};
+
+static struct domain_dev_attribute sata_attrs[] = {
+	__ATTR(dev_type, 0444, dev_show_type, NULL),
+	__ATTR(iproto, 0444, dev_show_iproto, NULL),
+	__ATTR(tproto, 0444, dev_show_tproto, NULL),
+	__ATTR(sas_addr, 0444, dev_show_sas_addr, NULL),
+	__ATTR(linkrate, 0444, dev_show_linkrate, NULL),
+	__ATTR(min_linkrate, 0444, dev_show_min_linkrate, NULL),
+	__ATTR(max_linkrate, 0444, dev_show_max_linkrate, NULL),
+	__ATTR(command_set, 0444, sata_show_command_set, NULL),
+	__ATTR(report_phy_sata_resp, 0444, sata_show_rps_resp, NULL),
+	__ATTR(serial_number, 0444, sata_show_serial_number, NULL),
+	__ATTR(firmware_rev, 0444, sata_show_firmware_rev, NULL),
+	__ATTR(model_number, 0444, sata_show_model_number, NULL),
+	__ATTR(identify_device, 0444, sata_show_identify_device, NULL),
+	__ATTR(identify_packet_device, 0444, sata_show_identify_packet, NULL),
+	__ATTR(port_no, 0444, sata_show_port_no, NULL),
+	__ATTR_NULL,
+};
+
+static void end_dev_release(struct kobject *obj)
+{
+	struct domain_device *dev = to_dom_device(obj);
+	BUG_ON(!list_empty(&dev->end_dev.LU_list));
+	SAS_DPRINTK("freeing dev %llx\n", SAS_ADDR(dev->sas_addr));
+	kfree(dev);
+}
+
+static void sata_dev_release(struct kobject *obj)
+{
+	struct domain_device *dev = to_dom_device(obj);
+
+	SAS_DPRINTK("freeing SATA dev %llx\n", SAS_ADDR(dev->sas_addr));
+	/* XXX Hint: unregister this SATA device with SATL.
+	if (dev->sata_dev->lu)
+		sas_satl_unregister_dev(dev);
+	*/
+	if (dev->sata_dev.identify_device) {
+		void *p = dev->sata_dev.identify_device;
+		mb();
+		dev->sata_dev.identify_device = NULL;
+		kfree(p);
+	}
+	if (dev->sata_dev.identify_packet_device) {
+		void *p = dev->sata_dev.identify_packet_device;
+		mb();
+		dev->sata_dev.identify_packet_device = NULL;
+		kfree(p);
+	}
+	kfree(dev);
+}
+
+static void sas_lu_release(struct kobject *obj)
+{
+	struct LU *lu = to_lu_device(obj);
+	SAS_DPRINTK("freeing LUN %016llx\n", SAS_ADDR(lu->LUN));
+	sas_release_scsi_id(lu->parent->port, lu->map.id);
+	kfree(lu);
+}
+
+static ssize_t dev_show_attr(struct kobject *kobj, struct attribute *attr,
+			     char *page)
+{
+	ssize_t ret = 0;
+	struct domain_device *dev = to_dom_device(kobj);
+	struct domain_dev_attribute *dev_attr = to_dev_attr(attr);
+
+	if (dev_attr->show)
+		ret = dev_attr->show(dev, page);
+	return ret;
+}
+
+static ssize_t lu_show_attr(struct kobject *obj, struct attribute *attr,
+			    char *page)
+{
+	ssize_t ret = 0;
+	struct LU *lu = to_lu_device(obj);
+	struct lu_dev_attribute *lu_attr = to_lu_attr(attr);
+
+	if (lu_attr->show)
+		ret = lu_attr->show(lu, page);
+	return ret;
+}
+
+struct sysfs_ops dev_sysfs_ops = {
+	.show = dev_show_attr,
+};
+static struct sysfs_ops lu_sysfs_ops = {
+	.show = lu_show_attr,
+};
+
+static struct attribute *end_dev_attrs[ARRAY_SIZE(dev_attrs)];
+static struct attribute *sata_dev_attrs[ARRAY_SIZE(sata_attrs)];
+static struct attribute *lu_dev_attrs[ARRAY_SIZE(lu_attrs)];
+
+static struct kobj_type end_dev_ktype = {
+	.release = end_dev_release,
+	.sysfs_ops = &dev_sysfs_ops,
+	.default_attrs = end_dev_attrs,
+};
+static struct kobj_type sata_dev_ktype = {
+	.release = sata_dev_release,
+	.sysfs_ops = &dev_sysfs_ops,
+	.default_attrs = sata_dev_attrs,
+};
+static struct kobj_type lu_dev_ktype = {
+	.release = sas_lu_release,
+	.sysfs_ops = &lu_sysfs_ops,
+	.default_attrs = lu_dev_attrs,
+};
+
+struct kobj_type *dev_ktype[] = {
+	NULL,
+	&end_dev_ktype,
+	&ex_dev_ktype,
+	&ex_dev_ktype,
+	NULL,
+	&sata_dev_ktype,
+	NULL,
+	NULL,
+};
+
+/* ---------- Basic task processing for discovery purposes ---------- */
+
+static void sas_task_timedout(unsigned long _task)
+{
+	struct sas_task *task = (void *) _task;
+	unsigned long flags;
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+	if (!del_timer(&task->timer))
+		return;
+	complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+			    int pci_dma_dir)
+{
+	int res = 0;
+	struct scatterlist *scatter = NULL;
+	struct task_status_struct *ts = &task->task_status;
+	int num_scatter = 0;
+	int retries = 0;
+
+	if (pci_dma_dir != PCI_DMA_NONE) {
+		scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+		if (!scatter)
+			goto out;
+
+		sg_init_one(scatter, buffer, size);
+		num_scatter = 1;
+	}
+
+	task->task_proto = task->dev->tproto;
+	task->scatter = scatter;
+	task->num_scatter = num_scatter;
+	task->total_xfer_len = size;
+	task->data_dir = pci_dma_dir;
+	task->task_done = sas_disc_task_done;
+
+	for (retries = 0; retries < 5; retries++) {
+		task->task_state_flags = SAS_TASK_STATE_PENDING;
+		init_completion(&task->completion);
+
+		task->timer.data = (unsigned long) task;
+		task->timer.function = sas_task_timedout;
+		task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+		add_timer(&task->timer);
+
+		res = task->dev->port->ha->lldd_execute_task(task, 1,
+							     GFP_KERNEL);
+		if (res) {
+			del_timer(&task->timer);
+			SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+				    res);
+			goto ex_err;
+		}
+		wait_for_completion(&task->completion);
+		res = -ETASK;
+		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+			int res2;
+			SAS_DPRINTK("task aborted, flags:0x%x\n",
+				    task->task_state_flags);
+			res2 = task->dev->port->ha->lldd_abort_task(task);
+			SAS_DPRINTK("came back from abort task\n");
+			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+				if (res2 == TMF_RESP_FUNC_COMPLETE)
+					continue; /* Retry the task */
+				else
+					goto ex_err;
+			}
+		}
+		if (task->task_status.stat == SAM_BUSY ||
+			   task->task_status.stat == SAM_TASK_SET_FULL ||
+			   task->task_status.stat == SAS_QUEUE_FULL) {
+			SAS_DPRINTK("task: q busy, sleeping...\n");
+			schedule_timeout_interruptible(HZ);
+		} else if (task->task_status.stat == SAM_CHECK_COND) {
+			struct scsi_sense_hdr shdr;
+
+			if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+						  &shdr)) {
+				SAS_DPRINTK("couldn't normalize sense\n");
+				continue;
+			}
+			if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+			    (shdr.sense_key == 2 && shdr.asc == 4 &&
+			     shdr.ascq == 1)) {
+				SAS_DPRINTK("device %016llx LUN: %016llx "
+					    "powering up or not ready yet, "
+					    "sleeping...\n",
+					    SAS_ADDR(task->dev->sas_addr),
+					    SAS_ADDR(task->ssp_task.LUN));
+
+				schedule_timeout_interruptible(5*HZ);
+			} else if (shdr.sense_key == 1) {
+				res = 0;
+				break;
+			} else if (shdr.sense_key == 5) {
+				break;
+			} else {
+				SAS_DPRINTK("dev %016llx LUN: %016llx "
+					    "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+					    "\n",
+					    SAS_ADDR(task->dev->sas_addr),
+					    SAS_ADDR(task->ssp_task.LUN),
+					    shdr.sense_key,
+					    shdr.asc, shdr.ascq);
+			}
+		} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+			   task->task_status.stat != SAM_GOOD) {
+			SAS_DPRINTK("task finished with resp:0x%x, "
+				    "stat:0x%x\n",
+				    task->task_status.resp,
+				    task->task_status.stat);
+			goto ex_err;
+		} else {
+			res = 0;
+			break;
+		}
+	}
+ex_err:
+	if (pci_dma_dir != PCI_DMA_NONE)
+		kfree(scatter);
+out:
+	return res;
+}
+
+/* ---------- Domain device discovery ---------- */
+
+/**
+ * sas_get_port_device -- Discover devices which caused port creation
+ * @port: pointer to struct sas_port of interest
+ *
+ * Devices directly attached to a HA port, have no parent.  This is
+ * how we know they are (domain) "root" devices.  All other devices
+ * do, and should have their "parent" pointer set appropriately as
+ * soon as a child device is discovered.
+ */
+static int sas_get_port_device(struct sas_port *port)
+{
+	unsigned long flags;
+	struct sas_phy *phy;
+	struct domain_device *dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&port->phy_list_lock, flags);
+	if (list_empty(&port->phy_list)) {
+		spin_unlock_irqrestore(&port->phy_list_lock, flags);
+		kfree(dev);
+		return -ENODEV;
+	}
+	phy = container_of(port->phy_list.next, struct sas_phy, port_phy_el);
+	spin_lock(&phy->frame_rcvd_lock);
+	memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
+					     (size_t)phy->frame_rcvd_size));
+	spin_unlock(&phy->frame_rcvd_lock);
+	spin_unlock_irqrestore(&port->phy_list_lock, flags);
+
+	if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
+		struct dev_to_host_fis *fis =
+			(struct dev_to_host_fis *) dev->frame_rcvd;
+		if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
+		    fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
+		    && (fis->device & ~0x10) == 0)
+			dev->dev_type = SATA_PM;
+		else
+			dev->dev_type = SATA_DEV;
+		dev->tproto = SATA_PROTO;
+	} else {
+		struct sas_identify_frame *id =
+			(struct sas_identify_frame *) dev->frame_rcvd;
+		dev->dev_type = id->dev_type;
+		dev->iproto = id->initiator_bits;
+		dev->tproto = id->target_bits;
+	}
+
+	sas_init_dev(dev);
+
+	memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
+	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+	port->port_dev = dev;
+	dev->port = port;
+	dev->linkrate = port->linkrate;
+	dev->min_linkrate = port->linkrate;
+	dev->max_linkrate = port->linkrate;
+	dev->pathways = port->num_phys;
+	memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
+	memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
+	memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
+	port->disc.max_level = 0;
+
+	return 0;
+}
+
+/* ---------- Discover and Revalidate ---------- */
+
+/* ---------- SATA ---------- */
+
+static inline void sas_get_ata_command_set(struct domain_device *dev)
+{
+	struct dev_to_host_fis *fis =
+		(struct dev_to_host_fis *) dev->frame_rcvd;
+
+	if ((fis->sector_count == 1 && /* ATA */
+	     fis->lbal         == 1 &&
+	     fis->lbam         == 0 &&
+	     fis->lbah         == 0 &&
+	     fis->device       == 0)
+	    ||
+	    (fis->sector_count == 0 && /* CE-ATA (mATA) */
+	     fis->lbal         == 0 &&
+	     fis->lbam         == 0xCE &&
+	     fis->lbah         == 0xAA &&
+	     (fis->device & ~0x10) == 0))
+
+		dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+	else if ((fis->interrupt_reason == 1 &&	/* ATAPI */
+		  fis->lbal             == 1 &&
+		  fis->byte_count_low   == 0x14 &&
+		  fis->byte_count_high  == 0xEB &&
+		  (fis->device & ~0x10) == 0))
+
+		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+	else if ((fis->sector_count == 1 && /* SEMB */
+		  fis->lbal         == 1 &&
+		  fis->lbam         == 0x3C &&
+		  fis->lbah         == 0xC3 &&
+		  fis->device       == 0)
+		||
+		 (fis->interrupt_reason == 1 &&	/* SATA PM */
+		  fis->lbal             == 1 &&
+		  fis->byte_count_low   == 0x69 &&
+		  fis->byte_count_high  == 0x96 &&
+		  (fis->device & ~0x10) == 0))
+
+		/* Treat it as a superset? */
+		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+			     u8 features, void *buffer, int size,
+			     int pci_dma_dir)
+{
+	int res = 0;
+	struct sas_task *task;
+	struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+		&dev->frame_rcvd[0];
+
+	res = -ENOMEM;
+	task = sas_alloc_task(GFP_KERNEL);
+	if (!task)
+		goto out;
+
+	task->dev = dev;
+
+	task->ata_task.fis.command = command;
+	task->ata_task.fis.features = features;
+	task->ata_task.fis.device = d2h_fis->device;
+	task->ata_task.retry_count = 1;
+
+	res = sas_execute_task(task, buffer, size, pci_dma_dir);
+
+	sas_free_task(task);
+out:
+	return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+	unsigned long flags;
+	struct sas_port *port = dev->port;
+	struct sas_phy  *phy;
+
+	BUG_ON(dev->parent);
+
+	memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+	spin_lock_irqsave(&port->phy_list_lock, flags);
+	list_for_each_entry(phy, &port->phy_list, port_phy_el)
+		memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+	spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV         0xEC
+#define ATA_IDENTIFY_PACKET_DEV  0xA1
+#define ATA_SET_FEATURES         0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it.  Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+	int     res;
+	__le16  *identify_x;
+	u8      command;
+
+	identify_x = kzalloc(512, GFP_KERNEL);
+	if (!identify_x)
+		return -ENOMEM;
+
+	if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+		dev->sata_dev.identify_device = identify_x;
+		command = ATA_IDENTIFY_DEV;
+	} else {
+		dev->sata_dev.identify_packet_device = identify_x;
+		command = ATA_IDENTIFY_PACKET_DEV;
+	}
+
+	res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+				PCI_DMA_FROMDEVICE);
+	if (res)
+		goto out_err;
+
+	/* lives on the media? */
+	if (le16_to_cpu(identify_x[0]) & 4) {
+		/* incomplete response */
+		SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+			    "dev %llx\n", SAS_ADDR(dev->sas_addr));
+		if (!le16_to_cpu(identify_x[83] & (1<<6)))
+			goto cont1;
+		res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+					ATA_FEATURE_PUP_STBY_SPIN_UP,
+					NULL, 0, PCI_DMA_NONE);
+		if (res)
+			goto cont1;
+
+		schedule_timeout_interruptible(5*HZ); /* More time? */
+		res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+					PCI_DMA_FROMDEVICE);
+		if (res)
+			goto out_err;
+	}
+cont1:
+	/* Get WWN */
+	if (dev->port->oob_mode != SATA_OOB_MODE) {
+		memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+		       SAS_ADDR_SIZE);
+	} else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+		   (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+		   == 0x5000) {
+		int i;
+
+		for (i = 0; i < 4; i++) {
+			dev->sas_addr[2*i] =
+	     (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+			dev->sas_addr[2*i+1] =
+	      le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+		}
+	}
+	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+	if (!dev->parent)
+		sas_sata_propagate_sas_addr(dev);
+
+	/* XXX Hint: register this SATA device with SATL.
+	   When this returns, dev->sata_dev->lu is alive and
+	   present.
+	sas_satl_register_dev(dev);
+	*/
+	return 0;
+out_err:
+	dev->sata_dev.identify_packet_device = NULL;
+	dev->sata_dev.identify_device = NULL;
+	kfree(identify_x);
+	return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+	return -ENODEV;
+}
+
+/* ---------- SAS end devices ---------- */
+
+static int sas_get_itnl_timeout(struct domain_device *dev)
+{
+	static const u8 mode_sense_6[16]  = { 0x1a, };
+	static const u8 mode_sense_10[16] = { 0x5a, };
+
+	int res = -ENOMEM;
+	struct sas_task *task;
+	u8 *buffer, *__buf;
+	const int buffer_size = 12;
+
+	task = sas_alloc_task(GFP_KERNEL);
+	if (!task)
+		return -ENOMEM;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer)
+		goto out;
+	__buf = buffer;
+
+	task->dev = dev;
+
+	task->ssp_task.retry_count = 1;
+	memcpy(task->ssp_task.cdb, mode_sense_6, 16);
+	task->ssp_task.cdb[1] |= (1 << 3);
+	task->ssp_task.cdb[2] = 0x19;
+	task->ssp_task.cdb[4] = buffer_size;
+
+	res = sas_execute_task(task, buffer, buffer_size, PCI_DMA_FROMDEVICE);
+	if (res) {
+		SAS_DPRINTK("task to device %llx returned stat 0x%x for "
+			    "MODE SENSE 6\n",
+			    SAS_ADDR(dev->sas_addr), task->task_status.stat);
+		memcpy(task->ssp_task.cdb, mode_sense_10, 16);
+		task->ssp_task.cdb[1] |= (1 << 3);
+		task->ssp_task.cdb[2] = 0x19;
+		task->ssp_task.cdb[8] = buffer_size;
+
+		res = sas_execute_task(task, buffer, buffer_size,
+				       PCI_DMA_FROMDEVICE);
+		if (res) {
+			SAS_DPRINTK("task to device %llx returned stat 0x%x "
+				    "for MODE SENSE 10\n",
+				    SAS_ADDR(dev->sas_addr),
+				    task->task_status.stat);
+			goto out_buf;
+		}
+		dev->end_dev.ms_10 = 1;
+		buffer += 4;
+	}
+
+	buffer += 4;		  /* skip mode parameter header */
+
+	dev->end_dev.ready_led_meaning = (buffer[2] & (1<<4)) ? 1 : 0;
+	dev->end_dev.itnl_timeout = be16_to_cpu(*(__be16 *)(buffer+4));
+	dev->end_dev.iresp_timeout= be16_to_cpu(*(__be16 *)(buffer+6));
+
+	res = 0;
+
+out_buf:
+	kfree(__buf);
+out:
+	sas_free_task(task);
+	return res;
+}
+
+static int sas_get_report_luns(struct domain_device *dev, u8 **buffer,
+			       int *size)
+{
+	static const u8 report_luns[16] = { 0xA0, };
+	static const u8 RL_WLUN[8] = { 0xC1, 0x01, };
+
+	int res = -ENOMEM;
+	struct sas_task *task;
+	u8 *buf;
+	int buffer_size = 16;
+	u32 len;
+
+	*buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!*buffer)
+		return -ENOMEM;
+	buf = *buffer;
+
+	task = sas_alloc_task(GFP_KERNEL);
+	if (!task)
+		goto out_err;
+
+	task->dev = dev;
+	task->ssp_task.retry_count = 1;
+	memcpy(task->ssp_task.cdb, report_luns, 16);
+	*(__be32 *)(&task->ssp_task.cdb[6]) = cpu_to_be32(buffer_size);
+
+	res = sas_execute_task(task, buf, buffer_size, PCI_DMA_FROMDEVICE);
+	if (res) {
+		SAS_DPRINTK("REPORT LUNS to LUN0 failed for device %llx "
+			    "with status:0x%x\n",
+			    SAS_ADDR(dev->sas_addr), task->task_status.stat);
+		memcpy(task->ssp_task.LUN, RL_WLUN, 8);
+		res = sas_execute_task(task, buf, buffer_size,
+				       PCI_DMA_FROMDEVICE);
+		if (res) {
+			SAS_DPRINTK("REPORT LUNS to REPORT LUNS W-LUN failed "
+				    "for device %llx with status:0x%x\n",
+				    SAS_ADDR(dev->sas_addr),
+				    task->task_status.stat);
+			goto out_err_task;
+		}
+		dev->end_dev.rl_wlun = 1;
+	}
+
+	len = be32_to_cpu(*(__be32 *)buf);
+	if (len + 8 > buffer_size) {
+		SAS_DPRINTK("need bigger buffer for REPORT LUNS\n");
+		buffer_size = len + 8;
+		res = -ENOMEM;
+		buf = kzalloc(buffer_size, GFP_KERNEL);
+		if (!buf)
+			goto out_err_task;
+		kfree(*buffer);
+		*buffer = buf;
+		if (dev->end_dev.rl_wlun)
+			memcpy(task->ssp_task.LUN, RL_WLUN, 8);
+		else
+			memset(task->ssp_task.LUN, 0, 8);
+		res = sas_execute_task(task, buf, buffer_size,
+				       PCI_DMA_FROMDEVICE);
+		if (res) {
+			SAS_DPRINTK("2nd REPORT LUNS to %s failed "
+				    "for device %llx with status:0x%x\n",
+				    dev->end_dev.rl_wlun ? "REPORT LUNS W-LUN"
+				    : "LUN0",
+				    SAS_ADDR(dev->sas_addr),
+				    task->task_status.stat);
+			goto out_err_task;
+		}
+	}
+
+	*size = len+8;
+	sas_free_task(task);
+	return 0;
+
+out_err_task:
+	sas_free_task(task);
+out_err:
+	kfree(*buffer);
+	*buffer = NULL;
+	size = 0;
+	return res;
+}
+
+#if 0
+static int sas_get_inquiry(struct LU *lu)
+{
+	static const u8 inquiry_cmd[16] = { 0x12, };
+	struct sas_task *task;
+	int res;
+
+	task = sas_alloc_task(GFP_KERNEL);
+	if (!task)
+		return -ENOMEM;
+
+	task->dev = lu->parent;
+	task->ssp_task.retry_count = 1;
+	memcpy(task->ssp_task.LUN, lu->LUN, 8);
+	memcpy(task->ssp_task.cdb, inquiry_cmd, 16);
+	*(__be16 *)(task->ssp_task.cdb+3) = cpu_to_be16(SAS_INQUIRY_DATA_LEN);
+
+	res = sas_execute_task(task, lu->inquiry_data, SAS_INQUIRY_DATA_LEN,
+			       PCI_DMA_FROMDEVICE);
+	if (!res)
+		lu->inquiry_valid_data_len = min(SAS_INQUIRY_DATA_LEN,
+						 lu->inquiry_data[4]+5);
+	sas_free_task(task);
+	return res;
+}
+#endif
+
+static struct LU *sas_alloc_lu(void)
+{
+	struct LU *lu = kzalloc(sizeof(*lu), GFP_KERNEL);
+	if (lu)
+		INIT_LIST_HEAD(&lu->list);
+	return lu;
+}
+
+static int sas_register_lu(struct domain_device *dev, u8 *buf, int size)
+{
+#if 0
+	int res;
+
+	for (buf = buf+8, size -= 8; size > 0; size -= 8, buf += 8) {
+		struct LU *lu = sas_alloc_lu();
+
+		SAS_DPRINTK("%016llx probing LUN:%016llx\n",
+			    SAS_ADDR(dev->sas_addr),
+			    be64_to_cpu(*(__be64 *)buf));
+		if (lu) {
+			lu->parent = dev;
+			memcpy(lu->LUN, buf, 8);
+			res = sas_get_inquiry(lu);
+			if (res) {
+				SAS_DPRINTK("dev %llx LUN %016llx didn't reply"
+					    " to INQUIRY, forgotten\n",
+					    SAS_ADDR(dev->sas_addr),
+					    SAS_ADDR(lu->LUN));
+				kfree(lu);
+				continue;
+			}
+			lu->lu_obj.kset = &dev->end_dev.LU_kset;
+			kobject_set_name(&lu->lu_obj, "%016llx",
+					 SAS_ADDR(lu->LUN));
+			lu->lu_obj.ktype = dev->end_dev.LU_kset.ktype;
+			list_add_tail(&lu->list, &dev->end_dev.LU_list);
+		}
+	}
+#else
+	struct LU *lu = sas_alloc_lu();
+	if (!lu)
+		goto out;
+	
+	lu->parent = dev;
+	memset(lu->LUN, 0, 8);
+
+	lu->lu_obj.kset = &dev->end_dev.LU_kset;
+	kobject_set_name(&lu->lu_obj, "%016llx",
+			 SAS_ADDR(lu->LUN));
+	lu->lu_obj.ktype = dev->end_dev.LU_kset.ktype;
+	list_add_tail(&lu->list, &dev->end_dev.LU_list);
+out:
+#endif
+
+	return list_empty(&dev->end_dev.LU_list) ? -ENODEV : 0;
+}
+
+/**
+ * sas_do_lu_discovery -- Discover LUs of a SCSI device
+ * @dev: pointer to a domain device of interest
+ *
+ * Discover logical units present in the SCSI device.  I'd like this
+ * to be moved to SCSI Core, but SCSI Core has no concept of a "SCSI
+ * device with a SCSI Target port".  A SCSI device with a SCSI Target
+ * port is a device which the _transport_ found, but other than that,
+ * the transport has little or _no_ knowledge about the device.
+ * Ideally, a LLDD would register a "SCSI device with a SCSI Target
+ * port" with SCSI Core and then SCSI Core would do LU discovery of
+ * that device.
+ *
+ * REPORT LUNS is mandatory.  If a device doesn't support it,
+ * it is broken and you should return it.  Nevertheless, we
+ * assume (optimistically) that the link hasn't been severed and
+ * that maybe we can get to the device anyhow.
+ */
+static int sas_do_lu_discovery(struct domain_device *dev)
+{
+	int  res;
+	u8  *buffer;
+	int  size;
+
+	res = sas_get_report_luns(dev, &buffer, &size);
+	if (res) {
+		SAS_DPRINTK("dev %llx didn't reply to REPORT LUNS, trying "
+			    "LUN 0 anyway\n",
+			    SAS_ADDR(dev->sas_addr));
+		size = 16;
+		buffer = kzalloc(size, GFP_KERNEL);
+	}
+
+	res = sas_register_lu(dev, buffer, size);
+	if (res) {
+		SAS_DPRINTK("dev %llx didn't report any LUs\n",
+			    SAS_ADDR(dev->sas_addr));
+		res = 0;
+	}
+
+	kfree(buffer);
+	return res;
+}
+
+/* ---------- Common/dispatchers ---------- */
+
+void sas_kobj_set(struct domain_device *dev)
+{
+	if (!dev->parent) {
+		/* device directly attached to the host adapter */
+		dev->dev_obj.kset = &dev->port->dev_kset;
+	} else {
+		/* parent is an expander */
+		dev->dev_obj.parent = &dev->parent->dev_obj;
+		dev->port = dev->parent->port;
+	}
+
+	list_add_tail(&dev->dev_list_node, &dev->port->dev_list);
+	kobject_set_name(&dev->dev_obj, "%016llx", SAS_ADDR(dev->sas_addr));
+	dev->dev_obj.ktype = dev_ktype[dev->dev_type];
+}
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it.  Then depending on the type of device we call the appropriate
+ * discover functions.  Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it.  That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time.  Devices directly attached to a HA
+ * port, have no parents.  All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+	int res;
+
+	sas_get_ata_command_set(dev);
+
+	res = sas_notify_lldd_dev_found(dev);
+	if (res)
+		return res;
+
+	switch (dev->dev_type) {
+	case SATA_DEV:
+		res = sas_discover_sata_dev(dev);
+		break;
+	case SATA_PM:
+		res = sas_discover_sata_pm(dev);
+		break;
+	default:
+		break;
+	}
+
+	sas_notify_lldd_dev_gone(dev);
+	if (!res) {
+		sas_notify_lldd_dev_found(dev);
+		sas_kobj_set(dev);
+	}
+	return res;
+}
+
+/**
+ * sas_discover_end_dev -- discover an end device (SSP, etc)
+ * @end: pointer to domain device of interest
+ *
+ * See comment in sas_discover_sata().
+ */
+int sas_discover_end_dev(struct domain_device *dev)
+{
+	int res;
+
+	res = sas_notify_lldd_dev_found(dev);
+	if (res)
+		return res;
+
+	res = sas_get_itnl_timeout(dev);
+	if (!res) {
+		sas_notify_lldd_dev_gone(dev);
+		sas_notify_lldd_dev_found(dev);
+	}
+
+	dev->end_dev.LU_kset.kobj.parent = &dev->dev_obj;
+	dev->end_dev.LU_kset.ktype  = &lu_dev_ktype;
+
+	res = sas_do_lu_discovery(dev);
+	if (res)
+		goto out_err;
+
+	kobject_set_name(&dev->end_dev.LU_kset.kobj, "%s", "LUNS");
+
+	sas_kobj_set(dev);
+	return 0;
+
+out_err:
+	sas_notify_lldd_dev_gone(dev);
+	return res;
+}
+
+/* ---------- Device registration and unregistration ---------- */
+
+static inline void sas_unregister_common_dev(struct domain_device *dev)
+{
+	sas_notify_lldd_dev_gone(dev);
+	if (!dev->parent)
+		dev->port->port_dev = NULL;
+	else
+		list_del_init(&dev->siblings);
+	list_del_init(&dev->dev_list_node);
+	kobject_unregister(&dev->dev_obj);
+}
+
+static int sas_register_end_dev(struct domain_device *dev)
+{
+	struct LU *lu;
+
+	kobject_register(&dev->dev_obj);
+	kset_register(&dev->end_dev.LU_kset);
+
+	list_for_each_entry(lu, &dev->end_dev.LU_list, list) {
+		sas_register_with_scsi(lu);
+	}
+
+	return 0;
+}
+
+static void sas_unregister_end_dev(struct domain_device *dev)
+{
+	struct LU *lu, *n;
+
+	list_for_each_entry_safe(lu, n, &dev->end_dev.LU_list, list) {
+		sas_unregister_with_scsi(lu);
+		list_del_init(&lu->list);
+	}
+	kset_unregister(&dev->end_dev.LU_kset);
+	sas_unregister_common_dev(dev);
+}
+
+static int sas_register_sata(struct domain_device *dev)
+{
+	/* XXX Hint: Register the SATL supported LU with SCSI.
+	if (dev->sata_dev->lu)
+		sas_register_with_scsi(dev->sata_dev->lu)
+	*/
+	kobject_register(&dev->dev_obj);
+	return 0;
+}
+
+static void sas_unregister_sata(struct domain_device *dev)
+{
+	/* XXX Hint: See hint above.
+	if (dev->sata_dev->lu)
+		sas_unregister_with_scsi(dev->sata_dev->lu);
+	*/
+	sas_unregister_common_dev(dev);
+}
+
+/**
+ * sas_register_ex_dev -- Register this expander
+ * @ex: pointer to domain device
+ *
+ * It is imperative that this is done breadth-first.  Other parts of
+ * the code rely on that.
+ */
+static int sas_register_ex_dev(struct domain_device *dev)
+{
+	kobject_register(&dev->dev_obj);
+	sysfs_create_bin_file(&dev->dev_obj, &dev->ex_dev.smp_bin_attr);
+	return 0;
+}
+
+static void sas_unregister_ex_dev(struct domain_device *dev)
+{
+	BUG_ON(!list_empty(&dev->ex_dev.children));
+	sas_unregister_common_dev(dev);
+}
+
+/**
+ * sas_register_domain_devs -- register the domain devices with sysfs
+ * @port: the port to the domain
+ *
+ * This function registers the domain devices with sysfs and with
+ * the SCSI subsystem.
+ */
+static int sas_register_domain_devs(struct sas_port *port)
+{
+	struct domain_device *dev;
+
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		if (dev->dev_obj.dentry)
+			continue;
+		switch (dev->dev_type) {
+		case SAS_END_DEV:
+			sas_register_end_dev(dev);
+			break;
+		case EDGE_DEV:
+		case FANOUT_DEV:
+			sas_register_ex_dev(dev);
+			break;
+		case SATA_DEV:
+		case SATA_PM:
+			sas_register_sata(dev);
+			break;
+		default:
+			SAS_DPRINTK("%s: unknown device type %d\n",
+				    __FUNCTION__, dev->dev_type);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+void sas_unregister_dev(struct domain_device *dev)
+{
+	switch (dev->dev_type) {
+	case SAS_END_DEV:
+		sas_unregister_end_dev(dev);
+		break;
+	case EDGE_DEV:
+	case FANOUT_DEV:
+		sas_unregister_ex_dev(dev);
+		break;
+	case SATA_DEV:
+	case SATA_PM:
+		sas_unregister_sata(dev);
+		break;
+	default:
+		SAS_DPRINTK("%s: unknown device type %d\n",
+			    __FUNCTION__, dev->dev_type);
+		BUG_ON(dev);
+		break;
+	}
+}
+
+static void sas_unregister_domain_devices(struct sas_port *port)
+{
+	struct domain_device *dev, *n;
+
+	list_for_each_entry_reverse_safe(dev,n,&port->dev_list,dev_list_node)
+		sas_unregister_dev(dev);
+}
+
+/* ---------- Discovery and Revalidation ---------- */
+
+/**
+ * sas_discover_domain -- discover the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered.  Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+static int sas_discover_domain(struct sas_port *port)
+{
+	int error = 0;
+
+	if (port->port_dev)
+		return 0;
+	else {
+		error = sas_get_port_device(port);
+		if (error)
+			return error;
+	}
+
+	SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
+		    current->pid);
+
+	switch (port->port_dev->dev_type) {
+	case SAS_END_DEV:
+		error = sas_discover_end_dev(port->port_dev);
+		break;
+	case EDGE_DEV:
+	case FANOUT_DEV:
+		error = sas_discover_root_expander(port->port_dev);
+		break;
+	case SATA_DEV:
+	case SATA_PM:
+		error = sas_discover_sata(port->port_dev);
+		break;
+	default:
+		SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type);
+		break;
+	}
+
+	if (error) {
+		kfree(port->port_dev); /* not kobject_register-ed yet */
+		port->port_dev = NULL;
+	} else
+		sas_register_domain_devs(port);
+
+	SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
+		    current->pid, error);
+
+	return error;
+}
+
+static int sas_revalidate_domain(struct sas_port *port)
+{
+	int res = 0;
+
+	SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
+		    current->pid);
+	if (port->port_dev) {
+		res = sas_ex_revalidate_domain(port->port_dev);
+		if (!res)
+			sas_register_domain_devs(port);
+	}
+	SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
+		    port->id, current->pid, res);
+	return res;
+}
+
+/* ---------- Threads and events ---------- */
+
+static DECLARE_COMPLETION(disc_comp_start);
+
+static int sas_discover_thread(void *_sas_port)
+{
+	struct sas_port *port = _sas_port;
+	struct sas_ha_struct *sas_ha = port->ha;
+	struct sas_discovery *disc = &port->disc;
+
+	daemonize("sas_disc_h%dp%d", sas_ha->core.shost->host_no, port->id);
+
+	spin_lock(&disc->disc_event_lock);
+	disc->disc_thread = current;
+	complete(&disc_comp_start);
+	while (!disc->disc_thread_quit && !list_empty(&disc->disc_event_list)){
+		struct list_head *head = disc->disc_event_list.next;
+		enum discover_event disc_ev = container_of(head,
+							   struct sas_event,
+							   el)->event;
+		list_del_init(head);
+		spin_unlock(&disc->disc_event_lock);
+
+		switch (disc_ev) {
+		case DISCE_DISCOVER_DOMAIN:
+			sas_discover_domain(port);
+			break;
+		case DISCE_REVALIDATE_DOMAIN:
+			sas_revalidate_domain(port);
+			break;
+		case DISCE_PORT_GONE:
+			sas_unregister_domain_devices(port);
+			complete(&port->port_gone_completion);
+			break;
+		}
+		spin_lock(&disc->disc_event_lock);
+	}
+	INIT_LIST_HEAD(&disc->disc_event_list);
+	disc->disc_thread = NULL;
+	spin_unlock(&disc->disc_event_lock);
+	up(&disc->disc_sema);
+
+	return 0;
+}
+
+static int sas_create_discover_thread(struct sas_port *port)
+{
+	int i;
+
+	init_completion(&disc_comp_start);
+	i = kernel_thread(sas_discover_thread, port, 0);
+	if (i >= 0)
+		wait_for_completion(&disc_comp_start);
+
+	return i < 0 ? i : 0;
+}
+
+int sas_discover_event(struct sas_port *port, enum discover_event ev)
+{
+	int res;
+	struct sas_discovery *disc = &port->disc;
+
+	spin_lock(&disc->disc_event_lock);
+	list_move_tail(&disc->disc_events[ev].el,
+		       &disc->disc_event_list);
+	if (disc->disc_thread) {
+		spin_unlock(&disc->disc_event_lock);
+		return 0;
+	}
+	down_interruptible(&disc->disc_sema);
+	disc->disc_thread_quit = 0;
+	spin_unlock(&disc->disc_event_lock);
+
+	/* The event thread (caller) is single threaded so this is safe. */
+	res = sas_create_discover_thread(port);
+	if (res) {
+		SAS_DPRINTK("sas port%d: couldn't create discovery thread!\n",
+			    port->id);
+		up(&disc->disc_sema);
+	}
+	return res;
+}
+
+void sas_kill_disc_thread(struct sas_port *port)
+{
+	struct sas_discovery *disc = &port->disc;
+
+	spin_lock(&disc->disc_event_lock);
+	disc->disc_thread_quit = 1;
+	if (disc->disc_thread) {
+		wake_up_process(disc->disc_thread);
+		spin_unlock(&disc->disc_event_lock);
+		down_interruptible(&disc->disc_sema);
+		return;
+	}
+	spin_unlock(&disc->disc_event_lock);
+}
+
+/**
+ * sas_init_disc -- initialize the discovery struct in the port
+ * @port: pointer to struct port
+ *
+ * Called when the ports are being initialized.
+ */
+void sas_init_disc(struct sas_discovery *disc, struct sas_port *port)
+{
+	int i;
+
+	if (!end_dev_attrs[0]) {
+		for (i = 0; i < ARRAY_SIZE(dev_attrs)-1; i++)
+			end_dev_attrs[i] = &dev_attrs[i].attr;
+		end_dev_attrs[i] = NULL;
+		sas_init_ex_attr();
+		for (i = 0; i < ARRAY_SIZE(sata_attrs)-1; i++)
+			sata_dev_attrs[i] = &sata_attrs[i].attr;
+		sata_dev_attrs[i] = NULL;
+		for (i = 0; i < ARRAY_SIZE(lu_attrs)-1; i++)
+			lu_dev_attrs[i] = &lu_attrs[i].attr;
+		lu_dev_attrs[i] = NULL;
+	}
+
+	spin_lock_init(&disc->disc_event_lock);
+	INIT_LIST_HEAD(&disc->disc_event_list);
+	init_MUTEX(&disc->disc_sema);
+	disc->disc_thread = NULL;
+	disc->disc_thread_quit = 0;
+
+	for (i = 0; i < DISC_NUM_EVENTS; i++) {
+		struct sas_event *ev = &disc->disc_events[i];
+		ev->event = i;
+		INIT_LIST_HEAD(&ev->el);
+	}
+}
+
+void sas_unregister_devices(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	for (i = 0; i < sas_ha->num_phys; i++)
+		sas_unregister_domain_devices(sas_ha->sas_port[i]);
+}
diff -urN oldtree/drivers/scsi/sas/sas_dump.c newtree/drivers/scsi/sas/sas_dump.c
--- oldtree/drivers/scsi/sas/sas_dump.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_dump.c	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,77 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_dump.c#4 $
+ */
+
+#include "sas_dump.h"
+
+#ifdef SAS_DEBUG
+
+static const char *sas_hae_str[] = {
+	[0] = "HAE_RESET",
+};
+
+static const char *sas_porte_str[] = {
+	[0] = "PORTE_BYTES_DMAED",
+	[1] = "PORTE_BROADCAST_RCVD",
+	[2] = "PORTE_LINK_RESET_ERR",
+	[3] = "PORTE_TIMER_EVENT",
+	[4] = "PORTE_HARD_RESET",
+};
+
+static const char *sas_phye_str[] = {
+	[0] = "PHYE_LOSS_OF_SIGNAL",
+	[1] = "PHYE_OOB_DONE",
+	[2] = "PHYE_OOB_ERROR",
+	[3] = "PHYE_SPINUP_HOLD",
+};
+
+void sas_dprint_porte(int phyid, enum port_event pe)
+{
+	SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]);
+}
+void sas_dprint_phye(int phyid, enum phy_event pe)
+{
+	SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]);
+}
+
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
+{
+	SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
+		    sas_hae_str[he]);
+}
+
+void sas_dump_port(struct sas_port *port)
+{
+	SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class);
+	SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id,
+		    SAS_ADDR(port->sas_addr));
+	SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id,
+		    SAS_ADDR(port->attached_sas_addr));
+	SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto);
+	SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto);
+	SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode);
+	SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys);
+}
+
+#endif /* SAS_DEBUG */
diff -urN oldtree/drivers/scsi/sas/sas_dump.h newtree/drivers/scsi/sas/sas_dump.h
--- oldtree/drivers/scsi/sas/sas_dump.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_dump.h	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,43 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_dump.h#2 $
+ */
+
+#include "sas_internal.h"
+
+#ifdef SAS_DEBUG
+
+void sas_dprint_porte(int phyid, enum port_event pe);
+void sas_dprint_phye(int phyid, enum phy_event pe);
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he);
+void sas_dump_port(struct sas_port *port);
+
+#else /* SAS_DEBUG */
+
+static inline void sas_dprint_porte(int phyid, enum port_event pe) { }
+static inline void sas_dprint_phye(int phyid, enum phy_event pe) { }
+static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha,
+				  enum ha_event he) { }
+static inline void sas_dump_port(struct sas_port *port) { }
+
+#endif /* SAS_DEBUG */
diff -urN oldtree/drivers/scsi/sas/sas_event.c newtree/drivers/scsi/sas/sas_event.c
--- oldtree/drivers/scsi/sas/sas_event.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_event.c	2006-04-01 05:35:45.923490000 -0500
@@ -0,0 +1,296 @@
+/*
+ * Serial Attached SCSI (SAS) Event processing
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_event.c#26 $
+ */
+
+/**
+ * Implementation Of Priority Queue Without Duplication
+ * Luben Tuikov 2005/07/11
+ *
+ * The SAS class implements priority queue without duplication for
+ * handling ha/port/phy/discover events.  That is, we want to process
+ * the last N unique/non-duplicating events, in the order they arrived.
+ *
+ * The requirement is that insertion is O(1), and ordered removal is O(1).
+ *
+ * Suppose events are identified by integers.  Then what is required
+ * is that for a given sequence of any random integers R, to find a
+ * sorted sequence E, where
+ *     a) |E| <= |R|.  If the number of types of events is bounded,
+ *        then E is also bounded by that number, from b).
+ *     b) For all i and k, E[i] != E[k], except when i == k,
+ *        this gives us uniqueness/non duplication.
+ *     c) For all i < k, Order(E[i]) < Order(E[k]), this gives us
+ *        ordering.
+ *     d) If T(R) = E, then O(T) <= |R|, this ensures that insertion
+ *        is O(1), and ordered removal is O(1) trivially, since we
+ *        remove at the head of E.
+ *
+ * Example:
+ * If R = {4, 5, 1, 2, 5, 3, 3, 4, 4, 3, 1}, then
+ *    E = {2, 5, 4, 3, 1}.
+ *
+ * The algorithm, T, makes use of an array of list elements, indexed
+ * by event type, and an event list head which is a linked list of the
+ * elements of the array.  When the next event arrives, we index the
+ * array by the event, and add that event to the tail of the event
+ * list head, deleting it from its previous list position (if it had
+ * one).
+ *
+ * Clearly insertion is O(1).
+ *
+ * E is given by the elements of the event list, traversed from head
+ * to tail.
+ */
+
+#include <linux/sched.h>
+
+#include <scsi/scsi_host.h>
+#include "sas_internal.h"
+#include "sas_dump.h"
+#include <scsi/sas/sas_discover.h>
+
+static void sas_process_phy_event(struct sas_phy *phy)
+{
+	unsigned long flags;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	enum phy_event phy_event;
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	while (!list_empty(&phy->phy_event_list)) {
+		struct list_head *head = phy->phy_event_list.next;
+		phy_event = container_of(head, struct sas_event, el)->event;
+		list_del_init(head);
+		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+
+		sas_dprint_phye(phy->id, phy_event);
+
+		switch(phy_event) {
+		case PHYE_LOSS_OF_SIGNAL:
+			sas_phye_loss_of_signal(phy);
+			break;
+		case PHYE_OOB_DONE:
+			sas_phye_oob_done(phy);
+			break;
+		case PHYE_OOB_ERROR:
+			sas_phye_oob_error(phy);
+			break;
+		case PHYE_SPINUP_HOLD:
+			sas_phye_spinup_hold(phy);
+			break;
+		}
+		spin_lock_irqsave(&sas_ha->event_lock, flags);
+	}
+	/* Clear the bit in case we received events in due time. */
+	sas_ha->phye_mask &= ~(1 << phy->id);
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+}
+
+static void sas_process_port_event(struct sas_phy *phy)
+{
+	unsigned long flags;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	enum port_event port_event;
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	while (!list_empty(&phy->port_event_list)) {
+		struct list_head *head = phy->port_event_list.next;
+		port_event = container_of(head, struct sas_event, el)->event;
+		list_del_init(head);
+		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+
+		sas_dprint_porte(phy->id, port_event);
+
+		switch (port_event) {
+		case PORTE_BYTES_DMAED:
+			sas_porte_bytes_dmaed(phy);
+			break;
+		case PORTE_BROADCAST_RCVD:
+			sas_porte_broadcast_rcvd(phy);
+			break;
+		case PORTE_LINK_RESET_ERR:
+			sas_porte_link_reset_err(phy);
+			break;
+		case PORTE_TIMER_EVENT:
+			sas_porte_timer_event(phy);
+			break;
+		case PORTE_HARD_RESET:
+			sas_porte_hard_reset(phy);
+			break;
+		}
+		spin_lock_irqsave(&sas_ha->event_lock, flags);
+	}
+	/* Clear the bit in case we received events in due time. */
+	sas_ha->porte_mask &= ~(1 << phy->id);
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+}
+
+static void sas_process_ha_event(struct sas_ha_struct *sas_ha)
+{
+	unsigned long flags;
+	enum ha_event ha_event;
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	while (!list_empty(&sas_ha->ha_event_list)) {
+		struct list_head *head = sas_ha->ha_event_list.next;
+		ha_event = container_of(head, struct sas_event, el)->event;
+		list_del_init(head);
+		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+
+		sas_dprint_hae(sas_ha, ha_event);
+
+		switch (ha_event) {
+		case HAE_RESET:
+			sas_hae_reset(sas_ha);
+			break;
+		}
+		spin_lock_irqsave(&sas_ha->event_lock, flags);
+	}
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+}
+
+static void sas_process_events(struct sas_ha_struct *sas_ha)
+{
+	unsigned long flags;
+	u32 porte_mask, phye_mask;
+	int p;
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	phye_mask = sas_ha->phye_mask;
+	sas_ha->phye_mask = 0;
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+
+	for (p = 0; phye_mask != 0; phye_mask >>= 1, p++)
+		if (phye_mask & 01)
+			sas_process_phy_event(sas_ha->sas_phy[p]);
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	porte_mask = sas_ha->porte_mask;
+	sas_ha->porte_mask = 0;
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+
+	for (p = 0; porte_mask != 0; porte_mask >>= 1, p++)
+		if (porte_mask & 01)
+			sas_process_port_event(sas_ha->sas_phy[p]);
+
+	sas_process_ha_event(sas_ha);
+}
+
+static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sas_ha->event_lock, flags);
+	list_move_tail(&sas_ha->ha_events[event].el, &sas_ha->ha_event_list);
+	up(&sas_ha->event_sema);
+	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+}
+
+static void notify_port_event(struct sas_phy *phy, enum port_event event)
+{
+	struct sas_ha_struct *ha = phy->ha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->event_lock, flags);
+	list_move_tail(&phy->port_events[event].el, &phy->port_event_list);
+	ha->porte_mask |= (1 << phy->id);
+	up(&ha->event_sema);
+	spin_unlock_irqrestore(&ha->event_lock, flags);
+}
+
+static void notify_phy_event(struct sas_phy *phy, enum phy_event event)
+{
+	struct sas_ha_struct *ha = phy->ha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->event_lock, flags);
+	list_move_tail(&phy->phy_events[event].el, &phy->phy_event_list);
+	ha->phye_mask |= (1 << phy->id);
+	up(&ha->event_sema);
+	spin_unlock_irqrestore(&ha->event_lock, flags);
+}
+
+static DECLARE_COMPLETION(event_th_comp);
+
+static int sas_event_thread(void *_sas_ha)
+{
+	struct sas_ha_struct *sas_ha = _sas_ha;
+
+	daemonize("sas_event_%d", sas_ha->core.shost->host_no);
+	current->flags |= PF_NOFREEZE;
+
+	complete(&event_th_comp);
+
+	while (1) {
+		down_interruptible(&sas_ha->event_sema);
+		if (sas_ha->event_thread_kill)
+			break;
+		sas_process_events(sas_ha);
+	}
+
+	complete(&event_th_comp);
+
+	return 0;
+}
+
+int sas_start_event_thread(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	init_MUTEX_LOCKED(&sas_ha->event_sema);
+	sas_ha->event_thread_kill = 0;
+
+	spin_lock_init(&sas_ha->event_lock);
+	INIT_LIST_HEAD(&sas_ha->ha_event_list);
+	sas_ha->porte_mask = 0;
+	sas_ha->phye_mask = 0;
+
+	for (i = 0; i < HA_NUM_EVENTS; i++) {
+		struct sas_event *ev = &sas_ha->ha_events[i];
+		ev->event = i;
+		INIT_LIST_HEAD(&ev->el);
+	}
+
+	sas_ha->notify_ha_event = notify_ha_event;
+	sas_ha->notify_port_event = notify_port_event;
+	sas_ha->notify_phy_event = notify_phy_event;
+
+	i = kernel_thread(sas_event_thread, sas_ha, 0);
+	if (i >= 0)
+		wait_for_completion(&event_th_comp);
+
+	return i < 0 ? i : 0;
+}
+
+void sas_kill_event_thread(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	init_completion(&event_th_comp);
+	sas_ha->event_thread_kill = 1;
+	up(&sas_ha->event_sema);
+	wait_for_completion(&event_th_comp);
+
+	for (i = 0; i < sas_ha->num_phys; i++)
+		sas_kill_disc_thread(sas_ha->sas_port[i]);
+}
diff -urN oldtree/drivers/scsi/sas/sas_expander.c newtree/drivers/scsi/sas/sas_expander.c
--- oldtree/drivers/scsi/sas/sas_expander.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_expander.c	2006-04-01 05:35:45.927490250 -0500
@@ -0,0 +1,1823 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_expander.c#60 $
+ */
+
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+
+#include "sas_internal.h"
+#include <scsi/sas/sas_task.h>
+#include <scsi/sas/sas_discover.h>
+
+static int sas_discover_expander(struct domain_device *dev);
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
+static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr);
+
+static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
+static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
+
+/* ---------- Expander attributes ---------- */
+
+static ssize_t ex_show_change_count(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.ex_change_count);
+}
+
+static ssize_t ex_show_max_route_indexes(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.max_route_indexes);
+}
+
+static ssize_t ex_show_num_phys(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.num_phys);
+}
+
+static ssize_t ex_show_enclosure_logical_id(struct domain_device *dev,
+					    char *page)
+{
+	return sprintf(page, "%llx\n",
+		       SAS_ADDR(dev->ex_dev.enclosure_logical_id));
+}
+
+static ssize_t ex_show_vendor_id(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%s\n", dev->ex_dev.vendor_id);
+}
+
+static ssize_t ex_show_product_id(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%s\n", dev->ex_dev.product_id);
+}
+
+static ssize_t ex_show_product_rev(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%s\n", dev->ex_dev.product_rev);
+}
+
+static ssize_t ex_show_component_vendor_id(struct domain_device *dev,
+					   char *page)
+{
+	return sprintf(page, "%s\n", dev->ex_dev.component_vendor_id);
+}
+
+static ssize_t ex_show_component_id(struct domain_device *dev, char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.component_id);
+}
+
+static ssize_t ex_show_component_revision_id(struct domain_device *dev,
+					     char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.component_revision_id);
+}
+
+static ssize_t ex_show_conf_route_table(struct domain_device *dev,
+					char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.conf_route_table);
+}
+
+static ssize_t ex_show_configuring(struct domain_device *dev,
+				   char *page)
+{
+	return sprintf(page, "%d\n", dev->ex_dev.configuring);
+}
+
+static struct domain_dev_attribute ex_attrs[] = {
+	__ATTR(dev_type, 0444, dev_show_type, NULL),
+	__ATTR(iproto, 0444, dev_show_iproto, NULL),
+	__ATTR(tproto, 0444, dev_show_tproto, NULL),
+	__ATTR(sas_addr, 0444, dev_show_sas_addr, NULL),
+	__ATTR(linkrate, 0444, dev_show_linkrate, NULL),
+	__ATTR(min_linkrate, 0444, dev_show_min_linkrate, NULL),
+	__ATTR(max_linkrate, 0444, dev_show_max_linkrate, NULL),
+	__ATTR(pathways, 0444, dev_show_pathways, NULL),
+	__ATTR(change_count, 0444, ex_show_change_count, NULL),
+	__ATTR(max_route_indexes, 0444, ex_show_max_route_indexes, NULL),
+	__ATTR(num_phys, 0444, ex_show_num_phys, NULL),
+	__ATTR(enclosure_logical_id, 0444, ex_show_enclosure_logical_id, NULL),
+	__ATTR(vendor_id, 0444, ex_show_vendor_id, NULL),
+	__ATTR(product_id, 0444, ex_show_product_id, NULL),
+	__ATTR(product_rev, 0444, ex_show_product_rev, NULL),
+	__ATTR(component_vendor_id, 0444, ex_show_component_vendor_id, NULL),
+	__ATTR(component_id, 0444, ex_show_component_id, NULL),
+	__ATTR(component_revision_id, 0444,ex_show_component_revision_id,NULL),
+	__ATTR(conf_route_table, 0444, ex_show_conf_route_table, NULL),
+	__ATTR(configuring, 0444, ex_show_configuring, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *ex_dev_attrs[ARRAY_SIZE(ex_attrs)];
+
+static void ex_dev_release(struct kobject *obj)
+{
+	struct domain_device *dev = to_dom_device(obj);
+	SAS_DPRINTK("freeing dev %016llx\n", SAS_ADDR(dev->sas_addr));
+	sysfs_remove_bin_file(&dev->dev_obj, &dev->ex_dev.smp_bin_attr);
+	kfree(dev->ex_dev.ex_phy);
+	kfree(dev->ex_dev.smp_req);
+	kfree(dev);
+}
+
+struct kobj_type ex_dev_ktype = {
+	.release = ex_dev_release,
+	.sysfs_ops = &dev_sysfs_ops,
+	.default_attrs = ex_dev_attrs,
+};
+
+/* ---------- SMP task management ---------- */
+
+static void smp_task_timedout(unsigned long _task)
+{
+	struct sas_task *task = (void *) _task;
+	unsigned long flags;
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	complete(&task->completion);
+}
+
+static void smp_task_done(struct sas_task *task)
+{
+	if (!del_timer(&task->timer))
+		return;
+	complete(&task->completion);
+}
+
+/* Give it some long enough timeout. In seconds. */
+#define SMP_TIMEOUT 10
+
+static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
+			    void *resp, int resp_size)
+{
+	int res;
+	struct sas_task *task = sas_alloc_task(GFP_KERNEL);
+
+	if (!task)
+		return -ENOMEM;
+
+	task->dev = dev;
+	task->task_proto = dev->tproto;
+	sg_init_one(&task->smp_task.smp_req, req, req_size);
+	sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
+
+	task->task_done = smp_task_done;
+
+	task->timer.data = (unsigned long) task;
+	task->timer.function = smp_task_timedout;
+	task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+	add_timer(&task->timer);
+
+	res = task->dev->port->ha->lldd_execute_task(task, 1, GFP_KERNEL);
+
+	if (res) {
+		del_timer(&task->timer);
+		SAS_DPRINTK("executing SMP task failed:%d\n", res);
+		goto ex_err;
+	}
+
+	wait_for_completion(&task->completion);
+	res = -ETASK;
+	if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+		SAS_DPRINTK("smp task timed out or aborted\n");
+		task->dev->port->ha->lldd_abort_task(task);
+		if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+			SAS_DPRINTK("SMP task aborted and not done\n");
+			goto ex_err;
+		}
+	}
+	if (task->task_status.resp == SAS_TASK_COMPLETE &&
+	    task->task_status.stat == SAM_GOOD)
+		res = 0;
+	else
+		SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
+			    "status 0x%x\n", __FUNCTION__,
+			    SAS_ADDR(dev->sas_addr),
+			    task->task_status.resp,
+			    task->task_status.stat);
+ex_err:
+	sas_free_task(task);
+	return res;
+}
+
+/* ---------- Allocations ---------- */
+
+static inline void *alloc_smp_req(int size)
+{
+	u8 *p = kzalloc(size, GFP_KERNEL);
+	if (p)
+		p[0] = SMP_REQUEST;
+	return p;
+}
+
+static inline void *alloc_smp_resp(int size)
+{
+	return kzalloc(size, GFP_KERNEL);
+}
+
+/* ---------- Expander configuration ---------- */
+
+static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
+			   void *disc_resp)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+	struct smp_resp *resp = disc_resp;
+	struct discover_resp *dr = &resp->disc;
+
+	switch (resp->result) {
+	case SMP_RESP_PHY_VACANT:
+		phy->phy_state = PHY_VACANT;
+		return;
+	default:
+		phy->phy_state = PHY_NOT_PRESENT;
+		return;
+	case SMP_RESP_FUNC_ACC:
+		phy->phy_state = PHY_EMPTY; /* do not know yet */
+		break;
+	}
+
+	phy->phy_id = phy_id;
+	phy->attached_dev_type = dr->attached_dev_type;
+	phy->linkrate = dr->linkrate;
+	phy->attached_sata_host = dr->attached_sata_host;
+	phy->attached_sata_dev  = dr->attached_sata_dev;
+	phy->attached_sata_ps   = dr->attached_sata_ps;
+	phy->attached_iproto = dr->iproto << 1;
+	phy->attached_tproto = dr->tproto << 1;
+	memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
+	phy->attached_phy_id = dr->attached_phy_id;
+	phy->phy_change_count = dr->change_count;
+	phy->routing_attr = dr->routing_attr;
+	phy->virtual = dr->virtual;
+	phy->last_da_index = -1;
+
+	SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
+		    SAS_ADDR(dev->sas_addr), phy->phy_id,
+		    phy->routing_attr == TABLE_ROUTING ? 'T' :
+		    phy->routing_attr == DIRECT_ROUTING ? 'D' :
+		    phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
+		    SAS_ADDR(phy->attached_sas_addr));
+
+	return;
+}
+
+#define DISCOVER_REQ_SIZE  16
+#define DISCOVER_RESP_SIZE 56
+
+static int sas_ex_phy_discover(struct domain_device *dev, int single)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int  res = 0;
+	u8   *disc_req;
+	u8   *disc_resp;
+
+	disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+	if (!disc_req)
+		return -ENOMEM;
+
+	disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
+	if (!disc_resp) {
+		kfree(disc_req);
+		return -ENOMEM;
+	}
+
+	disc_req[1] = SMP_DISCOVER;
+
+	if (0 <= single && single < ex->num_phys) {
+		disc_req[9] = single;
+		res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+				       disc_resp, DISCOVER_RESP_SIZE);
+		if (res)
+			goto out_err;
+		sas_set_ex_phy(dev, single, disc_resp);
+	} else {
+		int i;
+
+		for (i = 0; i < ex->num_phys; i++) {
+			disc_req[9] = i;
+			res = smp_execute_task(dev, disc_req,
+					       DISCOVER_REQ_SIZE, disc_resp,
+					       DISCOVER_RESP_SIZE);
+			if (res)
+				goto out_err;
+			sas_set_ex_phy(dev, i, disc_resp);
+		}
+	}
+out_err:
+	kfree(disc_resp);
+	kfree(disc_req);
+	return res;
+}
+
+static int sas_expander_discover(struct domain_device *dev)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int res;
+
+	ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL);
+	if (!ex->ex_phy)
+		return -ENOMEM;
+
+	res = sas_ex_phy_discover(dev, -1);
+	if (res)
+		goto out_err;
+
+	return 0;
+out_err:
+	kfree(ex->ex_phy);
+	ex->ex_phy = NULL;
+	return res;
+}
+
+#define MAX_EXPANDER_PHYS 128
+
+static inline void ex_assign_report_general(struct domain_device *dev,
+					    struct smp_resp *resp)
+{
+	struct report_general_resp *rg = &resp->rg;
+
+	dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
+	dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
+	dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
+	dev->ex_dev.conf_route_table = rg->conf_route_table;
+	dev->ex_dev.configuring = rg->configuring;
+	memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
+}
+
+#define RG_REQ_SIZE   8
+#define RG_RESP_SIZE 32
+
+static int sas_ex_general(struct domain_device *dev)
+{
+	u8 *rg_req;
+	struct smp_resp *rg_resp;
+	int res;
+	int i;
+
+	rg_req = alloc_smp_req(RG_REQ_SIZE);
+	if (!rg_req)
+		return -ENOMEM;
+
+	rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+	if (!rg_resp) {
+		kfree(rg_req);
+		return -ENOMEM;
+	}
+
+	rg_req[1] = SMP_REPORT_GENERAL;
+
+	for (i = 0; i < 5; i++) {
+		res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+				       RG_RESP_SIZE);
+
+		if (res) {
+			SAS_DPRINTK("RG to ex %016llx failed:0x%x\n",
+				    SAS_ADDR(dev->sas_addr), res);
+			goto out;
+		} else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+			SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n",
+				    SAS_ADDR(dev->sas_addr), rg_resp->result);
+			res = rg_resp->result;
+			goto out;
+		}
+
+		ex_assign_report_general(dev, rg_resp);
+
+		if (dev->ex_dev.configuring) {
+			SAS_DPRINTK("RG: ex %llx self-configuring...\n",
+				    SAS_ADDR(dev->sas_addr));
+			schedule_timeout_interruptible(5*HZ);
+		} else
+			break;
+	}
+out:
+	kfree(rg_req);
+	kfree(rg_resp);
+	return res;
+}
+
+static inline void ex_assign_manuf_info(struct domain_device *dev, void
+					*_mi_resp)
+{
+	u8 *mi_resp = _mi_resp;
+
+	memcpy(dev->ex_dev.vendor_id, mi_resp + 12, 8);
+	memcpy(dev->ex_dev.product_id, mi_resp + 20, 16);
+	memcpy(dev->ex_dev.product_rev, mi_resp + 36, 4);
+
+	if (mi_resp[8] & 1) {
+		memcpy(dev->ex_dev.component_vendor_id, mi_resp + 40, 8);
+		dev->ex_dev.component_id =
+			be16_to_cpu(*(__be16 *)(mi_resp + 48));
+		dev->ex_dev.component_revision_id = mi_resp[50];
+	}
+}
+
+#define MI_REQ_SIZE   8
+#define MI_RESP_SIZE 64
+
+static int sas_ex_manuf_info(struct domain_device *dev)
+{
+	u8 *mi_req;
+	u8 *mi_resp;
+	int res;
+
+	mi_req = alloc_smp_req(MI_REQ_SIZE);
+	if (!mi_req)
+		return -ENOMEM;
+
+	mi_resp = alloc_smp_resp(MI_RESP_SIZE);
+	if (!mi_resp) {
+		kfree(mi_req);
+		return -ENOMEM;
+	}
+
+	mi_req[1] = SMP_REPORT_MANUF_INFO;
+
+	res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
+	if (res) {
+		SAS_DPRINTK("MI: ex %016llx failed:0x%x\n",
+			    SAS_ADDR(dev->sas_addr), res);
+		goto out;
+	} else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
+		SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n",
+			    SAS_ADDR(dev->sas_addr), mi_resp[2]);
+		goto out;
+	}
+
+	ex_assign_manuf_info(dev, mi_resp);
+out:
+	kfree(mi_req);
+	kfree(mi_resp);
+	return res;
+}
+
+#define PC_REQ_SIZE  44
+#define PC_RESP_SIZE 8
+
+static int smp_phy_control(struct domain_device *dev, int phy_id,
+			   enum phy_func phy_func)
+{
+	u8 *pc_req;
+	u8 *pc_resp;
+	int res;
+
+	pc_req = alloc_smp_req(PC_REQ_SIZE);
+	if (!pc_req)
+		return -ENOMEM;
+
+	pc_resp = alloc_smp_resp(PC_RESP_SIZE);
+	if (!pc_resp) {
+		kfree(pc_req);
+		return -ENOMEM;
+	}
+
+	pc_req[1] = SMP_PHY_CONTROL;
+	pc_req[9] = phy_id;
+	pc_req[10]= phy_func;
+
+	res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
+
+	kfree(pc_resp);
+	kfree(pc_req);
+	return res;
+}
+
+static inline void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+
+	smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE);
+	phy->linkrate = PHY_DISABLED;
+}
+
+static inline void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int i;
+
+	for (i = 0; i < ex->num_phys; i++) {
+		struct ex_phy *phy = &ex->ex_phy[i];
+
+		if (phy->phy_state == PHY_VACANT ||
+		    phy->phy_state == PHY_NOT_PRESENT)
+			continue;
+
+		if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
+			sas_ex_disable_phy(dev, i);
+	}
+}
+
+static inline int sas_dev_present_in_domain(struct sas_port *port,
+					    u8 *sas_addr)
+{
+	struct domain_device *dev;
+
+	if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
+		return 1;
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
+			return 1;
+	}
+	return 0;
+}
+
+#define RPS_REQ_SIZE  16
+#define RPS_RESP_SIZE 60
+
+static inline int sas_get_report_phy_sata(struct domain_device *dev,
+					  int phy_id,
+					  struct smp_resp *rps_resp)
+{
+	int res;
+	u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+
+	if (!rps_req)
+		return -ENOMEM;
+
+	rps_req[1] = SMP_REPORT_PHY_SATA;
+	rps_req[9] = phy_id;
+
+	res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
+			            rps_resp, RPS_RESP_SIZE);
+
+	kfree(rps_req);
+	return 0;
+}
+
+static inline void sas_ex_get_linkrate(struct domain_device *parent,
+				       struct domain_device *child,
+				       struct ex_phy *parent_phy)
+{
+	struct expander_device *parent_ex = &parent->ex_dev;
+	int i;
+
+	child->pathways = 0;
+
+	for (i = 0; i < parent_ex->num_phys; i++) {
+		struct ex_phy *phy = &parent_ex->ex_phy[i];
+
+		if (phy->phy_state == PHY_VACANT ||
+		    phy->phy_state == PHY_NOT_PRESENT)
+			continue;
+
+		if (SAS_ADDR(phy->attached_sas_addr) ==
+		    SAS_ADDR(child->sas_addr)) {
+
+			child->min_linkrate = min(parent->min_linkrate,
+						  phy->linkrate);
+			child->max_linkrate = max(parent->max_linkrate,
+						  phy->linkrate);
+			child->pathways++;
+		}
+	}
+	child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
+	child->pathways = min(child->pathways, parent->pathways);
+}
+
+static struct domain_device *sas_ex_discover_end_dev(
+	struct domain_device *parent, int phy_id)
+{
+	struct expander_device *parent_ex = &parent->ex_dev;
+	struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
+	struct domain_device *child = NULL;
+	int res;
+
+	if (phy->attached_sata_host || phy->attached_sata_ps)
+		return NULL;
+
+	child = kzalloc(sizeof(*child), GFP_KERNEL);
+	if (!child)
+		return NULL;
+
+	child->parent = parent;
+	child->port   = parent->port;
+	child->iproto = phy->attached_iproto;
+	memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+	sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
+	sas_ex_get_linkrate(parent, child, phy);
+
+	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
+		child->dev_type = SATA_DEV;
+		if (phy->attached_tproto & SAS_PROTO_STP)
+			child->tproto = phy->attached_tproto;
+		if (phy->attached_sata_dev)
+			child->tproto |= SATA_DEV;
+		res = sas_get_report_phy_sata(parent, phy_id,
+					      &child->sata_dev.rps_resp);
+		if (res) {
+			SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
+				    "0x%x\n", SAS_ADDR(parent->sas_addr),
+				    phy_id, res);
+			kfree(child);
+			return NULL;
+		}
+		memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
+		       sizeof(struct dev_to_host_fis));
+		sas_init_dev(child);
+		res = sas_discover_sata(child);
+		if (res) {
+			SAS_DPRINTK("sas_discover_sata() for device %16llx at "
+				    "%016llx:0x%x returned 0x%x\n",
+				    SAS_ADDR(child->sas_addr),
+				    SAS_ADDR(parent->sas_addr), phy_id, res);
+			kfree(child);
+			return NULL;
+		}
+	} else if (phy->attached_tproto & SAS_PROTO_SSP) {
+		child->dev_type = SAS_END_DEV;
+		child->tproto = phy->attached_tproto;
+		sas_init_dev(child);
+		res = sas_discover_end_dev(child);
+		if (res) {
+			SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
+				    "at %016llx:0x%x returned 0x%x\n",
+				    SAS_ADDR(child->sas_addr),
+				    SAS_ADDR(parent->sas_addr), phy_id, res);
+			kfree(child);
+			return NULL;
+		}
+	} else {
+		SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
+			    phy->attached_tproto, SAS_ADDR(parent->sas_addr),
+			    phy_id);
+	}
+	list_add_tail(&child->siblings, &parent_ex->children);
+	return child;
+}
+
+static struct domain_device *sas_ex_discover_expander(
+	struct domain_device *parent, int phy_id)
+{
+	struct expander_device *parent_ex = &parent->ex_dev;
+	struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
+	struct domain_device *child = NULL;
+	int res;
+
+	if (phy->routing_attr == DIRECT_ROUTING) {
+		SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not "
+			    "allowed\n",
+			    SAS_ADDR(parent->sas_addr), phy_id,
+			    SAS_ADDR(phy->attached_sas_addr),
+			    phy->attached_phy_id);
+		return NULL;
+	}
+	child = kzalloc(sizeof(*child), GFP_KERNEL);
+	if (!child)
+		return NULL;
+	child->dev_type = phy->attached_dev_type;
+	child->parent = parent;
+	child->port = parent->port;
+	child->iproto = phy->attached_iproto;
+	child->tproto = phy->attached_tproto;
+	memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+	sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
+	sas_ex_get_linkrate(parent, child, phy);
+	child->ex_dev.level = parent_ex->level + 1;
+	parent->port->disc.max_level = max(parent->port->disc.max_level,
+					   child->ex_dev.level);
+	sas_init_dev(child);
+	res = sas_discover_expander(child);
+	if (res) {
+		kfree(child);
+		return NULL;
+	}
+	list_add_tail(&child->siblings, &parent_ex->children);
+	return child;
+}
+
+static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
+	struct domain_device *child = NULL;
+	int res = 0;
+
+	/* Phy state */
+	if (ex_phy->linkrate == PHY_SPINUP_HOLD) {
+		if (!smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET))
+			res = sas_ex_phy_discover(dev, phy_id);
+		if (res)
+			return res;
+	}
+
+	/* Parent and domain coherency */
+	if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+			     SAS_ADDR(dev->port->sas_addr)))
+		return 0;
+	if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+			    SAS_ADDR(dev->parent->sas_addr)))
+		return 0;
+	if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
+		sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
+
+	if (ex_phy->attached_dev_type == NO_DEVICE) {
+		if (ex_phy->routing_attr == DIRECT_ROUTING) {
+			memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+			sas_configure_routing(dev, ex_phy->attached_sas_addr);
+		}
+		return 0;
+	} else if (ex_phy->linkrate == PHY_LINKRATE_UNKNOWN)
+		return 0;
+
+	if (ex_phy->attached_dev_type != SAS_END_DEV &&
+	    ex_phy->attached_dev_type != FANOUT_DEV &&
+	    ex_phy->attached_dev_type != EDGE_DEV) {
+		SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
+			    "phy 0x%x\n", ex_phy->attached_dev_type,
+			    SAS_ADDR(dev->sas_addr),
+			    phy_id);
+		return 0;
+	}
+
+	res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
+	if (res) {
+		SAS_DPRINTK("configure routing for dev %016llx "
+			    "reported 0x%x. Forgotten\n",
+			    SAS_ADDR(ex_phy->attached_sas_addr), res);
+		sas_disable_routing(dev, ex_phy->attached_sas_addr);
+		return res;
+	}
+
+	switch (ex_phy->attached_dev_type) {
+	case SAS_END_DEV:
+		child = sas_ex_discover_end_dev(dev, phy_id);
+		break;
+	case FANOUT_DEV:
+		if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
+			SAS_DPRINTK("second fanout expander %016llx phy 0x%x "
+				    "attached to ex %016llx phy 0x%x\n",
+				    SAS_ADDR(ex_phy->attached_sas_addr),
+				    ex_phy->attached_phy_id,
+				    SAS_ADDR(dev->sas_addr),
+				    phy_id);
+			sas_ex_disable_phy(dev, phy_id);
+			break;
+		} else
+			memcpy(dev->port->disc.fanout_sas_addr,
+			       ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
+		/* fallthrough */
+	case EDGE_DEV:
+		child = sas_ex_discover_expander(dev, phy_id);
+		break;
+	default:
+		break;
+	}
+
+	if (child) {
+		int i;
+
+		for (i = 0; i < ex->num_phys; i++) {
+			if (ex->ex_phy[i].phy_state == PHY_VACANT ||
+			    ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
+				continue;
+
+			if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
+			    SAS_ADDR(child->sas_addr))
+				ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+		}
+	}
+
+	return res;
+}
+
+static inline int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int i;
+
+	for (i = 0; i < ex->num_phys; i++) {
+		struct ex_phy *phy = &ex->ex_phy[i];
+
+		if (phy->phy_state == PHY_VACANT ||
+		    phy->phy_state == PHY_NOT_PRESENT)
+			continue;
+
+		if ((phy->attached_dev_type == EDGE_DEV ||
+		     phy->attached_dev_type == FANOUT_DEV) &&
+		    phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+			memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
+
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int sas_check_level_subtractive_boundary(struct domain_device *dev)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct domain_device *child;
+	u8 sub_addr[8] = {0, };
+
+	list_for_each_entry(child, &ex->children, siblings) {
+		if (child->dev_type != EDGE_DEV &&
+		    child->dev_type != FANOUT_DEV)
+			continue;
+		if (sub_addr[0] == 0) {
+			sas_find_sub_addr(child, sub_addr);
+			continue;
+		} else {
+			u8 s2[8];
+
+			if (sas_find_sub_addr(child, s2) &&
+			    (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
+
+				SAS_DPRINTK("ex %016llx->%016llx-?->%016llx "
+					    "diverges from subtractive "
+					    "boundary %016llx\n",
+					    SAS_ADDR(dev->sas_addr),
+					    SAS_ADDR(child->sas_addr),
+					    SAS_ADDR(s2),
+					    SAS_ADDR(sub_addr));
+
+				sas_ex_disable_port(child, s2);
+			}
+		}
+	}
+	return 0;
+}
+/**
+ * sas_ex_discover_devices -- discover devices attached to this expander
+ * dev: pointer to the expander domain device
+ * single: if you want to do a single phy, else set to -1;
+ *
+ * Configure this expander for use with its devices and register the
+ * devices of this expander.
+ */
+static int sas_ex_discover_devices(struct domain_device *dev, int single)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int i = 0, end = ex->num_phys;
+	int res = 0;
+
+	if (0 <= single && single < end) {
+		i = single;
+		end = i+1;
+	}
+
+	for ( ; i < end; i++) {
+		struct ex_phy *ex_phy = &ex->ex_phy[i];
+
+		if (ex_phy->phy_state == PHY_VACANT ||
+		    ex_phy->phy_state == PHY_NOT_PRESENT ||
+		    ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
+			continue;
+
+		switch (ex_phy->linkrate) {
+		case PHY_DISABLED:
+		case PHY_RESET_PROBLEM:
+		case PHY_PORT_SELECTOR:
+			continue;
+		default:
+			res = sas_ex_discover_dev(dev, i);
+			if (res)
+				break;
+			continue;
+		}
+	}
+
+	if (!res)
+		sas_check_level_subtractive_boundary(dev);
+
+	return res;
+}
+
+static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int i;
+	u8  *sub_sas_addr = NULL;
+
+	if (dev->dev_type != EDGE_DEV)
+		return 0;
+
+	for (i = 0; i < ex->num_phys; i++) {
+		struct ex_phy *phy = &ex->ex_phy[i];
+
+		if (phy->phy_state == PHY_VACANT ||
+		    phy->phy_state == PHY_NOT_PRESENT)
+			continue;
+
+		if ((phy->attached_dev_type == FANOUT_DEV ||
+		     phy->attached_dev_type == EDGE_DEV) &&
+		    phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+			if (!sub_sas_addr)
+				sub_sas_addr = &phy->attached_sas_addr[0];
+			else if (SAS_ADDR(sub_sas_addr) !=
+				 SAS_ADDR(phy->attached_sas_addr)) {
+
+				SAS_DPRINTK("ex %016llx phy 0x%x "
+					    "diverges(%016llx) on subtractive "
+					    "boundary(%016llx). Disabled\n",
+					    SAS_ADDR(dev->sas_addr), i,
+					    SAS_ADDR(phy->attached_sas_addr),
+					    SAS_ADDR(sub_sas_addr));
+				sas_ex_disable_phy(dev, i);
+			}
+		}
+	}
+	return 0;
+}
+
+static inline void sas_print_parent_topology_bug(struct domain_device *child,
+						 struct ex_phy *parent_phy,
+						 struct ex_phy *child_phy)
+{
+	static const char ra_char[] = {
+		[DIRECT_ROUTING] = 'D',
+		[SUBTRACTIVE_ROUTING] = 'S',
+		[TABLE_ROUTING] = 'T',
+	};
+	static const char *ex_type[] = {
+		[EDGE_DEV] = "edge",
+		[FANOUT_DEV] = "fanout",
+	};
+	struct domain_device *parent = child->parent;
+
+	sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x "
+		   "has %c:%c routing link!\n",
+
+		   ex_type[parent->dev_type],
+		   SAS_ADDR(parent->sas_addr),
+		   parent_phy->phy_id,
+
+		   ex_type[child->dev_type],
+		   SAS_ADDR(child->sas_addr),
+		   child_phy->phy_id,
+
+		   ra_char[parent_phy->routing_attr],
+		   ra_char[child_phy->routing_attr]);
+}
+
+static inline int sas_check_eeds(struct domain_device *child,
+				 struct ex_phy *parent_phy,
+				 struct ex_phy *child_phy)
+{
+	int res = 0;
+	struct domain_device *parent = child->parent;
+
+	if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
+		res = -ENODEV;
+		SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx "
+			    "phy S:0x%x, while there is a fanout ex %016llx\n",
+			    SAS_ADDR(parent->sas_addr),
+			    parent_phy->phy_id,
+			    SAS_ADDR(child->sas_addr),
+			    child_phy->phy_id,
+			    SAS_ADDR(parent->port->disc.fanout_sas_addr));
+	} else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
+		memcpy(parent->port->disc.eeds_a, parent->sas_addr,
+		       SAS_ADDR_SIZE);
+		memcpy(parent->port->disc.eeds_b, child->sas_addr,
+		       SAS_ADDR_SIZE);
+	} else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
+		    SAS_ADDR(parent->sas_addr)) ||
+		   (SAS_ADDR(parent->port->disc.eeds_a) ==
+		    SAS_ADDR(child->sas_addr)))
+		   &&
+		   ((SAS_ADDR(parent->port->disc.eeds_b) ==
+		     SAS_ADDR(parent->sas_addr)) ||
+		    (SAS_ADDR(parent->port->disc.eeds_b) ==
+		     SAS_ADDR(child->sas_addr))))
+		;
+	else {
+		res = -ENODEV;
+		SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx "
+			    "phy 0x%x link forms a third EEDS!\n",
+			    SAS_ADDR(parent->sas_addr),
+			    parent_phy->phy_id,
+			    SAS_ADDR(child->sas_addr),
+			    child_phy->phy_id);
+	}
+
+	return res;
+}
+
+/* Here we spill over 80 columns.  It is intentional.
+ */
+static int sas_check_parent_topology(struct domain_device *child)
+{
+	struct expander_device *child_ex = &child->ex_dev;
+	struct expander_device *parent_ex;
+	int i;
+	int res = 0;
+
+	if (!child->parent)
+		return 0;
+
+	if (child->parent->dev_type != EDGE_DEV &&
+	    child->parent->dev_type != FANOUT_DEV)
+		return 0;
+
+	parent_ex = &child->parent->ex_dev;
+
+	for (i = 0; i < parent_ex->num_phys; i++) {
+		struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
+		struct ex_phy *child_phy;
+
+		if (parent_phy->phy_state == PHY_VACANT ||
+		    parent_phy->phy_state == PHY_NOT_PRESENT)
+			continue;
+
+		if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
+			continue;
+
+		child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
+
+		switch (child->parent->dev_type) {
+		case EDGE_DEV:
+			if (child->dev_type == FANOUT_DEV) {
+				if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
+				    child_phy->routing_attr != TABLE_ROUTING) {
+					sas_print_parent_topology_bug(child, parent_phy, child_phy);
+					res = -ENODEV;
+				}
+			} else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+				if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+					res = sas_check_eeds(child, parent_phy, child_phy);
+				} else if (child_phy->routing_attr != TABLE_ROUTING) {
+					sas_print_parent_topology_bug(child, parent_phy, child_phy);
+					res = -ENODEV;
+				}
+			} else if (parent_phy->routing_attr == TABLE_ROUTING &&
+				   child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+				sas_print_parent_topology_bug(child, parent_phy, child_phy);
+				res = -ENODEV;
+			}
+			break;
+		case FANOUT_DEV:
+			if (parent_phy->routing_attr != TABLE_ROUTING ||
+			    child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+				sas_print_parent_topology_bug(child, parent_phy, child_phy);
+				res = -ENODEV;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	return res;
+}
+
+#define RRI_REQ_SIZE  16
+#define RRI_RESP_SIZE 44
+
+static int sas_configure_present(struct domain_device *dev, int phy_id,
+				 u8 *sas_addr, int *index, int *present)
+{
+	int i, res = 0;
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+	u8 *rri_req;
+	u8 *rri_resp;
+
+	*present = 0;
+	*index = 0;
+
+	rri_req = alloc_smp_req(RRI_REQ_SIZE);
+	if (!rri_req)
+		return -ENOMEM;
+
+	rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
+	if (!rri_resp) {
+		kfree(rri_req);
+		return -ENOMEM;
+	}
+
+	rri_req[1] = SMP_REPORT_ROUTE_INFO;
+	rri_req[9] = phy_id;
+
+	for (i = 0; i < ex->max_route_indexes ; i++) {
+		*(__be16 *)(rri_req+6) = cpu_to_be16(i);
+		res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
+				       RRI_RESP_SIZE);
+		if (res)
+			goto out;
+		res = rri_resp[2];
+		if (res == SMP_RESP_NO_INDEX) {
+			SAS_DPRINTK("overflow of indexes: dev %016llx "
+				    "phy 0x%x index 0x%x\n",
+				    SAS_ADDR(dev->sas_addr), phy_id, i);
+			goto out;
+		} else if (res != SMP_RESP_FUNC_ACC) {
+			SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
+				    "result 0x%x\n", __FUNCTION__,
+				    SAS_ADDR(dev->sas_addr), phy_id, i, res);
+			goto out;
+		}
+		if (SAS_ADDR(sas_addr) != 0) {
+			if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
+				*index = i;
+				if ((rri_resp[12] & 0x80) == 0x80)
+					*present = 0;
+				else
+					*present = 1;
+				goto out;
+			} else if (SAS_ADDR(rri_resp+16) == 0) {
+				*index = i;
+				*present = 0;
+				goto out;
+			}
+		} else if (SAS_ADDR(rri_resp+16) == 0 &&
+			   phy->last_da_index < i) {
+			phy->last_da_index = i;
+			*index = i;
+			*present = 0;
+			goto out;
+		}
+	}
+	res = -1;
+out:
+	kfree(rri_req);
+	kfree(rri_resp);
+	return res;
+}
+
+#define CRI_REQ_SIZE  44
+#define CRI_RESP_SIZE  8
+
+static int sas_configure_set(struct domain_device *dev, int phy_id,
+			     u8 *sas_addr, int index, int include)
+{
+	int res;
+	u8 *cri_req;
+	u8 *cri_resp;
+
+	cri_req = alloc_smp_req(CRI_REQ_SIZE);
+	if (!cri_req)
+		return -ENOMEM;
+
+	cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
+	if (!cri_resp) {
+		kfree(cri_req);
+		return -ENOMEM;
+	}
+
+	cri_req[1] = SMP_CONF_ROUTE_INFO;
+	*(__be16 *)(cri_req+6) = cpu_to_be16(index);
+	cri_req[9] = phy_id;
+	if (SAS_ADDR(sas_addr) == 0 || !include)
+		cri_req[12] |= 0x80;
+	memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
+
+	res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
+			       CRI_RESP_SIZE);
+	if (res)
+		goto out;
+	res = cri_resp[2];
+	if (res == SMP_RESP_NO_INDEX) {
+		SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x "
+			    "index 0x%x\n",
+			    SAS_ADDR(dev->sas_addr), phy_id, index);
+	}
+out:
+	kfree(cri_req);
+	kfree(cri_resp);
+	return res;
+}
+
+static inline int sas_configure_phy(struct domain_device *dev, int phy_id,
+				    u8 *sas_addr, int include)
+{
+	int index;
+	int present;
+	int res;
+
+	res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
+	if (res)
+		return res;
+	if (include ^ present)
+		return sas_configure_set(dev, phy_id, sas_addr, index,include);
+
+	return res;
+}
+
+/**
+ * sas_configure_parent -- configure routing table of parent
+ * parent: parent expander
+ * child: child expander
+ * sas_addr: SAS port identifier of device directly attached to child
+ */
+static int sas_configure_parent(struct domain_device *parent,
+				struct domain_device *child,
+				u8 *sas_addr, int include)
+{
+	struct expander_device *ex_parent = &parent->ex_dev;
+	int res = 0;
+	int i;
+
+	if (parent->parent) {
+		res = sas_configure_parent(parent->parent, parent, sas_addr,
+					   include);
+		if (res)
+			return res;
+	}
+
+	if (ex_parent->conf_route_table == 0) {
+		SAS_DPRINTK("ex %016llx has self-configuring routing table\n",
+			    SAS_ADDR(parent->sas_addr));
+		return 0;
+	}
+
+	for (i = 0; i < ex_parent->num_phys; i++) {
+		struct ex_phy *phy = &ex_parent->ex_phy[i];
+
+		if ((phy->routing_attr == TABLE_ROUTING) &&
+		    (SAS_ADDR(phy->attached_sas_addr) ==
+		     SAS_ADDR(child->sas_addr))) {
+			res = sas_configure_phy(parent, i, sas_addr, include);
+			if (res)
+				return res;
+		}
+	}
+
+	return res;
+}
+
+/**
+ * sas_configure_routing -- configure routing
+ * dev: expander device
+ * sas_addr: port identifier of device directly attached to the expander device
+ */
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
+{
+	if (dev->parent)
+		return sas_configure_parent(dev->parent, dev, sas_addr, 1);
+	return 0;
+}
+
+static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr)
+{
+	if (dev->parent)
+		return sas_configure_parent(dev->parent, dev, sas_addr, 0);
+	return 0;
+}
+
+#define SMP_BIN_ATTR_NAME "smp_portal"
+
+static void sas_ex_smp_hook(struct domain_device *dev)
+{
+	struct expander_device *ex_dev = &dev->ex_dev;
+	struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
+
+	memset(bin_attr, 0, sizeof(*bin_attr));
+
+	bin_attr->attr.name = SMP_BIN_ATTR_NAME;
+	bin_attr->attr.owner = THIS_MODULE;
+	bin_attr->attr.mode = 0600;
+
+	bin_attr->size = 0;
+	bin_attr->private = NULL;
+	bin_attr->read = smp_portal_read;
+	bin_attr->write= smp_portal_write;
+	bin_attr->mmap = NULL;
+
+	ex_dev->smp_portal_pid = -1;
+	init_MUTEX(&ex_dev->smp_sema);
+}
+
+/**
+ * sas_discover_expander -- expander discovery
+ * @ex: pointer to expander domain device
+ *
+ * See comment in sas_discover_sata().
+ */
+static int sas_discover_expander(struct domain_device *dev)
+{
+	int res;
+
+	res = sas_notify_lldd_dev_found(dev);
+	if (res)
+		return res;
+
+	res = sas_ex_general(dev);
+	if (res)
+		goto out_err;
+	res = sas_ex_manuf_info(dev);
+	if (res)
+		goto out_err;
+
+	res = sas_expander_discover(dev);
+	if (res) {
+		SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n",
+			    SAS_ADDR(dev->sas_addr), res);
+		goto out_err;
+	}
+
+	sas_check_ex_subtractive_boundary(dev);
+	res = sas_check_parent_topology(dev);
+	if (res)
+		goto out_err;
+	sas_ex_smp_hook(dev);
+	sas_kobj_set(dev);
+	return 0;
+out_err:
+	sas_notify_lldd_dev_gone(dev);
+	return res;
+}
+
+static int sas_ex_level_discovery(struct sas_port *port, const int level)
+{
+	int res = 0;
+	struct domain_device *dev;
+
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		if (dev->dev_type == EDGE_DEV ||
+		    dev->dev_type == FANOUT_DEV) {
+			struct expander_device *ex = &dev->ex_dev;
+
+			if (level == ex->level)
+				res = sas_ex_discover_devices(dev, -1);
+		}
+	}
+
+	return res;
+}
+
+static int sas_ex_bfs_disc(struct sas_port *port)
+{
+	int res;
+	int level;
+
+	do {
+		level = port->disc.max_level;
+		res = sas_ex_level_discovery(port, level);
+		mb();
+	} while (level < port->disc.max_level);
+
+	return res;
+}
+
+int sas_discover_root_expander(struct domain_device *dev)
+{
+	int res;
+
+	dev->ex_dev.level = dev->port->disc.max_level; /* 0 */
+	res = sas_discover_expander(dev);
+	if (!res)
+		sas_ex_bfs_disc(dev->port);
+
+	return res;
+}
+
+void sas_init_ex_attr(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ex_attrs)-1; i++)
+		ex_dev_attrs[i] = &ex_attrs[i].attr;
+	ex_dev_attrs[i] = NULL;
+}
+
+/* ---------- Domain revalidation ---------- */
+
+static int sas_get_phy_discover(struct domain_device *dev,
+				int phy_id, struct smp_resp *disc_resp)
+{
+	int res;
+	u8 *disc_req;
+
+	disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+	if (!disc_req)
+		return -ENOMEM;
+
+	disc_req[1] = SMP_DISCOVER;
+	disc_req[9] = phy_id;
+
+	res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+			       disc_resp, DISCOVER_RESP_SIZE);
+	if (res)
+		goto out;
+	else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
+		res = disc_resp->result;
+		goto out;
+	}
+out:
+	kfree(disc_req);
+	return res;
+}
+
+static int sas_get_phy_change_count(struct domain_device *dev,
+				    int phy_id, int *pcc)
+{
+	int res;
+	struct smp_resp *disc_resp;
+
+	disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+	if (!disc_resp)
+		return -ENOMEM;
+
+	res = sas_get_phy_discover(dev, phy_id, disc_resp);
+	if (!res)
+		*pcc = disc_resp->disc.change_count;
+
+	kfree(disc_resp);
+	return res;
+}
+
+static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
+					 int phy_id, u8 *attached_sas_addr)
+{
+	int res;
+	struct smp_resp *disc_resp;
+
+	disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+	if (!disc_resp)
+		return -ENOMEM;
+
+	res = sas_get_phy_discover(dev, phy_id, disc_resp);
+	if (!res)
+		memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
+
+	kfree(disc_resp);
+	return res;
+}
+
+static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
+			      int from_phy)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int res = 0;
+	int i;
+
+	for (i = from_phy; i < ex->num_phys; i++) {
+		int phy_change_count;
+
+		res = sas_get_phy_change_count(dev, i, &phy_change_count);
+		if (res)
+			goto out;
+		else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
+			ex->ex_phy[i].phy_change_count = phy_change_count;
+			*phy_id = i;
+			return 0;
+		}
+	}
+out:
+	return res;
+}
+
+static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
+{
+	int res;
+	u8  *rg_req;
+	struct smp_resp  *rg_resp;
+
+	rg_req = alloc_smp_req(RG_REQ_SIZE);
+	if (!rg_req)
+		return -ENOMEM;
+
+	rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+	if (!rg_resp) {
+		kfree(rg_req);
+		return -ENOMEM;
+	}
+
+	rg_req[1] = SMP_REPORT_GENERAL;
+
+	res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+			       RG_RESP_SIZE);
+	if (res)
+		goto out;
+	if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+		res = rg_resp->result;
+		goto out;
+	}
+
+	*ecc = be16_to_cpu(rg_resp->rg.change_count);
+out:
+	kfree(rg_resp);
+	kfree(rg_req);
+	return res;
+}
+
+static int sas_find_bcast_dev(struct domain_device *dev,
+			      struct domain_device **src_dev)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	int ex_change_count = -1;
+	int res;
+
+	res = sas_get_ex_change_count(dev, &ex_change_count);
+	if (res)
+		goto out;
+	if (ex_change_count != -1 &&
+	    ex_change_count != ex->ex_change_count) {
+		*src_dev = dev;
+		ex->ex_change_count = ex_change_count;
+	} else {
+		struct domain_device *ch;
+
+		list_for_each_entry(ch, &ex->children, siblings) {
+			if (ch->dev_type == EDGE_DEV ||
+			    ch->dev_type == FANOUT_DEV) {
+				res = sas_find_bcast_dev(ch, src_dev);
+				if (src_dev)
+					return res;
+			}
+		}
+	}
+out:
+	return res;
+}
+
+static void sas_unregister_ex_tree(struct domain_device *dev)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct domain_device *child, *n;
+
+	list_for_each_entry_safe(child, n, &ex->children, siblings) {
+		if (child->dev_type == EDGE_DEV ||
+		    child->dev_type == FANOUT_DEV)
+			sas_unregister_ex_tree(child);
+		else
+			sas_unregister_dev(child);
+	}
+	sas_unregister_dev(dev);
+}
+
+static void sas_unregister_devs_sas_addr(struct domain_device *parent,
+					 int phy_id)
+{
+	struct expander_device *ex_dev = &parent->ex_dev;
+	struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
+	struct domain_device *child, *n;
+
+	list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
+		if (SAS_ADDR(child->sas_addr) ==
+		    SAS_ADDR(phy->attached_sas_addr)) {
+			if (child->dev_type == EDGE_DEV ||
+			    child->dev_type == FANOUT_DEV)
+				sas_unregister_ex_tree(child);
+			else
+				sas_unregister_dev(child);
+			break;
+		}
+	}
+	sas_disable_routing(parent, phy->attached_sas_addr);
+	memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+}
+
+static int sas_discover_bfs_by_root_level(struct domain_device *root,
+					  const int level)
+{
+	struct expander_device *ex_root = &root->ex_dev;
+	struct domain_device *child;
+	int res = 0;
+
+	list_for_each_entry(child, &ex_root->children, siblings) {
+		if (child->dev_type == EDGE_DEV ||
+		    child->dev_type == FANOUT_DEV) {
+			struct expander_device *ex = &child->ex_dev;
+
+			if (level > ex->level)
+				res = sas_discover_bfs_by_root_level(child,
+								     level);
+			else if (level == ex->level)
+				res = sas_ex_discover_devices(child, -1);
+		}
+	}
+	return res;
+}
+
+static int sas_discover_bfs_by_root(struct domain_device *dev)
+{
+	int res;
+	int level = dev->ex_dev.level+1;
+
+	res = sas_ex_discover_devices(dev, -1);
+	if (res)
+		goto out;
+	do {
+		res = sas_discover_bfs_by_root_level(dev, level);
+		mb();
+		level += 1;
+	} while (level <= dev->port->disc.max_level);
+out:
+	return res;
+}
+
+static inline int sas_discover_new(struct domain_device *dev, int phy_id)
+{
+	struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
+	struct domain_device *child;
+	int res;
+
+	SAS_DPRINTK("ex %016llx phy%d new device attached\n",
+		    SAS_ADDR(dev->sas_addr), phy_id);
+	res = sas_ex_phy_discover(dev, phy_id);
+	if (res)
+		goto out;
+	res = sas_ex_discover_devices(dev, phy_id);
+	if (res)
+		goto out;
+	list_for_each_entry(child, &dev->ex_dev.children, siblings) {
+		if (SAS_ADDR(child->sas_addr) ==
+		    SAS_ADDR(ex_phy->attached_sas_addr)) {
+			if (child->dev_type == EDGE_DEV ||
+			    child->dev_type == FANOUT_DEV)
+				res = sas_discover_bfs_by_root(child);
+			break;
+		}
+	}
+out:
+	return res;
+}
+
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *phy = &ex->ex_phy[phy_id];
+	u8 attached_sas_addr[8];
+	int res;
+
+	res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
+	switch (res) {
+	case SMP_RESP_NO_PHY:
+		phy->phy_state = PHY_NOT_PRESENT;
+		sas_unregister_devs_sas_addr(dev, phy_id);
+		goto out; break;
+	case SMP_RESP_PHY_VACANT:
+		phy->phy_state = PHY_VACANT;
+		sas_unregister_devs_sas_addr(dev, phy_id);
+		goto out; break;
+	case SMP_RESP_FUNC_ACC:
+		break;
+	}
+
+	if (SAS_ADDR(attached_sas_addr) == 0) {
+		phy->phy_state = PHY_EMPTY;
+		sas_unregister_devs_sas_addr(dev, phy_id);
+	} else if (SAS_ADDR(attached_sas_addr) ==
+		   SAS_ADDR(phy->attached_sas_addr)) {
+		SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
+			    SAS_ADDR(dev->sas_addr), phy_id);
+	} else
+		res = sas_discover_new(dev, phy_id);
+out:
+	return res;
+}
+
+static int sas_rediscover(struct domain_device *dev, const int phy_id)
+{
+	struct expander_device *ex = &dev->ex_dev;
+	struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
+	int res = 0;
+	int i;
+
+	SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
+		    SAS_ADDR(dev->sas_addr), phy_id);
+
+	if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
+		for (i = 0; i < ex->num_phys; i++) {
+			struct ex_phy *phy = &ex->ex_phy[i];
+
+			if (i == phy_id)
+				continue;
+			if (SAS_ADDR(phy->attached_sas_addr) ==
+			    SAS_ADDR(changed_phy->attached_sas_addr)) {
+				SAS_DPRINTK("phy%d part of wide port with "
+					    "phy%d\n", phy_id, i);
+				goto out;
+			}
+		}
+		res = sas_rediscover_dev(dev, phy_id);
+	} else
+		res = sas_discover_new(dev, phy_id);
+out:
+	return res;
+}
+
+/**
+ * sas_revalidate_domain -- revalidate the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered.  Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+int sas_ex_revalidate_domain(struct domain_device *port_dev)
+{
+	int res;
+	struct domain_device *dev = NULL;
+
+	res = sas_find_bcast_dev(port_dev, &dev);
+	if (res)
+		goto out;
+	if (dev) {
+		struct expander_device *ex = &dev->ex_dev;
+		int i = 0, phy_id;
+
+		do {
+			phy_id = -1;
+			res = sas_find_bcast_phy(dev, &phy_id, i);
+			if (phy_id == -1)
+				break;
+			res = sas_rediscover(dev, phy_id);
+			i = phy_id + 1;
+		} while (i < ex->num_phys);
+	}
+out:
+	return res;
+}
+
+/* ---------- SMP portal ---------- */
+
+static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
+				size_t size)
+{
+	struct domain_device *dev = to_dom_device(kobj);
+	struct expander_device *ex = &dev->ex_dev;
+
+	if (offs != 0)
+		return -EFBIG;
+	else if (size == 0)
+		return 0;
+
+	down_interruptible(&ex->smp_sema);
+	if (ex->smp_req)
+		kfree(ex->smp_req);
+	ex->smp_req = kzalloc(size, GFP_USER);
+	if (!ex->smp_req) {
+		up(&ex->smp_sema);
+		return -ENOMEM;
+	}
+	memcpy(ex->smp_req, buf, size);
+	ex->smp_req_size = size;
+	ex->smp_portal_pid = current->pid;
+	up(&ex->smp_sema);
+
+	return size;
+}
+
+static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
+			       size_t size)
+{
+	struct domain_device *dev = to_dom_device(kobj);
+	struct expander_device *ex = &dev->ex_dev;
+	u8 *smp_resp;
+	int res = -EINVAL;
+
+	/* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
+	 *  it should be 0.
+	 */
+
+	down_interruptible(&ex->smp_sema);
+	if (!ex->smp_req || ex->smp_portal_pid != current->pid)
+		goto out;
+
+	res = 0;
+	if (size == 0)
+		goto out;
+
+	res = -ENOMEM;
+	smp_resp = alloc_smp_resp(size);
+	if (!smp_resp)
+		goto out;
+	res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
+			       smp_resp, size);
+	if (!res) {
+		memcpy(buf, smp_resp, size);
+		res = size;
+	}
+
+	kfree(smp_resp);
+out:
+	kfree(ex->smp_req);
+	ex->smp_req = NULL;
+	ex->smp_req_size = 0;
+	ex->smp_portal_pid = -1;
+	up(&ex->smp_sema);
+	return res;
+}
diff -urN oldtree/drivers/scsi/sas/sas_init.c newtree/drivers/scsi/sas/sas_init.c
--- oldtree/drivers/scsi/sas/sas_init.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_init.c	2006-04-01 05:35:45.927490250 -0500
@@ -0,0 +1,230 @@
+/*
+ * Serial Attached SCSI (SAS) Transport Layer initialization
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_init.c#45 $
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi_host.h>
+
+#include "sas_internal.h"
+#include <scsi/sas/sas_task.h>
+
+kmem_cache_t *sas_task_cache;
+
+/* ---------- HA events ---------- */
+
+void sas_hae_reset(struct sas_ha_struct *sas_ha)
+{
+	;
+}
+
+/* ---------- HA attributes ---------- */
+
+static ssize_t sas_ha_name_show(struct sas_ha_struct *sas_ha, char *buf)
+{
+	if (sas_ha->sas_ha_name)
+		return sprintf(buf, "%s\n", sas_ha->sas_ha_name);
+	return 0;
+}
+
+static ssize_t sas_ha_addr_show(struct sas_ha_struct *sas_ha, char *buf)
+{
+	return sprintf(buf, "%llx\n", SAS_ADDR(sas_ha->sas_addr));
+}
+
+/* ---------- SAS HA Class ---------- */
+
+#define to_sas_ha(_obj) container_of(to_kset(_obj),struct sas_ha_struct,ha_kset)
+#define to_ha_attr(_attr) container_of(_attr, struct ha_attribute, attr)
+
+struct ha_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct sas_ha_struct *sas_ha, char *);
+	ssize_t (*store)(struct sas_ha_struct *sas_ha,const char *,size_t len);
+};
+
+static ssize_t ha_show_attr(struct kobject *kobj,
+		     struct attribute *attr,
+		     char *page)
+{
+	ssize_t ret = 0;
+	struct sas_ha_struct *sas_ha = to_sas_ha(kobj);
+	struct ha_attribute *ha_attr = to_ha_attr(attr);
+
+	if (ha_attr->show)
+		ret = ha_attr->show(sas_ha, page);
+	return ret;
+}
+
+static struct ha_attribute ha_attrs[] = {
+	__ATTR(ha_name, 0444, sas_ha_name_show, NULL),
+	__ATTR(device_name, 0444, sas_ha_addr_show, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *def_attrs[ARRAY_SIZE(ha_attrs)];
+
+static struct sysfs_ops ha_sysfs_ops = {
+	.show = ha_show_attr,
+};
+
+static struct kobj_type ha_ktype = {
+	.sysfs_ops = &ha_sysfs_ops,
+	.default_attrs = def_attrs,
+};
+
+/* This is our "root". */
+static struct kset sas_kset = {
+	.kobj = { .name = "sas" },
+	.ktype = &ha_ktype,	  /* children are of this type */
+};
+
+int sas_register_ha(struct sas_ha_struct *sas_ha,
+		    const struct scsi_host_template *scsi_ht)
+{
+	int i, error = 0;
+
+	spin_lock_init(&sas_ha->phy_port_lock);
+	sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
+
+	if (sas_ha->lldd_queue_size == 0)
+		sas_ha->lldd_queue_size = 1;
+	else if (sas_ha->lldd_queue_size == -1)
+		sas_ha->lldd_queue_size = 128; /* Sanity */
+
+	error = sas_register_scsi_host(sas_ha, scsi_ht);
+	if (error) {
+		printk(KERN_NOTICE "couldn't register scsi host\n");
+		return error;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(def_attrs)-1; i++)
+		def_attrs[i] = &ha_attrs[i].attr;
+	def_attrs[i] = NULL;
+
+	/* make sas/ appear */
+	sas_kset.kobj.parent = &sas_ha->core.shost->shost_gendev.kobj;
+	kset_register(&sas_kset);
+
+	/* make sas/ha/ appear */
+	kobject_set_name(&sas_ha->ha_kset.kobj, "%s", "ha");
+	sas_ha->ha_kset.kobj.kset = &sas_kset; /* parent */
+	sas_ha->ha_kset.kobj.ktype = sas_kset.ktype;
+	kset_register(&sas_ha->ha_kset);
+
+	error = sas_register_phys(sas_ha);
+	if (error) {
+		printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
+		goto Undo;
+	}
+
+	error = sas_register_ports(sas_ha);
+	if (error) {
+		printk(KERN_NOTICE "couldn't register sas ports:%d\n", error);
+		goto Undo_phys;
+	}
+
+	error = sas_start_event_thread(sas_ha);
+	if (error) {
+		printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
+		goto Undo_ports;
+	}
+
+	if (sas_ha->lldd_max_execute_num > 1) {
+		error = sas_init_queue(sas_ha);
+		if (!error)
+			kobject_register(&sas_ha->core.scsi_core_obj);
+		else {
+			printk(KERN_NOTICE "couldn't start queue thread:%d, "
+			       "running in direct mode\n", error);
+			sas_ha->lldd_max_execute_num = 1;
+		}
+	}
+
+	return 0;
+
+Undo_ports:
+	sas_unregister_ports(sas_ha);
+Undo_phys:
+	sas_unregister_phys(sas_ha);
+Undo:
+	kset_unregister(&sas_ha->ha_kset);
+	kset_unregister(&sas_kset);
+	sas_unregister_scsi_host(sas_ha);
+
+	return error;
+}
+
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+	sas_unregister_devices(sas_ha);
+
+	if (sas_ha->lldd_max_execute_num > 1) {
+		kobject_unregister(&sas_ha->core.scsi_core_obj);
+		sas_shutdown_queue(sas_ha);
+	}
+
+	sas_kill_event_thread(sas_ha);
+
+	sas_unregister_ports(sas_ha);
+	sas_unregister_phys(sas_ha);
+
+	kset_unregister(&sas_ha->ha_kset);
+	kset_unregister(&sas_kset);
+
+	sas_unregister_scsi_host(sas_ha);
+
+	return 0;
+}
+
+/* ---------- SAS Class register/unregister ---------- */
+
+static int __init sas_class_init(void)
+{
+	sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
+					   0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!sas_task_cache)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __exit sas_class_exit(void)
+{
+	if (sas_task_cache)
+		kmem_cache_destroy(sas_task_cache);
+}
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION("SAS Transport Layer");
+MODULE_LICENSE("GPL v2");
+
+module_init(sas_class_init);
+module_exit(sas_class_exit);
+
+EXPORT_SYMBOL_GPL(sas_register_ha);
+EXPORT_SYMBOL_GPL(sas_unregister_ha);
diff -urN oldtree/drivers/scsi/sas/sas_internal.h newtree/drivers/scsi/sas/sas_internal.h
--- oldtree/drivers/scsi/sas/sas_internal.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_internal.h	2006-04-01 05:35:45.927490250 -0500
@@ -0,0 +1,80 @@
+/*
+ * Serial Attached SCSI (SAS) class internal header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_internal.h#35 $
+ */
+
+#ifndef _SAS_INTERNAL_H_
+#define _SAS_INTERNAL_H_
+
+#include <scsi/sas/sas_class.h>
+
+#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+
+#ifdef SAS_DEBUG
+#define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+#else
+#define SAS_DPRINTK(fmt, ...)
+#endif
+
+int sas_show_class(enum sas_class class, char *buf);
+int sas_show_proto(enum sas_proto proto, char *buf);
+int sas_show_linkrate(enum sas_phy_linkrate linkrate, char *buf);
+int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
+
+int  sas_register_phys(struct sas_ha_struct *sas_ha);
+void sas_unregister_phys(struct sas_ha_struct *sas_ha);
+
+int  sas_register_ports(struct sas_ha_struct *sas_ha);
+void sas_unregister_ports(struct sas_ha_struct *sas_ha);
+
+extern int  sas_register_scsi_host(struct sas_ha_struct *,
+				   const struct scsi_host_template *);
+void sas_unregister_scsi_host(struct sas_ha_struct *sas_ha);
+
+int  sas_start_event_thread(struct sas_ha_struct *sas_ha);
+void sas_kill_event_thread(struct sas_ha_struct *sas_ha);
+
+int  sas_init_queue(struct sas_ha_struct *sas_ha);
+void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
+
+void sas_phye_loss_of_signal(struct sas_phy *phy);
+void sas_phye_oob_done(struct sas_phy *phy);
+void sas_phye_oob_error(struct sas_phy *phy);
+void sas_phye_spinup_hold(struct sas_phy *phy);
+
+void sas_deform_port(struct sas_phy *phy);
+
+void sas_porte_bytes_dmaed(struct sas_phy *phy);
+void sas_porte_broadcast_rcvd(struct sas_phy *phy);
+void sas_porte_link_reset_err(struct sas_phy *phy);
+void sas_porte_timer_event(struct sas_phy *phy);
+void sas_porte_hard_reset(struct sas_phy *phy);
+
+int  sas_reserve_free_id(struct sas_port *port);
+void sas_reserve_scsi_id(struct sas_port *port, int id);
+void sas_release_scsi_id(struct sas_port *port, int id);
+
+void sas_hae_reset(struct sas_ha_struct *sas_ha);
+
+#endif /* _SAS_INTERNAL_H_ */
diff -urN oldtree/drivers/scsi/sas/sas_phy.c newtree/drivers/scsi/sas/sas_phy.c
--- oldtree/drivers/scsi/sas/sas_phy.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_phy.c	2006-04-01 05:35:45.927490250 -0500
@@ -0,0 +1,307 @@
+/*
+ * Serial Attached SCSI (SAS) Phy class
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_phy.c#38 $
+ */
+
+#include "sas_internal.h"
+
+/* ---------- Phy events ---------- */
+
+void sas_phye_loss_of_signal(struct sas_phy *phy)
+{
+	phy->error = 0;
+	sas_deform_port(phy);
+}
+
+void sas_phye_oob_done(struct sas_phy *phy)
+{
+	phy->error = 0;
+}
+
+void sas_phye_oob_error(struct sas_phy *phy)
+{
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_port *port = phy->port;
+
+	sas_deform_port(phy);
+
+	if (!port && phy->enabled && sas_ha->lldd_control_phy) {
+		phy->error++;
+		switch (phy->error) {
+		case 1:
+		case 2:
+			sas_ha->lldd_control_phy(phy, PHY_FUNC_HARD_RESET);
+			break;
+		case 3:
+		default:
+			phy->error = 0;
+			phy->enabled = 0;
+			sas_ha->lldd_control_phy(phy, PHY_FUNC_DISABLE);
+			break;
+		}
+	}
+}
+
+void sas_phye_spinup_hold(struct sas_phy *phy)
+{
+	struct sas_ha_struct *sas_ha = phy->ha;
+
+	phy->error = 0;
+	sas_ha->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD);
+}
+
+/* ---------- Phy attributes ---------- */
+
+static ssize_t sas_phy_id_show(struct sas_phy *phy, char *buf)
+{
+	return sprintf(buf, "%d\n", phy->id);
+}
+
+static ssize_t sas_phy_enabled_show(struct sas_phy *phy, char *buf)
+{
+	return sprintf(buf, "%d\n", phy->enabled);
+}
+
+static ssize_t sas_phy_enabled_store(struct sas_phy *phy, const char *buf,
+				     size_t size)
+{
+	if (size > 0) {
+		if (buf[0] == '1')
+			phy->ha->lldd_control_phy(phy, PHY_FUNC_LINK_RESET);
+	}
+	return size;
+}
+
+static ssize_t sas_phy_class_show(struct sas_phy *phy, char *buf)
+{
+	if (!phy->enabled)
+		return 0;
+	return sas_show_class(phy->class, buf);
+}
+
+static ssize_t sas_phy_iproto_show(struct sas_phy *phy, char *page)
+{
+	if (!phy->enabled)
+		return 0;
+	return sas_show_proto(phy->iproto, page);
+}
+
+static ssize_t sas_phy_tproto_show(struct sas_phy *phy, char *page)
+{
+	if (!phy->enabled)
+		return 0;
+	return sas_show_proto(phy->tproto, page);
+}
+
+static ssize_t sas_phy_type_show(struct sas_phy *phy, char *buf)
+{
+	static const char *phy_type_str[] = {
+		[PHY_TYPE_PHYSICAL] = "physical",
+		[PHY_TYPE_VIRTUAL] = "virtual",
+	};
+	if (!phy->enabled)
+		return 0;
+	return sprintf(buf, "%s\n", phy_type_str[phy->type]);
+}
+
+static ssize_t sas_phy_role_show(struct sas_phy *phy, char *page)
+{
+	static const char *phy_role_str[] = {
+		[PHY_ROLE_NONE] = "none",
+		[PHY_ROLE_TARGET] = "target",
+		[PHY_ROLE_INITIATOR] = "initiator",
+	};
+	int  v;
+	char *buf = page;
+
+	if (!phy->enabled)
+		return 0;
+
+	if (phy->role == PHY_ROLE_NONE)
+		return sprintf(buf, "%s\n", phy_role_str[PHY_ROLE_NONE]);
+
+	for (v = 1; v <= PHY_ROLE_INITIATOR; v <<= 1) {
+		if (v & phy->role) {
+			buf += sprintf(buf, "%s", phy_role_str[v]);
+			if (phy->role & ~((v<<1)-1))
+				buf += sprintf(buf, "|");
+			else
+				buf += sprintf(buf, "\n");
+		}
+	}
+	return buf-page;
+}
+
+static ssize_t sas_phy_linkrate_show(struct sas_phy *phy, char *buf)
+{
+	if (!phy->enabled)
+		return 0;
+	return sas_show_linkrate(phy->linkrate, buf);
+}
+
+static ssize_t sas_phy_addr_show(struct sas_phy *phy, char *buf)
+{
+	if (!phy->enabled)
+		return 0;
+	return sprintf(buf, "%llx\n", SAS_ADDR(phy->sas_addr));
+}
+
+static ssize_t sas_phy_oob_mode_show(struct sas_phy *phy, char *buf)
+{
+	if (!phy->enabled)
+		return 0;
+	return sas_show_oob_mode(phy->oob_mode, buf);
+}
+
+struct phy_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct sas_phy *phy, char *);
+	ssize_t (*store)(struct sas_phy *phy, const char *, size_t);
+};
+
+static struct phy_attribute phy_attrs[] = {
+	/* port is a symlink */
+	__ATTR(id, 0444, sas_phy_id_show, NULL),
+	__ATTR(enabled, 0644, sas_phy_enabled_show, sas_phy_enabled_store),
+	__ATTR(class, 0444, sas_phy_class_show, NULL),
+	__ATTR(iproto, 0444, sas_phy_iproto_show, NULL),
+	__ATTR(tproto, 0444, sas_phy_tproto_show, NULL),
+	__ATTR(type, 0444, sas_phy_type_show, NULL),
+	__ATTR(role, 0444, sas_phy_role_show, NULL),
+	__ATTR(linkrate, 0444, sas_phy_linkrate_show, NULL),
+	__ATTR(sas_addr, 0444, sas_phy_addr_show, NULL),
+	__ATTR(oob_mode, 0444, sas_phy_oob_mode_show, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *def_attrs[ARRAY_SIZE(phy_attrs)];
+
+#define to_sas_phy(_obj) container_of(_obj, struct sas_phy, phy_kobj)
+#define to_phy_attr(_attr) container_of(_attr, struct phy_attribute, attr)
+
+static ssize_t phy_show_attr(struct kobject *kobj,
+			     struct attribute *attr,
+			     char *page)
+{
+	ssize_t ret = 0;
+	struct sas_phy *phy = to_sas_phy(kobj);
+	struct phy_attribute *phy_attr = to_phy_attr(attr);
+
+	if (phy_attr->show)
+		ret = phy_attr->show(phy, page);
+	return ret;
+}
+
+static ssize_t phy_store_attr(struct kobject *kobj,
+			      struct attribute *attr,
+			      const char *page, size_t size)
+{
+	ssize_t ret = 0;
+	struct sas_phy *phy = to_sas_phy(kobj);
+	struct phy_attribute *phy_attr = to_phy_attr(attr);
+
+	if (phy_attr->store)
+		ret = phy_attr->store(phy, page, size);
+	return ret;
+}
+
+static struct sysfs_ops phy_sysfs_ops = {
+	.show = phy_show_attr,
+	.store = phy_store_attr,
+};
+
+static struct kobj_type phy_ktype = {
+	.sysfs_ops = &phy_sysfs_ops,
+	.default_attrs = def_attrs,
+};
+
+/* ---------- Phy class registration ---------- */
+
+int sas_register_phys(struct sas_ha_struct *sas_ha)
+{
+	int i, error;
+
+	for (i = 0; i < ARRAY_SIZE(def_attrs)-1; i++)
+		def_attrs[i] = &phy_attrs[i].attr;
+	def_attrs[i] = NULL;
+
+	/* make sas/ha/phys/ appear */
+	kobject_set_name(&sas_ha->phy_kset.kobj, "%s", "phys");
+	sas_ha->phy_kset.kobj.kset = &sas_ha->ha_kset; /* parent */
+	/* we do not inherit the type of the parent */
+	sas_ha->phy_kset.kobj.ktype = NULL;
+	sas_ha->phy_kset.ktype = &phy_ktype;
+	error = kset_register(&sas_ha->phy_kset);
+	if (error)
+		return error;
+
+	/* Now register the phys. */
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		int k;
+		struct sas_phy *phy = sas_ha->sas_phy[i];
+
+		phy->error = 0;
+		INIT_LIST_HEAD(&phy->port_phy_el);
+		INIT_LIST_HEAD(&phy->port_event_list);
+		INIT_LIST_HEAD(&phy->phy_event_list);
+		for (k = 0; k < PORT_NUM_EVENTS; k++) {
+			struct sas_event *ev = &phy->port_events[k];
+			ev->event = k;
+			INIT_LIST_HEAD(&ev->el);
+		}
+		for (k = 0; k < PHY_NUM_EVENTS; k++) {
+			struct sas_event *ev = &phy->phy_events[k];
+			ev->event = k;
+			INIT_LIST_HEAD(&ev->el);
+		}
+		phy->port = NULL;
+		phy->ha = sas_ha;
+		spin_lock_init(&phy->frame_rcvd_lock);
+		spin_lock_init(&phy->sas_prim_lock);
+		phy->frame_rcvd_size = 0;
+
+		kobject_set_name(&phy->phy_kobj, "%d", i);
+		phy->phy_kobj.kset = &sas_ha->phy_kset; /* parent */
+		phy->phy_kobj.ktype = sas_ha->phy_kset.ktype;
+		error = kobject_register(&phy->phy_kobj);
+		if (error)
+			goto unroll;
+	}
+
+	return 0;
+unroll:
+	for (i--; i >= 0; i--)
+		kobject_unregister(&sas_ha->sas_phy[i]->phy_kobj);
+
+	return error;
+}
+
+void sas_unregister_phys(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	for (i = 0; i < sas_ha->num_phys; i++)
+		kobject_unregister(&sas_ha->sas_phy[i]->phy_kobj);
+
+	kset_unregister(&sas_ha->phy_kset);
+}
diff -urN oldtree/drivers/scsi/sas/sas_port.c newtree/drivers/scsi/sas/sas_port.c
--- oldtree/drivers/scsi/sas/sas_port.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_port.c	2006-04-01 05:35:45.927490250 -0500
@@ -0,0 +1,429 @@
+/*
+ * Serial Attached SCSI (SAS) Port class
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_port.c#44 $
+ */
+
+#include "sas_internal.h"
+#include <scsi/sas/sas_discover.h>
+
+/* called only when num_phys increments, afterwards */
+static void sas_create_port_sysfs_links(struct sas_phy *phy)
+{
+	struct sas_port *port = phy->port;
+
+	if (port->num_phys == 1) {
+		kobject_register(&port->port_kobj);
+		kset_register(&port->phy_kset);
+		kset_register(&port->dev_kset);
+	}
+	/* add port->phy link */
+	sysfs_create_link(&port->phy_kset.kobj, &phy->phy_kobj,
+			  kobject_name(&phy->phy_kobj));
+	/* add phy->port link */
+	sysfs_create_link(&phy->phy_kobj, &port->port_kobj, "port");
+}
+
+/* called only when num_phys decrements, just before it does */
+static void sas_remove_port_sysfs_links(struct sas_phy *phy)
+{
+	struct sas_port *port = phy->port;
+
+	/* remove phy->port link */
+	sysfs_remove_link(&phy->phy_kobj, "port");
+	/* remove port to phy link */
+	sysfs_remove_link(&port->phy_kset.kobj, kobject_name(&phy->phy_kobj));
+
+	if (port->num_phys == 1) {
+		kset_unregister(&port->dev_kset);
+		kset_unregister(&port->phy_kset);
+		kobject_unregister(&port->port_kobj);
+	}
+}
+
+/**
+ * sas_form_port -- add this phy to a port
+ * @phy: the phy of interest
+ *
+ * This function adds this phy to an existing port, thus creating a wide
+ * port, or it creates a port and adds the phy to the port.
+ */
+static void sas_form_port(struct sas_phy *phy)
+{
+	int i;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_port *port = phy->port;
+
+	if (port) {
+		if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
+			   SAS_ADDR_SIZE) == 0)
+			sas_deform_port(phy);
+		else {
+			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
+				    __FUNCTION__, phy->id, phy->port->id,
+				    phy->port->num_phys);
+			return;
+		}
+	}
+
+	/* find a port */
+	spin_lock(&sas_ha->phy_port_lock);
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		port = sas_ha->sas_port[i];
+		spin_lock(&port->phy_list_lock);
+		if (*(u64 *) port->sas_addr &&
+		    memcmp(port->attached_sas_addr,
+			   phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
+		    port->num_phys > 0) {
+			/* wide port */
+			SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
+				    port->id);
+			break;
+		} else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
+			memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
+			break;
+		}
+		spin_unlock(&port->phy_list_lock);
+	}
+
+	if (i >= sas_ha->num_phys) {
+		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
+		       __FUNCTION__);
+		spin_unlock(&sas_ha->phy_port_lock);
+		return;
+	}
+
+	/* add the phy to the port */
+	list_add_tail(&phy->port_phy_el, &port->phy_list);
+	phy->port = port;
+	port->num_phys++;
+	port->phy_mask |= (1U << phy->id);
+
+	SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,
+		    port->id, port->phy_mask);
+
+	if (*(u64 *)port->attached_sas_addr == 0) {
+		port->class = phy->class;
+		memcpy(port->attached_sas_addr, phy->attached_sas_addr,
+		       SAS_ADDR_SIZE);
+		port->iproto = phy->iproto;
+		port->tproto = phy->tproto;
+		port->oob_mode = phy->oob_mode;
+		port->linkrate = phy->linkrate;
+	} else
+		port->linkrate = max(port->linkrate, phy->linkrate);
+	spin_unlock(&port->phy_list_lock);
+	spin_unlock(&sas_ha->phy_port_lock);
+
+	if (port->port_dev)
+		port->port_dev->pathways = port->num_phys;
+
+	sas_create_port_sysfs_links(phy);
+	/* Tell the LLDD about this port formation. */
+	if (sas_ha->lldd_port_formed)
+		sas_ha->lldd_port_formed(phy);
+
+	sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
+}
+
+/**
+ * sas_deform_port -- remove this phy from the port it belongs to
+ * @phy: the phy of interest
+ *
+ * This is called when the physical link to the other phy has been
+ * lost (on this phy), in Event thread context. We cannot delay here.
+ */
+void sas_deform_port(struct sas_phy *phy)
+{
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_port *port = phy->port;
+
+	if (!port)
+		return;		  /* done by a phy event */
+
+	if (port->port_dev)
+		port->port_dev->pathways--;
+
+	if (port->num_phys == 1) {
+		init_completion(&port->port_gone_completion);
+		sas_discover_event(port, DISCE_PORT_GONE);
+		wait_for_completion(&port->port_gone_completion);
+	}
+
+	if (sas_ha->lldd_port_deformed)
+		sas_ha->lldd_port_deformed(phy);
+
+	sas_remove_port_sysfs_links(phy);
+
+	spin_lock(&sas_ha->phy_port_lock);
+	spin_lock(&port->phy_list_lock);
+
+	list_del_init(&phy->port_phy_el);
+	phy->port = NULL;
+	port->num_phys--;
+	port->phy_mask &= ~(1U << phy->id);
+
+	if (port->num_phys == 0) {
+		INIT_LIST_HEAD(&port->phy_list);
+		memset(port->sas_addr, 0, SAS_ADDR_SIZE);
+		memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);
+		port->class = 0;
+		port->iproto = 0;
+		port->tproto = 0;
+		port->oob_mode = 0;
+		port->phy_mask = 0;
+	}
+	spin_unlock(&port->phy_list_lock);
+	spin_unlock(&sas_ha->phy_port_lock);
+
+	return;
+}
+
+/* ---------- SAS port events ---------- */
+
+void sas_porte_bytes_dmaed(struct sas_phy *phy)
+{
+	sas_form_port(phy);
+}
+
+void sas_porte_broadcast_rcvd(struct sas_phy *phy)
+{
+	unsigned long flags;
+	u32 prim;
+
+	spin_lock_irqsave(&phy->sas_prim_lock, flags);
+	prim = phy->sas_prim;
+	spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
+
+	SAS_DPRINTK("broadcast received: %d\n", prim);
+	sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
+}
+
+void sas_porte_link_reset_err(struct sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+void sas_porte_timer_event(struct sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+void sas_porte_hard_reset(struct sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+/* ---------- SAS port attributes ---------- */
+
+static ssize_t sas_port_id_show(struct sas_port *port, char *buf)
+{
+	return sprintf(buf, "%d\n", port->id);
+}
+
+static ssize_t sas_port_class_show(struct sas_port *port, char *buf)
+{
+	return sas_show_class(port->class, buf);
+}
+
+static ssize_t sas_port_sas_addr_show(struct sas_port *port, char *buf)
+{
+	return sprintf(buf, "%llx\n", SAS_ADDR(port->sas_addr));
+}
+
+static ssize_t sas_port_attached_sas_addr_show(struct sas_port *port,char *buf)
+{
+	return sprintf(buf, "%llx\n", SAS_ADDR(port->attached_sas_addr));
+}
+
+static ssize_t sas_port_iproto_show(struct sas_port *port, char *buf)
+{
+	return sas_show_proto(port->iproto, buf);
+}
+
+static ssize_t sas_port_tproto_show(struct sas_port *port, char *buf)
+{
+	return sas_show_proto(port->tproto, buf);
+}
+
+static ssize_t sas_port_oob_mode_show(struct sas_port *port, char *buf)
+{
+	return sas_show_oob_mode(port->oob_mode, buf);
+}
+
+struct port_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct sas_port *port, char *);
+	ssize_t (*store)(struct sas_port *port, const char *, size_t);
+};
+
+static struct port_attribute port_attrs[] = {
+	__ATTR(id, 0444, sas_port_id_show, NULL),
+	__ATTR(class, 0444, sas_port_class_show, NULL),
+	__ATTR(port_identifier, 0444, sas_port_sas_addr_show, NULL),
+	__ATTR(attached_port_identifier, 0444, sas_port_attached_sas_addr_show, NULL),
+	__ATTR(iproto, 0444, sas_port_iproto_show, NULL),
+	__ATTR(tproto, 0444, sas_port_tproto_show, NULL),
+	__ATTR(oob_mode, 0444, sas_port_oob_mode_show, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *def_attrs[ARRAY_SIZE(port_attrs)];
+
+#define to_sas_port(_obj) container_of(_obj, struct sas_port, port_kobj)
+#define to_port_attr(_attr) container_of(_attr, struct port_attribute, attr)
+
+static ssize_t port_show_attr(struct kobject *kobj, struct attribute *attr,
+			      char *page)
+{
+	ssize_t ret = 0;
+	struct sas_port *port = to_sas_port(kobj);
+	struct port_attribute *port_attr = to_port_attr(attr);
+
+	if (port_attr->show)
+		ret = port_attr->show(port, page);
+	return ret;
+}
+
+static struct sysfs_ops port_sysfs_ops = {
+	.show = port_show_attr,
+};
+
+static struct kobj_type port_type = {
+	.sysfs_ops = &port_sysfs_ops,
+	.default_attrs = def_attrs,
+};
+
+/* ---------- SAS port registration ---------- */
+
+static void sas_init_port(struct sas_port *port,
+			  struct sas_ha_struct *sas_ha, int i,
+			  struct kset *parent_kset)
+{
+	port->id = i;
+	INIT_LIST_HEAD(&port->dev_list);
+	spin_lock_init(&port->phy_list_lock);
+	INIT_LIST_HEAD(&port->phy_list);
+	port->num_phys = 0;
+	port->phy_mask = 0;
+	port->ha = sas_ha;
+
+	memset(&port->port_kobj, 0, sizeof(port->port_kobj));
+	memset(&port->phy_kset, 0, sizeof(port->phy_kset));
+	memset(&port->dev_kset, 0, sizeof(port->dev_kset));
+
+	kobject_set_name(&port->port_kobj, "%d", port->id);
+	port->port_kobj.kset = parent_kset;
+	port->port_kobj.ktype= parent_kset->ktype;
+
+	kobject_set_name(&port->phy_kset.kobj, "%s", "phys");
+	port->phy_kset.kobj.parent = &port->port_kobj;
+	port->phy_kset.ktype = NULL;
+
+	kobject_set_name(&port->dev_kset.kobj, "%s", "domain");
+	port->dev_kset.kobj.parent = &port->port_kobj;
+	port->dev_kset.ktype = NULL;
+
+	port->id_map.max_ids = 128;
+	port->id_map.id_bitmap_size =
+		BITS_TO_LONGS(port->id_map.max_ids)*sizeof(long);
+	port->id_map.id_bitmap = kzalloc(port->id_map.id_bitmap_size,
+					 GFP_KERNEL);
+	spin_lock_init(&port->id_map.id_bitmap_lock);
+}
+
+int sas_register_ports(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(def_attrs)-1; i++)
+		def_attrs[i] = &port_attrs[i].attr;
+	def_attrs[i] = NULL;
+
+	/* make sas/ha/ports/ appear */
+	kobject_set_name(&sas_ha->port_kset.kobj, "%s", "ports");
+	sas_ha->port_kset.kobj.kset = &sas_ha->ha_kset; /* parent */
+	/* no type inheritance */
+	sas_ha->port_kset.kobj.ktype = NULL;
+	sas_ha->port_kset.ktype = &port_type; /* children are of this type */
+
+	/* initialize the ports and discovery */
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		struct sas_port *port = sas_ha->sas_port[i];
+
+		sas_init_port(port, sas_ha, i, &sas_ha->port_kset);
+		sas_init_disc(&port->disc, port);
+	}
+
+	return kset_register(&sas_ha->port_kset);
+}
+
+void sas_unregister_ports(struct sas_ha_struct *sas_ha)
+{
+	int i;
+
+	for (i = 0; i < sas_ha->num_phys; i++)
+		if (sas_ha->sas_phy[i]->port)
+			sas_deform_port(sas_ha->sas_phy[i]);
+
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		kfree(sas_ha->sas_port[i]->id_map.id_bitmap);
+		sas_ha->sas_port[i]->id_map.id_bitmap = NULL;
+	}
+
+	kset_unregister(&sas_ha->port_kset);
+}
+
+int sas_reserve_free_id(struct sas_port *port)
+{
+	int id;
+
+	spin_lock(&port->id_map.id_bitmap_lock);
+	id = find_first_zero_bit(port->id_map.id_bitmap, port->id_map.max_ids);
+	if (id >= port->id_map.max_ids) {
+		id = -ENOMEM;
+		spin_unlock(&port->id_map.id_bitmap_lock);
+		goto out;
+	}
+	set_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+out:
+	return id;
+}
+
+void sas_reserve_scsi_id(struct sas_port *port, int id)
+{
+	if (0 > id || id >= port->id_map.max_ids)
+		return;
+	spin_lock(&port->id_map.id_bitmap_lock);
+	set_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+}
+
+void sas_release_scsi_id(struct sas_port *port, int id)
+{
+	if (0 > id || id >= port->id_map.max_ids)
+		return;
+	spin_lock(&port->id_map.id_bitmap_lock);
+	clear_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+}
diff -urN oldtree/drivers/scsi/sas/sas_scsi_host.c newtree/drivers/scsi/sas/sas_scsi_host.c
--- oldtree/drivers/scsi/sas/sas_scsi_host.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/sas/sas_scsi_host.c	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,975 @@
+/*
+ * Serial Attached SCSI (SAS) class SCSI Host glue.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_scsi_host.c#60 $
+ */
+
+#include "sas_internal.h"
+#include <scsi/sas/sas_discover.h>
+#include <scsi/sas/sas_task.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/kobject.h>
+#include <linux/scatterlist.h>
+
+/* The SAM LUN structure should be _completely_ opaque to SCSI Core.
+ * This is why this macro here, and not using the broken
+ * scsilun_to_int().  Ideally, a SCSI LUN should be communicated in
+ * its entirety, and not as an integer.  For some unknown to myself
+ * reason, SCSI Core thinks that SCSI LUNs can be interpreted as
+ * integers.
+ */
+#define SCSI_LUN(_sam_lun)   ((unsigned int)be32_to_cpu(*(__be32 *)_sam_lun))
+
+/* ---------- SCSI Core device registration ---------- */
+
+int  sas_register_with_scsi(struct LU *lu)
+{
+	struct domain_device *dev = lu->parent;
+	lu->map.channel = dev->port->id;
+	lu->map.id      = sas_reserve_free_id(dev->port);
+	if (lu->map.id == -ENOMEM)
+		return -ENOMEM;
+
+	scsi_scan_target(&dev->port->ha->core.shost->shost_gendev,
+		         lu->map.channel, lu->map.id, ~0, 0);
+	return 0;
+}
+
+void sas_unregister_with_scsi(struct LU *lu)
+{
+	if (lu->uldd_dev) {
+		struct scsi_device *scsi_dev = lu->uldd_dev;
+		scsi_remove_device(scsi_dev);
+	}
+}
+
+/* ---------- SCSI Host glue ---------- */
+
+#define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
+static void sas_scsi_task_done(struct sas_task *task)
+{
+	struct task_status_struct *ts = &task->task_status;
+	struct scsi_cmnd *sc = task->uldd_task;
+	unsigned ts_flags = task->task_state_flags;
+	int hs = 0, stat = 0;
+
+	if (unlikely(!sc)) {
+		SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+		list_del_init(&task->list);
+		sas_free_task(task);
+		return;
+	}
+
+	if (ts->resp == SAS_TASK_UNDELIVERED) {
+		/* transport error */
+		hs = DID_NO_CONNECT;
+	} else { /* ts->resp == SAS_TASK_COMPLETE */
+		/* task delivered, what happened afterwards? */
+		switch (ts->stat) {
+		case SAS_DEV_NO_RESPONSE:
+		case SAS_INTERRUPTED:
+		case SAS_PHY_DOWN:
+		case SAS_NAK_R_ERR:
+		case SAS_OPEN_TO:
+			hs = DID_NO_CONNECT;
+			break;
+		case SAS_DATA_UNDERRUN:
+			sc->resid = ts->residual;
+			if (sc->request_bufflen - sc->resid < sc->underflow)
+				hs = DID_ERROR;
+			break;
+		case SAS_DATA_OVERRUN:
+			hs = DID_ERROR;
+			break;
+		case SAS_QUEUE_FULL:
+			hs = DID_SOFT_ERROR; /* retry */
+			break;
+		case SAS_DEVICE_UNKNOWN:
+			hs = DID_BAD_TARGET;
+			break;
+		case SAS_SG_ERR:
+			hs = DID_PARITY;
+			break;
+		case SAS_OPEN_REJECT:
+			if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY)
+				hs = DID_SOFT_ERROR; /* retry */
+			else
+				hs = DID_ERROR;
+			break;
+		case SAS_PROTO_RESPONSE:
+			SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP "
+				    "task; please report this\n",
+				    task->dev->port->ha->sas_ha_name);
+			break;
+		case SAS_ABORTED_TASK:
+			hs = DID_ABORT;
+			break;
+		case SAM_CHECK_COND:
+			memcpy(sc->sense_buffer, ts->buf,
+			       max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+			stat = SAM_CHECK_COND;
+			break;
+		default:
+			stat = ts->stat;
+			break;
+		}
+	}
+	ASSIGN_SAS_TASK(sc, NULL);
+	sc->result = (hs << 16) | stat;
+	list_del_init(&task->list);
+	sas_free_task(task);
+	/* This is very ugly but this is how SCSI Core works. */
+	if (ts_flags & SAS_TASK_STATE_ABORTED)
+		scsi_finish_command(sc);
+	else
+		sc->scsi_done(sc);
+}
+
+static inline enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
+{
+	enum task_attribute ta = TASK_ATTR_SIMPLE;
+	if (cmd->request && blk_rq_tagged(cmd->request)) {
+		if (cmd->device->ordered_tags &&
+		    (cmd->request->flags & REQ_HARDBARRIER))
+			ta = TASK_ATTR_HOQ;
+	}
+	return ta;
+}
+
+static inline struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
+					       struct LU *lu,
+					       unsigned long gfp_flags)
+{
+	struct sas_task *task = sas_alloc_task(gfp_flags);
+
+	if (!task)
+		return NULL;
+
+	*(u32 *)cmd->sense_buffer = 0;
+	task->uldd_task = cmd;
+	ASSIGN_SAS_TASK(cmd, task);
+
+	task->dev = lu->parent;
+	task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */
+
+	task->ssp_task.retry_count = 1;
+	memcpy(task->ssp_task.LUN, lu->LUN, 8);
+	task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
+	memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
+
+	task->scatter = cmd->request_buffer;
+	task->num_scatter = cmd->use_sg;
+	task->total_xfer_len = cmd->request_bufflen;
+	task->data_dir = cmd->sc_data_direction;
+
+	task->task_done = sas_scsi_task_done;
+
+	return task;
+}
+
+static inline int sas_queue_up(struct sas_task *task)
+{
+	struct sas_ha_struct *sas_ha = task->dev->port->ha;
+	struct scsi_core *core = &sas_ha->core;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&core->task_queue_lock, flags);
+	if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
+		spin_unlock_irqrestore(&core->task_queue_lock, flags);
+		return -SAS_QUEUE_FULL;
+	}
+	list_add_tail(&task->list, &core->task_queue);
+	core->task_queue_size += 1;
+	spin_unlock_irqrestore(&core->task_queue_lock, flags);
+	up(&core->queue_thread_sema);
+
+	return 0;
+}
+
+/**
+ * sas_queuecommand -- Enqueue a command for processing
+ * @parameters: See SCSI Core documentation
+ *
+ * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
+ * call us without holding an IRQ spinlock...
+ */
+int sas_queuecommand(struct scsi_cmnd *cmd,
+		     void (*scsi_done)(struct scsi_cmnd *))
+{
+	int res = 0;
+	struct LU *lu = cmd->device->hostdata;
+	struct Scsi_Host *host = cmd->device->host;
+
+	spin_unlock_irq(host->host_lock);
+	if (!lu) {
+		SAS_DPRINTK("scsi cmd 0x%p sent to non existing LU\n",
+			    cmd);
+		cmd->result = DID_BAD_TARGET << 16;
+		scsi_done(cmd);
+		goto out;
+	} else {
+		struct sas_ha_struct *sas_ha = lu->parent->port->ha;
+		struct sas_task *task;
+
+		res = -ENOMEM;
+		task = sas_create_task(cmd, lu, GFP_ATOMIC);
+		if (!task)
+			goto out;
+
+		cmd->scsi_done = scsi_done;
+		/* Queue up, Direct Mode or Task Collector Mode. */
+		if (sas_ha->lldd_max_execute_num < 2)
+			res = sas_ha->lldd_execute_task(task, 1, GFP_ATOMIC);
+		else
+			res = sas_queue_up(task);
+
+		/* Examine */
+		if (res) {
+			SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+			ASSIGN_SAS_TASK(cmd, NULL);
+			sas_free_task(task);
+			if (res == -SAS_QUEUE_FULL) {
+				cmd->result = DID_SOFT_ERROR << 16; /* retry */
+				res = 0;
+				scsi_done(cmd);
+			}
+			goto out;
+		}
+	}
+out:
+	spin_lock_irq(host->host_lock);
+	return res;
+}
+
+static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct LU *lu)
+{
+	struct scsi_cmnd *cmd, *n;
+
+	list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+		struct LU *x = cmd->device->hostdata;
+
+		if (x == lu)
+			list_del_init(&cmd->eh_entry);
+	}
+}
+
+static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
+				     struct domain_device *dev)
+{
+	struct scsi_cmnd *cmd, *n;
+
+	list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+		struct LU *y = cmd->device->hostdata;
+		struct domain_device *x = y->parent;
+
+		if (x == dev)
+			list_del_init(&cmd->eh_entry);
+	}
+}
+
+static void sas_scsi_clear_queue_port(struct list_head *error_q,
+				      struct sas_port *port)
+{
+	struct scsi_cmnd *cmd, *n;
+
+	list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+		struct LU *y = cmd->device->hostdata;
+		struct sas_port *x = y->parent->port;
+
+		if (x == port)
+			list_del_init(&cmd->eh_entry);
+	}
+}
+
+enum task_disposition {
+	TASK_IS_DONE,
+	TASK_IS_ABORTED,
+	TASK_IS_AT_LU,
+	TASK_IS_NOT_AT_LU,
+};
+
+static enum task_disposition sas_scsi_find_task(struct sas_task *task)
+{
+	struct sas_ha_struct *ha = task->dev->port->ha;
+	unsigned long flags;
+	int i, res;
+
+	if (ha->lldd_max_execute_num > 1) {
+		struct scsi_core *core = &ha->core;
+		struct sas_task *t, *n;
+
+		spin_lock_irqsave(&core->task_queue_lock, flags);
+		list_for_each_entry_safe(t, n, &core->task_queue, list) {
+			if (task == t) {
+				list_del_init(&t->list);
+				spin_unlock_irqrestore(&core->task_queue_lock,
+						       flags);
+				SAS_DPRINTK("%s: task 0x%p aborted from "
+					    "task_queue\n",
+					    __FUNCTION__, task);
+				return TASK_IS_ABORTED;
+			}
+		}
+		spin_unlock_irqrestore(&core->task_queue_lock, flags);
+	}
+
+	for (i = 0; i < 5; i++) {
+		SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
+		res = task->dev->port->ha->lldd_abort_task(task);
+
+		spin_lock_irqsave(&task->task_state_lock, flags);
+		if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+			spin_unlock_irqrestore(&task->task_state_lock, flags);
+			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+				    task);
+			return TASK_IS_DONE;
+		}
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+		if (res == TMF_RESP_FUNC_COMPLETE) {
+			SAS_DPRINTK("%s: task 0x%p is aborted\n",
+				    __FUNCTION__, task);
+			return TASK_IS_ABORTED;
+		} else if (ha->lldd_query_task) {
+			SAS_DPRINTK("%s: querying task 0x%p\n",
+				    __FUNCTION__, task);
+			res = ha->lldd_query_task(task);
+			if (res == TMF_RESP_FUNC_SUCC) {
+				SAS_DPRINTK("%s: task 0x%p at LU\n",
+					    __FUNCTION__, task);
+				return TASK_IS_AT_LU;
+			} else if (res == TMF_RESP_FUNC_COMPLETE) {
+				SAS_DPRINTK("%s: task 0x%p not at LU\n",
+					    __FUNCTION__, task);
+				return TASK_IS_NOT_AT_LU;
+			}
+		}
+	}
+	return res;
+}
+
+static int sas_recover_lu(struct domain_device *dev, struct LU *lu)
+{
+	struct sas_ha_struct *ha = dev->port->ha;
+	int res = TMF_RESP_FUNC_FAILED;
+
+	SAS_DPRINTK("eh: device %llx LUN %llx has the task\n",
+		    SAS_ADDR(dev->sas_addr),
+		    SAS_ADDR(lu->LUN));
+
+	if (ha->lldd_abort_task_set)
+		res = ha->lldd_abort_task_set(dev, lu->LUN);
+
+	if (res == TMF_RESP_FUNC_FAILED) {
+		if (ha->lldd_clear_task_set)
+			res = ha->lldd_clear_task_set(dev, lu->LUN);
+	}
+
+	if (res == TMF_RESP_FUNC_FAILED) {
+		if (ha->lldd_lu_reset)
+			res = ha->lldd_lu_reset(dev, lu->LUN);
+	}
+
+	return res;
+}
+
+static int sas_recover_I_T(struct domain_device *dev)
+{
+	struct sas_ha_struct *ha = dev->port->ha;
+	int res = TMF_RESP_FUNC_FAILED;
+
+	SAS_DPRINTK("I_T nexus reset for dev %016llx\n",
+		    SAS_ADDR(dev->sas_addr));
+
+	if (ha->lldd_I_T_nexus_reset)
+		res = ha->lldd_I_T_nexus_reset(dev);
+
+	return res;
+}
+
+int sas_scsi_recover_host(struct Scsi_Host *shost)
+{
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	unsigned long flags;
+	LIST_HEAD(error_q);
+	struct scsi_cmnd *cmd, *n;
+	enum task_disposition res = TASK_IS_DONE;
+	int tmf_resp;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_splice_init(&shost->eh_cmd_q, &error_q);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+
+	/* All tasks on this list were marked SAS_TASK_STATE_ABORTED
+	 * by sas_scsi_timed_out() callback.
+	 */
+Again:
+	SAS_DPRINTK("going over list...\n");
+	list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+		struct sas_task *task = TO_SAS_TASK(cmd);
+		struct LU *lu = cmd->device->hostdata;
+
+		SAS_DPRINTK("trying to find task 0x%p\n", task);
+		list_del_init(&cmd->eh_entry);
+		res = sas_scsi_find_task(task);
+
+		cmd->eh_eflags = 0;
+		shost->host_failed--;
+
+		switch (res) {
+		case TASK_IS_DONE:
+			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+				    task);
+			task->task_done(task);
+			continue;
+		case TASK_IS_ABORTED:
+			SAS_DPRINTK("%s: task 0x%p is aborted\n",
+				    __FUNCTION__, task);
+			task->task_done(task);
+			continue;
+		case TASK_IS_AT_LU:
+			SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
+			tmf_resp = sas_recover_lu(task->dev, lu);
+			if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+				SAS_DPRINTK("dev %016llx LU %016llx is "
+					    "recovered\n",
+					    SAS_ADDR(task->dev),
+					    SAS_ADDR(lu->LUN));
+				task->task_done(task);
+				sas_scsi_clear_queue_lu(&error_q, lu);
+				goto Again;
+			}
+			/* fallthrough */
+		case TASK_IS_NOT_AT_LU:
+			SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
+				    task);
+			tmf_resp = sas_recover_I_T(task->dev);
+			if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+				SAS_DPRINTK("I_T %016llx recovered\n",
+					    SAS_ADDR(task->dev->sas_addr));
+				task->task_done(task);
+				sas_scsi_clear_queue_I_T(&error_q, task->dev);
+				goto Again;
+			}
+			/* Hammer time :-) */
+			if (ha->lldd_clear_nexus_port) {
+				struct sas_port *port = task->dev->port;
+				SAS_DPRINTK("clearing nexus for port:%d\n",
+					    port->id);
+				res = ha->lldd_clear_nexus_port(port);
+				if (res == TMF_RESP_FUNC_COMPLETE) {
+					SAS_DPRINTK("clear nexus port:%d "
+						    "succeeded\n", port->id);
+					task->task_done(task);
+					sas_scsi_clear_queue_port(&error_q,
+								  port);
+					goto Again;
+				}
+			}
+			if (ha->lldd_clear_nexus_ha) {
+				SAS_DPRINTK("clear nexus ha\n");
+				res = ha->lldd_clear_nexus_ha(ha);
+				if (res == TMF_RESP_FUNC_COMPLETE) {
+					SAS_DPRINTK("clear nexus ha "
+						    "succeeded\n");
+					task->task_done(task);
+					goto out;
+				}
+			}
+			/* If we are here -- this means that no amount
+			 * of effort could recover from errors.  Quite
+			 * possibly the HA just disappeared.
+			 */
+			SAS_DPRINTK("error from  device %llx, LUN %llx "
+				    "couldn't be recovered in any way\n",
+				    SAS_ADDR(task->dev->sas_addr),
+				    SAS_ADDR(lu->LUN));
+
+			task->task_done(task);
+			goto clear_q;
+		}
+	}
+out:
+	SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+	return 0;
+clear_q:
+	SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+	list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+		struct sas_task *task = TO_SAS_TASK(cmd);
+		list_del_init(&cmd->eh_entry);
+		task->task_done(task);
+	}
+	return 0;
+}
+
+enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+	struct sas_task *task = TO_SAS_TASK(cmd);
+	unsigned long flags;
+
+	if (!task) {
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+			    cmd, task);
+		return EH_HANDLED;
+	}
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+			    cmd, task);
+		return EH_HANDLED;
+	}
+	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+		    cmd, task);
+
+	return EH_NOT_HANDLED;
+}
+
+/**
+ * sas_slave_alloc -- configure an LU which SCSI Core wants to poke at
+ * @scsi_dev: pointer to scsi device
+ *
+ * The kludge here is that the only token we have to go by in order to
+ * identify which device SCSI Core has just found about, is channel,
+ * id and lun/2.  Of course this is 1) incredibly broken and 2)
+ * leftover from when SCSI Core was SPI-centric.  A solution would be
+ * to pass an opaque token to scsi_add_device, which SCSI Core treats
+ * as that, an opaque token, which it sets inside scsi_dev, so we can
+ * find out which device SCSI Core is talking about.  That is, how
+ * SCSI Core is _addressing_ the device is not the business of LLDD
+ * and vice versa.  An even _better_ solution is if SCSI Core knew
+ * about a "SCSI device with Target ports" so we can register only the
+ * targets, and then it would do its own LU discovery...  See comment
+ * in sas_do_lu_discovery().
+ */
+int sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(scsi_dev->host);
+	struct sas_port *port = sas_ha->sas_port[scsi_dev->channel];
+        unsigned id = scsi_dev->id;
+	unsigned lun = scsi_dev->lun;
+
+	struct domain_device *dev = NULL;
+	struct LU *lu = NULL;
+
+	scsi_dev->hostdata = NULL;
+
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		if (dev->dev_type == SAS_END_DEV) {
+			list_for_each_entry(lu, &dev->end_dev.LU_list, list) {
+				if (lu->map.id == id &&
+				    SCSI_LUN(lu->LUN) == lun) {
+					scsi_dev->hostdata = lu;
+					lu->uldd_dev = scsi_dev;
+					goto out_loop;
+				}
+			}
+		}
+	}
+out_loop:
+	if (!scsi_dev->hostdata) {
+		SAS_DPRINTK("sas device not found! How is this possible?\n");
+		return -ENODEV;
+	}
+	kobject_get(&lu->lu_obj);
+	return 0;
+}
+
+#define SAS_DEF_QD 32
+#define SAS_MAX_QD 64
+
+int sas_slave_configure(struct scsi_device *scsi_dev)
+{
+	struct LU *lu = scsi_dev->hostdata;
+	struct domain_device *dev;
+	struct sas_ha_struct *sas_ha;
+
+	if (!lu) {
+		SAS_DPRINTK("slave configure and no LU?!\n");
+		return -ENODEV;
+	}
+
+	dev = lu->parent;
+	sas_ha = dev->port->ha;
+
+	if (scsi_dev->inquiry_len > 7) {
+		u8 bq = (scsi_dev->inquiry[6] & 0x80) ? 1 : 0;
+		u8 cq = (scsi_dev->inquiry[7] & 0x02) ? 1 : 0;
+
+		if (bq ^ cq) {
+			lu->tm_type = (bq<<1) | cq;
+			scsi_dev->tagged_supported = 1;
+			if (cq)
+				scsi_set_tag_type(scsi_dev, MSG_ORDERED_TAG);
+			else
+				scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
+			scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
+		} else {
+			SAS_DPRINTK("device %llx, LUN %llx doesn't support "
+				    "TCQ\n", SAS_ADDR(dev->sas_addr),
+				    SAS_ADDR(lu->LUN));
+			scsi_dev->tagged_supported = 0;
+			scsi_set_tag_type(scsi_dev, 0);
+			scsi_deactivate_tcq(scsi_dev, 1);
+		}
+	}
+
+	if (dev->end_dev.itnl_timeout > 0)
+		scsi_dev->timeout = HZ +
+			msecs_to_jiffies(dev->end_dev.itnl_timeout);
+
+	return 0;
+}
+
+void sas_slave_destroy(struct scsi_device *scsi_dev)
+{
+	struct LU *lu = scsi_dev->hostdata;
+
+	if (lu) {
+		scsi_dev->hostdata = NULL;
+		lu->uldd_dev = NULL;
+		kobject_put(&lu->lu_obj);
+	}
+}
+
+int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
+{
+	int res = min(new_depth, SAS_MAX_QD);
+
+	if (scsi_dev->tagged_supported)
+		scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
+					res);
+	else {
+		struct LU *lu = scsi_dev->hostdata;
+		sas_printk("device %llx LUN %llx queue depth changed to 1\n",
+			   SAS_ADDR(lu->parent->sas_addr),
+			   SAS_ADDR(lu->LUN));
+		scsi_adjust_queue_depth(scsi_dev, 0, 1);
+		res = 1;
+	}
+
+	return res;
+}
+
+int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
+{
+	struct LU *lu = scsi_dev->hostdata;
+
+	if (!scsi_dev->tagged_supported)
+		return 0;
+
+	scsi_deactivate_tcq(scsi_dev, 1);
+
+	switch (qt) {
+	case MSG_ORDERED_TAG:
+		if (lu->tm_type != TASK_MANAGEMENT_FULL)
+			qt = MSG_SIMPLE_TAG;
+		break;
+	case MSG_SIMPLE_TAG:
+	default:
+		;
+	}
+
+	scsi_set_tag_type(scsi_dev, qt);
+	scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
+
+	return qt;
+}
+
+int sas_bios_param(struct scsi_device *scsi_dev,
+			  struct block_device *bdev,
+			  sector_t capacity, int *hsc)
+{
+	hsc[0] = 255;
+	hsc[1] = 63;
+	sector_div(capacity, 255*63);
+	hsc[2] = capacity;
+
+	return 0;
+}
+
+static inline void sas_init_host_template(struct sas_ha_struct *sas_ha,
+			      const struct scsi_host_template *scsi_ht)
+{
+	struct scsi_host_template *sht = sas_ha->core.sht;
+
+	memcpy(sht, scsi_ht, sizeof(struct scsi_host_template));
+
+	sht->name = sas_ha->sas_ha_name;
+	sht->can_queue = sas_ha->lldd_queue_size;
+	sht->cmd_per_lun = sht->can_queue;
+}
+
+int sas_register_scsi_host(struct sas_ha_struct *sas_ha,
+			   const struct scsi_host_template *scsi_ht)
+{
+	int err = -ENOMEM;
+
+	sas_ha->core.sht = kzalloc(sizeof(*sas_ha->core.sht), GFP_KERNEL);
+	if (!sas_ha->core.sht)
+		return -ENOMEM;
+
+	sas_init_host_template(sas_ha, scsi_ht);
+
+	sas_ha->core.shost = scsi_host_alloc(sas_ha->core.sht, sizeof(void *));
+	if (!sas_ha->core.shost) {
+		printk(KERN_NOTICE "couldn't allocate scsi host\n");
+		goto out_err;
+	}
+	SHOST_TO_SAS_HA(sas_ha->core.shost) = sas_ha;
+
+	/* XXX: SCSI Core should really fix this (max vs. num of) */
+	sas_ha->core.shost->max_channel = sas_ha->num_phys - 1;
+	sas_ha->core.shost->max_id = ~0 - 1;
+	sas_ha->core.shost->max_lun = ~0 - 1;
+
+	sas_ha->core.shost->max_cmd_len = 16;
+
+	err = scsi_add_host(sas_ha->core.shost, &sas_ha->pcidev->dev);
+	if (err) {
+		scsi_host_put(sas_ha->core.shost);
+		sas_ha->core.shost = NULL;
+		goto out_err;
+	}
+	return 0;
+
+out_err:
+	kfree(sas_ha->core.sht);
+	sas_ha->core.sht = NULL;
+	return err;
+}
+
+void sas_unregister_scsi_host(struct sas_ha_struct *sas_ha)
+{
+	scsi_remove_host(sas_ha->core.shost);
+	scsi_host_put(sas_ha->core.shost);
+	sas_ha->core.shost = NULL;
+	kfree(sas_ha->core.sht);
+	sas_ha->core.sht = NULL;
+}
+
+/* ---------- Task Collector Thread implementation ---------- */
+
+static void sas_queue(struct sas_ha_struct *sas_ha)
+{
+	struct scsi_core *core = &sas_ha->core;
+	unsigned long flags;
+	LIST_HEAD(q);
+	int can_queue;
+	int res;
+
+	spin_lock_irqsave(&core->task_queue_lock, flags);
+	while (!core->queue_thread_kill &&
+	       !list_empty(&core->task_queue)) {
+
+		can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
+		if (can_queue >= 0) {
+			can_queue = core->task_queue_size;
+			list_splice_init(&core->task_queue, &q);
+		} else {
+			struct list_head *a, *n;
+
+			can_queue = sas_ha->lldd_queue_size;
+			list_for_each_safe(a, n, &core->task_queue) {
+				list_move_tail(a, &q);
+				if (--can_queue == 0)
+					break;
+			}
+			can_queue = sas_ha->lldd_queue_size;
+		}
+		core->task_queue_size -= can_queue;
+		spin_unlock_irqrestore(&core->task_queue_lock, flags);
+		{
+			struct sas_task *task = list_entry(q.next,
+							   struct sas_task,
+							   list);
+			list_del_init(&q);
+			res = sas_ha->lldd_execute_task(task, can_queue,
+							GFP_KERNEL);
+			if (unlikely(res))
+				__list_add(&q, task->list.prev, &task->list);
+		}
+		spin_lock_irqsave(&core->task_queue_lock, flags);
+		if (res) {
+			list_splice_init(&q, &core->task_queue); /*at head*/
+			core->task_queue_size += can_queue;
+		}
+	}
+	spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+static DECLARE_COMPLETION(queue_th_comp);
+
+/**
+ * sas_queue_thread -- The Task Collector thread
+ * @_sas_ha: pointer to struct sas_ha
+ */
+static int sas_queue_thread(void *_sas_ha)
+{
+	struct sas_ha_struct *sas_ha = _sas_ha;
+	struct scsi_core *core = &sas_ha->core;
+
+	daemonize("sas_queue_%d", core->shost->host_no);
+	current->flags |= PF_NOFREEZE;
+
+	complete(&queue_th_comp);
+
+	while (1) {
+		down_interruptible(&core->queue_thread_sema);
+		sas_queue(sas_ha);
+		if (core->queue_thread_kill)
+			break;
+	}
+
+	complete(&queue_th_comp);
+
+	return 0;
+}
+
+/* ---------- SCSI Core struct attributes ---------- */
+
+static ssize_t show_task_queue_size(struct scsi_core *core, char *page)
+{
+	return sprintf(page, "%d\n", core->task_queue_size);
+}
+
+struct scsi_core_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct scsi_core *, char *);
+	ssize_t (*store)(struct scsi_core *, const char *, size_t len);
+};
+
+#define to_scsi_core(_obj) container_of((_obj), struct scsi_core, \
+					scsi_core_obj)
+#define to_sc_attr(_attr) container_of((_attr), struct scsi_core_attribute,\
+				       attr)
+
+static ssize_t sc_show_attr(struct kobject *kobj, struct attribute *attr,
+			    char *page)
+{
+	ssize_t ret = 0;
+	struct scsi_core *core = to_scsi_core(kobj);
+	struct scsi_core_attribute *sc_attr = to_sc_attr(attr);
+
+	if (sc_attr->show)
+		ret = sc_attr->show(core, page);
+	return ret;
+}
+
+static struct scsi_core_attribute sc_attrs[] = {
+	__ATTR(task_queue_size, 0444, show_task_queue_size, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *sc_def_attrs[ARRAY_SIZE(sc_attrs)];
+
+static struct sysfs_ops sc_sysfs_ops = {
+	.show = sc_show_attr,
+};
+
+static struct kobj_type scsi_core_ktype = {
+	.sysfs_ops = &sc_sysfs_ops,
+	.default_attrs = sc_def_attrs,
+};
+
+int sas_init_queue(struct sas_ha_struct *sas_ha)
+{
+	int res;
+	struct scsi_core *core = &sas_ha->core;
+
+	spin_lock_init(&core->task_queue_lock);
+	core->task_queue_size = 0;
+	INIT_LIST_HEAD(&core->task_queue);
+	init_MUTEX_LOCKED(&core->queue_thread_sema);
+
+	res = kernel_thread(sas_queue_thread, sas_ha, 0);
+	if (res >= 0) {
+		int i;
+		wait_for_completion(&queue_th_comp);
+
+		for (i = 0; i < ARRAY_SIZE(sc_attrs)-1; i++)
+			sc_def_attrs[i] = &sc_attrs[i].attr;
+		sc_def_attrs[i] = NULL;
+
+		core->scsi_core_obj.kset = &sas_ha->ha_kset;
+		kobject_set_name(&core->scsi_core_obj, "%s", "scsi_core");
+		core->scsi_core_obj.ktype = &scsi_core_ktype;
+	}
+
+	return res < 0 ? res : 0;
+}
+
+void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
+{
+	unsigned long flags;
+	struct scsi_core *core = &sas_ha->core;
+	struct sas_task *task, *n;
+
+	init_completion(&queue_th_comp);
+	core->queue_thread_kill = 1;
+	up(&core->queue_thread_sema);
+	wait_for_completion(&queue_th_comp);
+
+	if (!list_empty(&core->task_queue))
+		SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
+			    SAS_ADDR(sas_ha->sas_addr));
+
+	spin_lock_irqsave(&core->task_queue_lock, flags);
+	list_for_each_entry_safe(task, n, &core->task_queue, list) {
+		struct scsi_cmnd *cmd = task->uldd_task;
+
+		list_del_init(&task->list);
+
+		ASSIGN_SAS_TASK(cmd, NULL);
+		sas_free_task(task);
+		cmd->result = DID_ABORT << 16;
+		cmd->scsi_done(cmd);
+	}
+	spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(sas_queuecommand);
+EXPORT_SYMBOL_GPL(sas_scsi_recover_host);
+EXPORT_SYMBOL_GPL(sas_scsi_timed_out);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
+EXPORT_SYMBOL_GPL(sas_slave_configure);
+EXPORT_SYMBOL_GPL(sas_slave_destroy);
+EXPORT_SYMBOL_GPL(sas_change_queue_depth);
+EXPORT_SYMBOL_GPL(sas_change_queue_type);
+EXPORT_SYMBOL_GPL(sas_bios_param);
diff -urN oldtree/drivers/scsi/scsi.c newtree/drivers/scsi/scsi.c
--- oldtree/drivers/scsi/scsi.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/scsi.c	2006-04-01 05:35:45.871486750 -0500
@@ -236,6 +236,58 @@
 }
 
 /*
+ * Function:	scsi_host_get_command()
+ *
+ * Purpose:	Allocate and setup a scsi command block and blk request
+ *
+ * Arguments:	shost	- scsi host
+ *		data_dir - dma data dir
+ *		gfp_mask- allocator flags
+ *
+ * Returns:	The allocated scsi command structure.
+ *
+ * This should be called by target LLDs to get a command.
+ */
+struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
+					enum dma_data_direction data_dir,
+					gfp_t gfp_mask)
+{
+	int write = (data_dir == DMA_TO_DEVICE);
+	struct request *rq;
+	struct scsi_cmnd *cmd;
+
+	/* Bail if we can't get a reference to the device */
+	if (!get_device(&shost->shost_gendev))
+		return NULL;
+
+	rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
+	if (!rq)
+		goto put_dev;
+
+	cmd = __scsi_get_command(shost, gfp_mask);
+	if (!cmd)
+		goto release_rq;
+
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->sc_data_direction = data_dir;
+	cmd->jiffies_at_alloc = jiffies;
+	cmd->request = rq;
+
+	rq->special = cmd;
+	rq->flags |= REQ_SPECIAL | REQ_BLOCK_PC;
+
+	return cmd;
+
+release_rq:
+	blk_put_request(rq);
+put_dev:
+	put_device(&shost->shost_gendev);
+	return NULL;
+
+}
+EXPORT_SYMBOL_GPL(scsi_host_get_command);
+
+/*
  * Function:	scsi_get_command()
  *
  * Purpose:	Allocate and setup a scsi command block
@@ -274,6 +326,45 @@
 EXPORT_SYMBOL(scsi_get_command);
 
 /*
+ * Function:	scsi_host_put_command()
+ *
+ * Purpose:	Free a scsi command block
+ *
+ * Arguments:	shost	- scsi host
+ * 		cmd	- command block to free
+ *
+ * Returns:	Nothing.
+ *
+ * Notes:	The command must not belong to any lists.
+ */
+void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+	struct request_queue *q = shost->uspace_req_q;
+	struct request *rq = cmd->request;
+	unsigned long flags;
+
+	/* changing locks here, don't need to restore the irq state */
+	spin_lock_irqsave(&shost->free_list_lock, flags);
+	if (unlikely(list_empty(&shost->free_list))) {
+		list_add(&cmd->list, &shost->free_list);
+		cmd = NULL;
+	}
+	spin_unlock(&shost->free_list_lock);
+
+	spin_lock(q->queue_lock);
+	if (blk_rq_tagged(rq))
+		blk_queue_end_tag(q, rq);
+	__blk_put_request(q, rq);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (likely(cmd != NULL))
+		kmem_cache_free(shost->cmd_pool->slab, cmd);
+
+	put_device(&shost->shost_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_host_put_command);
+
+/*
  * Function:	scsi_put_command()
  *
  * Purpose:	Free a scsi command block
diff -urN oldtree/drivers/scsi/scsi_lib.c newtree/drivers/scsi/scsi_lib.c
--- oldtree/drivers/scsi/scsi_lib.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/scsi_lib.c	2006-04-01 05:35:45.875487000 -0500
@@ -804,7 +804,7 @@
 	return NULL;
 }
 
-static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 {
 	struct scsi_host_sg_pool *sgp;
 	struct scatterlist *sgl;
@@ -845,7 +845,9 @@
 	return sgl;
 }
 
-static void scsi_free_sgtable(struct scatterlist *sgl, int index)
+EXPORT_SYMBOL(scsi_alloc_sgtable);
+
+void scsi_free_sgtable(struct scatterlist *sgl, int index)
 {
 	struct scsi_host_sg_pool *sgp;
 
@@ -855,6 +857,8 @@
 	mempool_free(sgl, sgp->pool);
 }
 
+EXPORT_SYMBOL(scsi_free_sgtable);
+
 /*
  * Function:    scsi_release_buffers()
  *
@@ -1687,29 +1691,40 @@
 }
 EXPORT_SYMBOL(scsi_calculate_bounce_limit);
 
-struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+					 request_fn_proc *request_fn)
 {
-	struct Scsi_Host *shost = sdev->host;
 	struct request_queue *q;
 
-	q = blk_init_queue(scsi_request_fn, NULL);
+	q = blk_init_queue(request_fn, NULL);
 	if (!q)
 		return NULL;
 
-	blk_queue_prep_rq(q, scsi_prep_fn);
-
 	blk_queue_max_hw_segments(q, shost->sg_tablesize);
 	blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
-	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
-	blk_queue_softirq_done(q, scsi_softirq_done);
 
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	return q;
 }
+EXPORT_SYMBOL(__scsi_alloc_queue);
+
+struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+{
+	struct request_queue *q;
+
+	q = __scsi_alloc_queue(sdev->host, scsi_request_fn);
+	if (!q)
+		return NULL;
+
+	blk_queue_prep_rq(q, scsi_prep_fn);
+	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+	blk_queue_softirq_done(q, scsi_softirq_done);
+	return q;
+}
 
 void scsi_free_queue(struct request_queue *q)
 {
diff -urN oldtree/drivers/scsi/scsi_tgt_if.c newtree/drivers/scsi/scsi_tgt_if.c
--- oldtree/drivers/scsi/scsi_tgt_if.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/scsi_tgt_if.c	2006-04-01 05:35:45.875487000 -0500
@@ -0,0 +1,214 @@
+/*
+ * SCSI target kernel/user interface functions
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2005 Mike Christie <michaelc@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 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/blkdev.h>
+#include <linux/file.h>
+#include <linux/netlink.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include "scsi_tgt_priv.h"
+
+static int tgtd_pid;
+static struct sock *nl_sk;
+
+static int send_event_res(uint16_t type, struct tgt_event *p,
+			  void *data, int dlen, gfp_t flags, pid_t pid)
+{
+	struct tgt_event *ev;
+	struct nlmsghdr *nlh;
+	struct sk_buff *skb;
+	uint32_t len;
+
+	len = NLMSG_SPACE(sizeof(*ev) + dlen);
+	skb = alloc_skb(len, flags);
+	if (!skb)
+		return -ENOMEM;
+
+	nlh = __nlmsg_put(skb, pid, 0, type, len - sizeof(*nlh), 0);
+
+	ev = NLMSG_DATA(nlh);
+	memcpy(ev, p, sizeof(*ev));
+	if (dlen)
+		memcpy(ev->data, data, dlen);
+
+	return netlink_unicast(nl_sk, skb, pid, 0);
+}
+
+int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t gfp_mask)
+{
+	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct tgt_event *ev;
+	struct tgt_cmd *tcmd;
+	int err, len;
+
+	len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct tgt_cmd));
+	/*
+	 * TODO: add MAX_COMMAND_SIZE to ev and add mempool
+	 */
+	skb = alloc_skb(NLMSG_SPACE(len), gfp_mask);
+	if (!skb)
+		return -ENOMEM;
+
+	nlh = __nlmsg_put(skb, tgtd_pid, 0, TGT_KEVENT_CMD_REQ,
+			  len - sizeof(*nlh), 0);
+
+	ev = NLMSG_DATA(nlh);
+	ev->k.cmd_req.host_no = shost->host_no;
+	ev->k.cmd_req.cid = cmd->request->tag;
+	ev->k.cmd_req.data_len = cmd->request_bufflen;
+
+	dprintk("%d %u %u\n", ev->k.cmd_req.host_no, ev->k.cmd_req.cid,
+		ev->k.cmd_req.data_len);
+
+	/* FIXME: we need scsi core to do that. */
+	memcpy(cmd->cmnd, cmd->data_cmnd, MAX_COMMAND_SIZE);
+
+	tcmd = (struct tgt_cmd *) ev->data;
+	memcpy(tcmd->scb, cmd->cmnd, sizeof(tcmd->scb));
+	memcpy(tcmd->lun, lun, sizeof(struct scsi_lun));
+
+	err = netlink_unicast(nl_sk, skb, tgtd_pid, 0);
+	if (err < 0)
+		printk(KERN_ERR "scsi_tgt_uspace_send: could not send skb %d\n",
+		       err);
+	return err;
+}
+
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+	struct tgt_event ev;
+	char dummy[sizeof(struct tgt_cmd)];
+
+	memset(&ev, 0, sizeof(ev));
+	ev.k.cmd_done.host_no = shost->host_no;
+	ev.k.cmd_done.cid = cmd->request->tag;
+	ev.k.cmd_done.result = cmd->result;
+
+	return send_event_res(TGT_KEVENT_CMD_DONE, &ev, dummy, sizeof(dummy),
+			      gfp_mask, tgtd_pid);
+}
+
+static int event_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	struct tgt_event *ev = NLMSG_DATA(nlh);
+	int err = 0;
+
+	dprintk("%d %d %d\n", nlh->nlmsg_type,
+		nlh->nlmsg_pid, current->pid);
+
+	switch (nlh->nlmsg_type) {
+	case TGT_UEVENT_TGTD_BIND:
+		tgtd_pid = NETLINK_CREDS(skb)->pid;
+		break;
+	case TGT_UEVENT_CMD_RES:
+		/* TODO: handle multiple cmds in one event */
+		err = scsi_tgt_kspace_exec(ev->u.cmd_res.host_no,
+					   ev->u.cmd_res.cid,
+					   ev->u.cmd_res.result,
+					   ev->u.cmd_res.len,
+					   ev->u.cmd_res.offset,
+					   ev->u.cmd_res.uaddr,
+					   ev->u.cmd_res.rw,
+					   ev->u.cmd_res.try_map);
+		break;
+	default:
+		eprintk("unknown type %d\n", nlh->nlmsg_type);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+static int event_recv_skb(struct sk_buff *skb)
+{
+	int err;
+	uint32_t rlen;
+	struct nlmsghdr	*nlh;
+
+	while (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *) skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+			return 0;
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
+		err = event_recv_msg(skb, nlh);
+
+		dprintk("%d %d\n", nlh->nlmsg_type, err);
+		/*
+		 * TODO for passthru commands the lower level should
+		 * probably handle the result or we should modify this
+		 */
+		if (nlh->nlmsg_type != TGT_UEVENT_CMD_RES) {
+			struct tgt_event ev;
+
+			memset(&ev, 0, sizeof(ev));
+			ev.k.event_res.err = err;
+			send_event_res(TGT_KEVENT_RESPONSE, &ev, NULL, 0,
+				       GFP_KERNEL | __GFP_NOFAIL,
+					nlh->nlmsg_pid);
+		}
+		skb_pull(skb, rlen);
+	}
+	return 0;
+}
+
+static void event_recv(struct sock *sk, int length)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+		if (NETLINK_CREDS(skb)->uid) {
+			skb_pull(skb, skb->len);
+			kfree_skb(skb);
+			continue;
+		}
+
+		if (event_recv_skb(skb) && skb->len)
+			skb_queue_head(&sk->sk_receive_queue, skb);
+		else
+			kfree_skb(skb);
+	}
+}
+
+void __exit scsi_tgt_if_exit(void)
+{
+	sock_release(nl_sk->sk_socket);
+}
+
+int __init scsi_tgt_if_init(void)
+{
+	nl_sk = netlink_kernel_create(NETLINK_TGT, 1, event_recv,
+				    THIS_MODULE);
+	if (!nl_sk)
+		return -ENOMEM;
+
+	return 0;
+}
diff -urN oldtree/drivers/scsi/scsi_tgt_lib.c newtree/drivers/scsi/scsi_tgt_lib.c
--- oldtree/drivers/scsi/scsi_tgt_lib.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/scsi_tgt_lib.c	2006-04-01 05:35:45.875487000 -0500
@@ -0,0 +1,550 @@
+/*
+ * SCSI target lib functions
+ *
+ * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/blkdev.h>
+#include <linux/elevator.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <../drivers/md/dm-bio-list.h>
+
+#include "scsi_tgt_priv.h"
+
+static struct workqueue_struct *scsi_tgtd;
+static kmem_cache_t *scsi_tgt_cmd_cache;
+
+/*
+ * TODO: this struct will be killed when the block layer supports large bios
+ * and James's work struct code is in
+ */
+struct scsi_tgt_cmd {
+	/* TODO replace work with James b's code */
+	struct work_struct work;
+	/* TODO replace the lists with a large bio */
+	struct bio_list xfer_done_list;
+	struct bio_list xfer_list;
+	struct scsi_lun *lun;
+};
+
+static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
+{
+	struct bio *bio;
+
+	/* must call bio_endio in case bio was bounced */
+	while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
+		bio_endio(bio, bio->bi_size, 0);
+		bio_unmap_user(bio);
+	}
+
+	while ((bio = bio_list_pop(&tcmd->xfer_list))) {
+		bio_endio(bio, bio->bi_size, 0);
+		bio_unmap_user(bio);
+	}
+}
+
+static void scsi_tgt_cmd_destroy(void *data)
+{
+	struct scsi_cmnd *cmd = data;
+	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+
+	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
+		rq_data_dir(cmd->request));
+	/*
+	 * We must set rq->flags here because bio_map_user and
+	 * blk_rq_bio_prep ruined ti.
+	 */
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		cmd->request->flags |= 1;
+	else
+		cmd->request->flags &= ~1UL;
+
+	scsi_unmap_user_pages(tcmd);
+	scsi_tgt_uspace_send_status(cmd, GFP_KERNEL);
+	kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
+	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
+}
+
+static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd)
+{
+	tcmd->lun = rq->end_io_data;
+	bio_list_init(&tcmd->xfer_list);
+	bio_list_init(&tcmd->xfer_done_list);
+}
+
+static int scsi_uspace_prep_fn(struct request_queue *q, struct request *rq)
+{
+	struct scsi_tgt_cmd *tcmd;
+
+	tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
+	if (!tcmd)
+		return BLKPREP_DEFER;
+
+	init_scsi_tgt_cmd(rq, tcmd);
+	rq->end_io_data = tcmd;
+	rq->flags |= REQ_DONTPREP;
+	return BLKPREP_OK;
+}
+
+static void scsi_uspace_request_fn(struct request_queue *q)
+{
+	struct request *rq;
+	struct scsi_cmnd *cmd;
+	struct scsi_tgt_cmd *tcmd;
+
+	/*
+	 * TODO: just send everthing in the queue to userspace in
+	 * one vector instead of multiple calls
+	 */
+	while ((rq = elv_next_request(q)) != NULL) {
+		cmd = rq->special;
+		tcmd = rq->end_io_data;
+
+		/* the completion code kicks us in case we hit this */
+		if (blk_queue_start_tag(q, rq))
+			break;
+
+		spin_unlock_irq(q->queue_lock);
+		if (scsi_tgt_uspace_send(cmd, tcmd->lun, GFP_ATOMIC) < 0)
+			goto requeue;
+		spin_lock_irq(q->queue_lock);
+	}
+
+	return;
+requeue:
+	spin_lock_irq(q->queue_lock);
+	/* need to track cnts and plug */
+	blk_requeue_request(q, rq);
+	spin_lock_irq(q->queue_lock);
+}
+
+/**
+ * scsi_tgt_alloc_queue - setup queue used for message passing
+ * shost: scsi host
+ *
+ * This should be called by the LLD after host allocation.
+ * And will be released when the host is released.
+ **/
+int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
+{
+	struct scsi_tgt_queuedata *queuedata;
+	struct request_queue *q;
+	int err;
+
+	/*
+	 * Do we need to send a netlink event or should uspace
+	 * just respond to the hotplug event?
+	 */
+	q = __scsi_alloc_queue(shost, scsi_uspace_request_fn);
+	if (!q)
+		return -ENOMEM;
+
+	queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL);
+	if (!queuedata) {
+		err = -ENOMEM;
+		goto cleanup_queue;
+	}
+	queuedata->shost = shost;
+	q->queuedata = queuedata;
+
+	elevator_exit(q->elevator);
+	err = elevator_init(q, "noop");
+	if (err)
+		goto free_data;
+
+	blk_queue_prep_rq(q, scsi_uspace_prep_fn);
+	/*
+	 * this is a silly hack. We should probably just queue as many
+	 * command as is recvd to userspace. uspace can then make
+	 * sure we do not overload the HBA
+	 */
+	q->nr_requests = shost->hostt->can_queue;
+	blk_queue_init_tags(q, shost->hostt->can_queue, NULL);
+	/*
+	 * We currently only support software LLDs so this does
+	 * not matter for now. Do we need this for the cards we support?
+	 * If so we should make it a host template value.
+	 */
+	blk_queue_dma_alignment(q, 0);
+	shost->uspace_req_q = q;
+
+	return 0;
+
+free_data:
+	kfree(queuedata);
+cleanup_queue:
+	blk_cleanup_queue(q);
+	return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);
+
+struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd)
+{
+	struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata;
+	return queue->shost;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
+
+/**
+ * scsi_tgt_queue_command - queue command for userspace processing
+ * @cmd:	scsi command
+ * @scsilun:	scsi lun
+ * @noblock:	set to nonzero if the command should be queued
+ **/
+void scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
+			    int noblock)
+{
+	/*
+	 * For now this just calls the request_fn from this context.
+	 * For HW llds though we do not want to execute from here so
+	 * the elevator code needs something like a REQ_TGT_CMD or
+	 * REQ_MSG_DONT_UNPLUG_IMMED_BECUASE_WE_WILL_HANDLE_IT
+	 */
+	cmd->request->end_io_data = scsilun;
+	elv_add_request(cmd->request->q, cmd->request, ELEVATOR_INSERT_BACK, 1);
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
+
+/*
+ * This is run from a interrpt handler normally and the unmap
+ * needs process context so we must queue
+ */
+static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
+{
+	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+
+	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+
+	/* don't we have to call this if result is set or not */
+	if (cmd->result) {
+		scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC);
+		return;
+	}
+
+	INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy, cmd);
+	queue_work(scsi_tgtd, &tcmd->work);
+}
+
+static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+	int err;
+
+	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+
+	err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
+	switch (err) {
+	case SCSI_MLQUEUE_HOST_BUSY:
+	case SCSI_MLQUEUE_DEVICE_BUSY:
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+	int err;
+
+	err = __scsi_tgt_transfer_response(cmd);
+	if (!err)
+		return;
+
+	cmd->result = DID_BUS_BUSY << 16;
+	if (scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC) <= 0)
+		/* the eh will have to pick this up */
+		printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+}
+
+static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+	struct request *rq = cmd->request;
+	int count;
+
+	cmd->use_sg = rq->nr_phys_segments;
+	cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask);
+	if (!cmd->request_buffer)
+		return -ENOMEM;
+
+	cmd->request_bufflen = rq->data_len;
+
+	dprintk("cmd %p addr %p cnt %d %lu\n", cmd, cmd->buffer, cmd->use_sg,
+		rq_data_dir(rq));
+	count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
+	if (likely(count <= cmd->use_sg)) {
+		cmd->use_sg = count;
+		return 0;
+	}
+
+	eprintk("cmd %p addr %p cnt %d\n", cmd, cmd->buffer, cmd->use_sg);
+	scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+	return -EINVAL;
+}
+
+/* TODO: test this crap and replace bio_map_user with new interface maybe */
+static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
+			       int rw)
+{
+	struct request_queue *q = cmd->request->q;
+	struct request *rq = cmd->request;
+	void *uaddr = cmd->buffer;
+	unsigned int len = cmd->bufflen;
+	struct bio *bio;
+	int err;
+
+	while (len > 0) {
+		dprintk("%lx %u\n", (unsigned long) uaddr, len);
+		bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw, 1);
+		if (IS_ERR(bio)) {
+			err = PTR_ERR(bio);
+			dprintk("fail to map %lx %u %d %x\n",
+				(unsigned long) uaddr, len, err, cmd->cmnd[0]);
+			goto unmap_bios;
+		}
+
+		uaddr += bio->bi_size;
+		len -= bio->bi_size;
+
+		/*
+		 * The first bio is added and merged. We could probably
+		 * try to add others using scsi_merge_bio() but for now
+		 * we keep it simple. The first bio should be pretty large
+		 * (either hitting the 1 MB bio pages limit or a queue limit)
+		 * already but for really large IO we may want to try and
+		 * merge these.
+		 */
+		if (!rq->bio) {
+			blk_rq_bio_prep(q, rq, bio);
+			rq->data_len = bio->bi_size;
+		} else
+			/* put list of bios to transfer in next go around */
+			bio_list_add(&tcmd->xfer_list, bio);
+	}
+
+	cmd->offset = 0;
+	err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
+	if (err)
+		goto unmap_bios;
+
+	return 0;
+
+unmap_bios:
+	if (rq->bio) {
+		bio_unmap_user(rq->bio);
+		while ((bio = bio_list_pop(&tcmd->xfer_list)))
+			bio_unmap_user(bio);
+	}
+
+	return err;
+}
+
+static int scsi_tgt_transfer_data(struct scsi_cmnd *);
+
+static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
+{
+	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+	struct bio *bio;
+	int err;
+
+	/* should we free resources here on error ? */
+	if (cmd->result) {
+send_uspace_err:
+		if (scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC) <= 0)
+			/* the tgt uspace eh will have to pick this up */
+			printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+		return;
+	}
+
+	dprintk("cmd %p request_bufflen %u bufflen %u\n",
+		cmd, cmd->request_bufflen, cmd->bufflen);
+
+	scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+	bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
+
+	cmd->buffer += cmd->request_bufflen;
+	cmd->offset += cmd->request_bufflen;
+
+	if (!tcmd->xfer_list.head) {
+		scsi_tgt_transfer_response(cmd);
+		return;
+	}
+
+	dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
+		cmd, cmd->request_bufflen, cmd->bufflen);
+
+	bio = bio_list_pop(&tcmd->xfer_list);
+	BUG_ON(!bio);
+
+	blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
+	cmd->request->data_len = bio->bi_size;
+	err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
+	if (err) {
+		cmd->result = DID_ERROR << 16;
+		goto send_uspace_err;
+	}
+
+	if (scsi_tgt_transfer_data(cmd)) {
+		cmd->result = DID_NO_CONNECT << 16;
+		goto send_uspace_err;
+	}
+}
+
+static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
+{
+	int err;
+	struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
+
+	err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
+	switch (err) {
+		case SCSI_MLQUEUE_HOST_BUSY:
+		case SCSI_MLQUEUE_DEVICE_BUSY:
+			return -EAGAIN;
+	default:
+		return 0;
+	}
+}
+
+static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
+				unsigned len)
+{
+	char __user *p = (char __user *) uaddr;
+
+	if (copy_from_user(cmd->sense_buffer, p,
+			   min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) {
+		printk(KERN_ERR "Could not copy the sense buffer\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len, u64 offset,
+			 unsigned long uaddr, u8 rw, u8 try_map)
+{
+	struct Scsi_Host *shost;
+	struct scsi_cmnd *cmd;
+	struct request *rq;
+	int err = 0;
+
+	dprintk("%d %u %d %u %llu %lx %u %u\n", host_no, cid, result,
+		len, (unsigned long long) offset, uaddr, rw, try_map);
+
+	/* TODO: replace with a O(1) alg */
+	shost = scsi_host_lookup(host_no);
+	if (IS_ERR(shost)) {
+		printk(KERN_ERR "Could not find host no %d\n", host_no);
+		return -EINVAL;
+	}
+
+	rq = blk_queue_find_tag(shost->uspace_req_q, cid);
+	if (!rq) {
+		printk(KERN_ERR "Could not find cid %u\n", cid);
+		err = -EINVAL;
+		goto done;
+	}
+	cmd = rq->special;
+
+	dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
+		result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+
+	/*
+	 * store the userspace values here, the working values are
+	 * in the request_* values
+	 */
+	cmd->buffer = (void *)uaddr;
+	if (len)
+		cmd->bufflen = len;
+	cmd->result = result;
+
+	if (!cmd->bufflen) {
+		err = __scsi_tgt_transfer_response(cmd);
+		goto done;
+	}
+
+	/*
+	 * TODO: Do we need to handle case where request does not
+	 * align with LLD.
+	 */
+	err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
+	if (err) {
+		eprintk("%p %d\n", cmd, err);
+		err = -EAGAIN;
+		goto done;
+	}
+
+	/* userspace failure */
+	if (cmd->result) {
+		if (status_byte(cmd->result) == CHECK_CONDITION)
+			scsi_tgt_copy_sense(cmd, uaddr, len);
+		err = __scsi_tgt_transfer_response(cmd);
+		goto done;
+	}
+	/* ask the target LLD to transfer the data to the buffer */
+	err = scsi_tgt_transfer_data(cmd);
+
+done:
+	scsi_host_put(shost);
+	return err;
+}
+
+static int __init scsi_tgt_init(void)
+{
+	int err;
+
+	scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
+					       sizeof(struct scsi_tgt_cmd),
+					       0, 0, NULL, NULL);
+	if (!scsi_tgt_cmd_cache)
+		return -ENOMEM;
+
+	scsi_tgtd = create_workqueue("scsi_tgtd");
+	if (!scsi_tgtd) {
+		err = -ENOMEM;
+		goto free_kmemcache;
+	}
+
+	err = scsi_tgt_if_init();
+	if (err)
+		goto destroy_wq;
+
+	return 0;
+
+destroy_wq:
+	destroy_workqueue(scsi_tgtd);
+free_kmemcache:
+	kmem_cache_destroy(scsi_tgt_cmd_cache);
+	return err;
+}
+
+static void __exit scsi_tgt_exit(void)
+{
+	destroy_workqueue(scsi_tgtd);
+	scsi_tgt_if_exit();
+	kmem_cache_destroy(scsi_tgt_cmd_cache);
+}
+
+module_init(scsi_tgt_init);
+module_exit(scsi_tgt_exit);
+
+MODULE_DESCRIPTION("SCSI target core");
+MODULE_LICENSE("GPL");
diff -urN oldtree/drivers/scsi/scsi_tgt_priv.h newtree/drivers/scsi/scsi_tgt_priv.h
--- oldtree/drivers/scsi/scsi_tgt_priv.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/drivers/scsi/scsi_tgt_priv.h	2006-04-01 05:35:45.875487000 -0500
@@ -0,0 +1,25 @@
+struct scsi_cmnd;
+struct scsi_lun;
+struct Scsi_Host;
+struct task_struct;
+
+/* tmp - will replace with SCSI logging stuff */
+#define dprintk(fmt, args...)					\
+do {								\
+	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+} while (0)
+
+#define eprintk dprintk
+
+struct scsi_tgt_queuedata {
+	struct Scsi_Host *shost;
+};
+
+extern void scsi_tgt_if_exit(void);
+extern int scsi_tgt_if_init(void);
+
+extern int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t flags);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t flags);
+extern int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
+				u64 offset, unsigned long uaddr, u8 rw,
+				u8 try_map);
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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/sym53c8xx_2/sym_glue.c	2006-04-01 05:35:42.971305500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/sym53c8xx_2/sym_glue.h	2006-04-01 05:35:42.975305750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/sym53c8xx_2/sym_hipd.c	2006-04-01 05:35:42.975305750 -0500
@@ -473,7 +473,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 
@@ -974,8 +974,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;
 	/*
@@ -993,20 +993,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 
@@ -1095,7 +1100,7 @@
 		err |= 4;
 	}
 
-	return (err);
+	return err;
 }
 
 /*
@@ -1476,7 +1481,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;
 
@@ -4626,7 +4631,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.
@@ -4671,7 +4677,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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/scsi/sym53c8xx_2/sym_hipd.h	2006-04-01 05:35:42.975305750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/serial/8250.h	2006-04-01 05:36:15.353329250 -0500
@@ -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/m32r_sio.h newtree/drivers/serial/m32r_sio.h
--- oldtree/drivers/serial/m32r_sio.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/serial/m32r_sio.h	2006-04-01 05:36:15.353329250 -0500
@@ -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/serial_cs.c newtree/drivers/serial/serial_cs.c
--- oldtree/drivers/serial/serial_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/serial/serial_cs.c	2006-04-01 05:35:44.307389000 -0500
@@ -41,6 +41,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/serial_core.h>
+#include <linux/delay.h>
 #include <linux/major.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -97,11 +98,13 @@
 #define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
 
 struct serial_info {
-	dev_link_t		link;
+	struct pcmcia_device	*p_dev;
 	int			ndev;
 	int			multi;
 	int			slave;
 	int			manfid;
+	int			prodid;
+	int			c950ctrl;
 	dev_node_t		node[4];
 	int			line[4];
 };
@@ -113,9 +116,36 @@
 };
 
 
-static void serial_config(dev_link_t * link);
+static int serial_config(struct pcmcia_device * link);
 
 
+static void wakeup_card(struct serial_info *info)
+{
+	int ctrl = info->c950ctrl;
+
+	if (info->manfid == MANFID_OXSEMI) {
+		outb(12, ctrl + 1);
+	} else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
+		/* request_region? oxsemi branch does no request_region too... */
+		/* This sequence is needed to properly initialize MC45 attached to OXCF950.
+		 * I tried decreasing these msleep()s, but it worked properly (survived
+		 * 1000 stop/start operations) with these timeouts (or bigger). */
+		outb(0xA, ctrl + 1);
+		msleep(100);
+		outb(0xE, ctrl + 1);
+		msleep(300);
+		outb(0xC, ctrl + 1);
+		msleep(100);
+		outb(0xE, ctrl + 1);
+		msleep(200);
+		outb(0xF, ctrl + 1);
+		msleep(100);
+		outb(0xE, ctrl + 1);
+		msleep(100);
+		outb(0xC, ctrl + 1);
+	}
+}
+
 /*======================================================================
 
     After a card is removed, serial_remove() will unregister
@@ -123,67 +153,45 @@
     
 ======================================================================*/
 
-static void serial_remove(dev_link_t *link)
+static void serial_remove(struct pcmcia_device *link)
 {
 	struct serial_info *info = link->priv;
 	int i;
 
-	link->state &= ~DEV_PRESENT;
-
 	DEBUG(0, "serial_release(0x%p)\n", link);
 
 	/*
 	 * Recheck to see if the device is still configured.
 	 */
-	if (info->link.state & DEV_CONFIG) {
-		for (i = 0; i < info->ndev; i++)
-			serial8250_unregister_port(info->line[i]);
+	for (i = 0; i < info->ndev; i++)
+		serial8250_unregister_port(info->line[i]);
 
-		info->link.dev = NULL;
+	info->p_dev->dev_node = NULL;
 
-		if (!info->slave) {
-			pcmcia_release_configuration(info->link.handle);
-			pcmcia_release_io(info->link.handle, &info->link.io);
-			pcmcia_release_irq(info->link.handle, &info->link.irq);
-		}
-
-		info->link.state &= ~DEV_CONFIG;
-	}
+	if (!info->slave)
+		pcmcia_disable_device(link);
 }
 
-static int serial_suspend(struct pcmcia_device *dev)
+static int serial_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-	link->state |= DEV_SUSPEND;
-
-	if (link->state & DEV_CONFIG) {
-		struct serial_info *info = link->priv;
-		int i;
-
-		for (i = 0; i < info->ndev; i++)
-			serial8250_suspend_port(info->line[i]);
+	struct serial_info *info = link->priv;
+	int i;
 
-		if (!info->slave)
-			pcmcia_release_configuration(link->handle);
-	}
+	for (i = 0; i < info->ndev; i++)
+		serial8250_suspend_port(info->line[i]);
 
 	return 0;
 }
 
-static int serial_resume(struct pcmcia_device *dev)
+static int serial_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
-	link->state &= ~DEV_SUSPEND;
-
-	if (DEV_OK(link)) {
+	if (pcmcia_dev_present(link)) {
 		struct serial_info *info = link->priv;
 		int i;
 
-		if (!info->slave)
-			pcmcia_request_configuration(link->handle, &link->conf);
-
 		for (i = 0; i < info->ndev; i++)
 			serial8250_resume_port(info->line[i]);
+		wakeup_card(info);
 	}
 
 	return 0;
@@ -197,10 +205,9 @@
 
 ======================================================================*/
 
-static int serial_probe(struct pcmcia_device *p_dev)
+static int serial_probe(struct pcmcia_device *link)
 {
 	struct serial_info *info;
-	dev_link_t *link;
 
 	DEBUG(0, "serial_attach()\n");
 
@@ -209,7 +216,7 @@
 	if (!info)
 		return -ENOMEM;
 	memset(info, 0, sizeof (*info));
-	link = &info->link;
+	info->p_dev = link;
 	link->priv = info;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -223,12 +230,7 @@
 	}
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	serial_config(link);
-
-	return 0;
+	return serial_config(link);
 }
 
 /*======================================================================
@@ -240,9 +242,8 @@
 
 ======================================================================*/
 
-static void serial_detach(struct pcmcia_device *p_dev)
+static void serial_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct serial_info *info = link->priv;
 
 	DEBUG(0, "serial_detach(0x%p)\n", link);
@@ -263,7 +264,7 @@
 
 /*====================================================================*/
 
-static int setup_serial(client_handle_t handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
 			kio_addr_t iobase, int irq)
 {
 	struct uart_port port;
@@ -298,7 +299,7 @@
 /*====================================================================*/
 
 static int
-first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
+first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
 {
 	int i;
 	i = pcmcia_get_first_tuple(handle, tuple);
@@ -311,7 +312,7 @@
 }
 
 static int
-next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
+next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
 {
 	int i;
 	i = pcmcia_get_next_tuple(handle, tuple);
@@ -325,11 +326,10 @@
 
 /*====================================================================*/
 
-static int simple_config(dev_link_t *link)
+static int simple_config(struct pcmcia_device *link)
 {
 	static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 	static const int size_table[2] = { 8, 16 };
-	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
 	struct serial_cfg_mem *cfg_mem;
 	tuple_t *tuple;
@@ -350,7 +350,7 @@
 	buf = cfg_mem->buf;
 
 	/* If the card is already configured, look up the port and irq */
-	i = pcmcia_get_configuration_info(handle, &config);
+	i = pcmcia_get_configuration_info(link, &config);
 	if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
 		kio_addr_t port = 0;
 		if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
@@ -363,10 +363,9 @@
 		}
 		if (info->slave) {
 			kfree(cfg_mem);
-			return setup_serial(handle, info, port, config.AssignedIRQ);
+			return setup_serial(link, info, port, config.AssignedIRQ);
 		}
 	}
-	link->conf.Vcc = config.Vcc;
 
 	/* First pass: look for a config entry that looks normal. */
 	tuple->TupleData = (cisdata_t *) buf;
@@ -377,12 +376,12 @@
 	/* Two tries: without IO aliases, then with aliases */
 	for (s = 0; s < 2; s++) {
 		for (try = 0; try < 2; try++) {
-			i = first_tuple(handle, tuple, parse);
+			i = first_tuple(link, tuple, parse);
 			while (i != CS_NO_MORE_ITEMS) {
 				if (i != CS_SUCCESS)
 					goto next_entry;
 				if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-					link->conf.Vpp1 = link->conf.Vpp2 =
+					link->conf.Vpp =
 					    cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
 				if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) &&
 					    (cf->io.win[0].base != 0)) {
@@ -390,19 +389,19 @@
 					link->io.BasePort1 = cf->io.win[0].base;
 					link->io.IOAddrLines = (try == 0) ?
 					    16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-					i = pcmcia_request_io(link->handle, &link->io);
+					i = pcmcia_request_io(link, &link->io);
 					if (i == CS_SUCCESS)
 						goto found_port;
 				}
 next_entry:
-				i = next_tuple(handle, tuple, parse);
+				i = next_tuple(link, tuple, parse);
 			}
 		}
 	}
 	/* Second pass: try to find an entry that isn't picky about
 	   its base address, then try to grab any standard serial port
 	   address, and finally try to get any free port. */
-	i = first_tuple(handle, tuple, parse);
+	i = first_tuple(link, tuple, parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
 		    ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
@@ -410,50 +409,48 @@
 			for (j = 0; j < 5; j++) {
 				link->io.BasePort1 = base[j];
 				link->io.IOAddrLines = base[j] ? 16 : 3;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				if (i == CS_SUCCESS)
 					goto found_port;
 			}
 		}
-		i = next_tuple(handle, tuple, parse);
+		i = next_tuple(link, tuple, parse);
 	}
 
       found_port:
 	if (i != CS_SUCCESS) {
 		printk(KERN_NOTICE
 		       "serial_cs: no usable port range found, giving up\n");
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		kfree(cfg_mem);
 		return -1;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 	if (info->multi && (info->manfid == MANFID_3COM))
 		link->conf.ConfigIndex &= ~(0x08);
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		kfree(cfg_mem);
 		return -1;
 	}
 	kfree(cfg_mem);
-	return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
+	return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
 }
 
-static int multi_config(dev_link_t * link)
+static int multi_config(struct pcmcia_device * link)
 {
-	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
 	struct serial_cfg_mem *cfg_mem;
 	tuple_t *tuple;
 	u_char *buf;
 	cisparse_t *parse;
 	cistpl_cftable_entry_t *cf;
-	config_info_t config;
 	int i, rc, base2 = 0;
 
 	cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
@@ -464,14 +461,6 @@
 	cf = &parse->cftable_entry;
 	buf = cfg_mem->buf;
 
-	i = pcmcia_get_configuration_info(handle, &config);
-	if (i != CS_SUCCESS) {
-		cs_error(handle, GetConfigurationInfo, i);
-		rc = -1;
-		goto free_cfg_mem;
-	}
-	link->conf.Vcc = config.Vcc;
-
 	tuple->TupleData = (cisdata_t *) buf;
 	tuple->TupleOffset = 0;
 	tuple->TupleDataMax = 255;
@@ -480,7 +469,7 @@
 
 	/* First, look for a generic full-sized window */
 	link->io.NumPorts1 = info->multi * 8;
-	i = first_tuple(handle, tuple, parse);
+	i = first_tuple(link, tuple, parse);
 	while (i != CS_NO_MORE_ITEMS) {
 		/* The quad port cards have bad CIS's, so just look for a
 		   window larger than 8 ports and assume it will be right */
@@ -490,19 +479,19 @@
 			link->io.BasePort1 = cf->io.win[0].base;
 			link->io.IOAddrLines =
 			    cf->io.flags & CISTPL_IO_LINES_MASK;
-			i = pcmcia_request_io(link->handle, &link->io);
+			i = pcmcia_request_io(link, &link->io);
 			base2 = link->io.BasePort1 + 8;
 			if (i == CS_SUCCESS)
 				break;
 		}
-		i = next_tuple(handle, tuple, parse);
+		i = next_tuple(link, tuple, parse);
 	}
 
 	/* If that didn't work, look for two windows */
 	if (i != CS_SUCCESS) {
 		link->io.NumPorts1 = link->io.NumPorts2 = 8;
 		info->multi = 2;
-		i = first_tuple(handle, tuple, parse);
+		i = first_tuple(link, tuple, parse);
 		while (i != CS_NO_MORE_ITEMS) {
 			if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
 				link->conf.ConfigIndex = cf->index;
@@ -510,26 +499,26 @@
 				link->io.BasePort2 = cf->io.win[1].base;
 				link->io.IOAddrLines =
 				    cf->io.flags & CISTPL_IO_LINES_MASK;
-				i = pcmcia_request_io(link->handle, &link->io);
+				i = pcmcia_request_io(link, &link->io);
 				base2 = link->io.BasePort2;
 				if (i == CS_SUCCESS)
 					break;
 			}
-			i = next_tuple(handle, tuple, parse);
+			i = next_tuple(link, tuple, parse);
 		}
 	}
 
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestIO, i);
+		cs_error(link, RequestIO, i);
 		rc = -1;
 		goto free_cfg_mem;
 	}
 
-	i = pcmcia_request_irq(link->handle, &link->irq);
+	i = pcmcia_request_irq(link, &link->irq);
 	if (i != CS_SUCCESS) {
 		printk(KERN_NOTICE
 		       "serial_cs: no usable port range found, giving up\n");
-		cs_error(link->handle, RequestIRQ, i);
+		cs_error(link, RequestIRQ, i);
 		link->irq.AssignedIRQ = 0;
 	}
 	/* Socket Dual IO: this enables irq's for second port */
@@ -537,35 +526,43 @@
 		link->conf.Present |= PRESENT_EXT_STATUS;
 		link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
 	}
-	i = pcmcia_request_configuration(link->handle, &link->conf);
+	i = pcmcia_request_configuration(link, &link->conf);
 	if (i != CS_SUCCESS) {
-		cs_error(link->handle, RequestConfiguration, i);
+		cs_error(link, RequestConfiguration, i);
 		rc = -1;
 		goto free_cfg_mem;
 	}
 
 	/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-	   8 registers are for the UART, the others are extra registers */
-	if (info->manfid == MANFID_OXSEMI) {
+	 * 8 registers are for the UART, the others are extra registers.
+	 * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+	 */
+	if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+				info->prodid == PRODID_POSSIO_GCC)) {
+		int err;
+
 		if (cf->index == 1 || cf->index == 3) {
-			setup_serial(handle, info, base2, link->irq.AssignedIRQ);
-			outb(12, link->io.BasePort1 + 1);
+			err = setup_serial(link, info, base2,
+					link->irq.AssignedIRQ);
+			base2 = link->io.BasePort1;
 		} else {
-			setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
-			outb(12, base2 + 1);
+			err = setup_serial(link, info, link->io.BasePort1,
+					link->irq.AssignedIRQ);
 		}
+		info->c950ctrl = base2;
+		wakeup_card(info);
 		rc = 0;
 		goto free_cfg_mem;
 	}
 
-	setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
+	setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
 	/* The Nokia cards are not really multiport cards */
 	if (info->manfid == MANFID_NOKIA) {
 		rc = 0;
 		goto free_cfg_mem;
 	}
 	for (i = 0; i < info->multi - 1; i++)
-		setup_serial(handle, info, base2 + (8 * i),
+		setup_serial(link, info, base2 + (8 * i),
 				link->irq.AssignedIRQ);
 	rc = 0;
 free_cfg_mem:
@@ -581,9 +578,8 @@
 
 ======================================================================*/
 
-void serial_config(dev_link_t * link)
+static int serial_config(struct pcmcia_device * link)
 {
-	client_handle_t handle = link->handle;
 	struct serial_info *info = link->priv;
 	struct serial_cfg_mem *cfg_mem;
 	tuple_t *tuple;
@@ -609,7 +605,7 @@
 	tuple->Attributes = 0;
 	/* Get configuration register information */
 	tuple->DesiredTuple = CISTPL_CONFIG;
-	last_ret = first_tuple(handle, tuple, parse);
+	last_ret = first_tuple(link, tuple, parse);
 	if (last_ret != CS_SUCCESS) {
 		last_fn = ParseTuple;
 		goto cs_failed;
@@ -617,18 +613,16 @@
 	link->conf.ConfigBase = parse->config.base;
 	link->conf.Present = parse->config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	/* Is this a compliant multifunction card? */
 	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
 	tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
-	info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
+	info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS);
 
 	/* Is this a multiport card? */
 	tuple->DesiredTuple = CISTPL_MANFID;
-	if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+	if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
 		info->manfid = parse->manfid.manf;
+		info->prodid = le16_to_cpu(buf[1]);
 		for (i = 0; i < MULTI_COUNT; i++)
 			if ((info->manfid == multi_id[i].manfid) &&
 			    (parse->manfid.card == multi_id[i].prodid))
@@ -641,11 +635,11 @@
 	   multifunction cards that ask for appropriate IO port ranges */
 	tuple->DesiredTuple = CISTPL_FUNCID;
 	if ((info->multi == 0) &&
-	    ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
+	    ((first_tuple(link, tuple, parse) != CS_SUCCESS) ||
 	     (parse->funcid.func == CISTPL_FUNCID_MULTI) ||
 	     (parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
 		tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
-		if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+		if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
 			if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
 				info->multi = cf->io.win[0].len >> 3;
 			if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
@@ -664,31 +658,30 @@
 
 	if (info->manfid == MANFID_IBM) {
 		conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
-		last_ret = pcmcia_access_configuration_register(link->handle, &reg);
+		last_ret = pcmcia_access_configuration_register(link, &reg);
 		if (last_ret) {
 			last_fn = AccessConfigurationRegister;
 			goto cs_failed;
 		}
 		reg.Action = CS_WRITE;
 		reg.Value = reg.Value | 1;
-		last_ret = pcmcia_access_configuration_register(link->handle, &reg);
+		last_ret = pcmcia_access_configuration_register(link, &reg);
 		if (last_ret) {
 			last_fn = AccessConfigurationRegister;
 			goto cs_failed;
 		}
 	}
 
-	link->dev = &info->node[0];
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &info->node[0];
 	kfree(cfg_mem);
-	return;
+	return 0;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
  failed:
 	serial_remove(link);
-	link->state &= ~DEV_CONFIG_PENDING;
 	kfree(cfg_mem);
+	return -ENODEV;
 }
 
 static struct pcmcia_device_id serial_ids[] = {
diff -urN oldtree/drivers/telephony/ixj_pcmcia.c newtree/drivers/telephony/ixj_pcmcia.c
--- oldtree/drivers/telephony/ixj_pcmcia.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/telephony/ixj_pcmcia.c	2006-04-01 05:35:44.307389000 -0500
@@ -35,73 +35,52 @@
 } ixj_info_t;
 
 static void ixj_detach(struct pcmcia_device *p_dev);
-static void ixj_config(dev_link_t * link);
-static void ixj_cs_release(dev_link_t * link);
+static int ixj_config(struct pcmcia_device * link);
+static void ixj_cs_release(struct pcmcia_device * link);
 
-static int ixj_attach(struct pcmcia_device *p_dev)
+static int ixj_probe(struct pcmcia_device *p_dev)
 {
-	dev_link_t *link;
-
 	DEBUG(0, "ixj_attach()\n");
 	/* Create new ixj device */
-	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-	if (!link)
-		return -ENOMEM;
-	memset(link, 0, sizeof(struct dev_link_t));
-	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-	link->io.IOAddrLines = 3;
-	link->conf.Vcc = 50;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-	link->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
-	if (!link->priv) {
-		kfree(link);
+	p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	p_dev->io.IOAddrLines = 3;
+	p_dev->conf.IntType = INT_MEMORY_AND_IO;
+	p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
+	if (!p_dev->priv) {
 		return -ENOMEM;
 	}
-	memset(link->priv, 0, sizeof(struct ixj_info_t));
-
-	link->handle = p_dev;
-	p_dev->instance = link;
+	memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
 
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	ixj_config(link);
-
-	return 0;
+	return ixj_config(p_dev);
 }
 
-static void ixj_detach(struct pcmcia_device *p_dev)
+static void ixj_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DEBUG(0, "ixj_detach(0x%p)\n", link);
 
-	link->state &= ~DEV_RELEASE_PENDING;
-	if (link->state & DEV_CONFIG)
-		ixj_cs_release(link);
+	ixj_cs_release(link);
 
         kfree(link->priv);
-        kfree(link);
 }
 
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void ixj_get_serial(dev_link_t * link, IXJ * j)
+static void ixj_get_serial(struct pcmcia_device * link, IXJ * j)
 {
-	client_handle_t handle;
 	tuple_t tuple;
 	u_short buf[128];
 	char *str;
 	int last_ret, last_fn, i, place;
-	handle = link->handle;
 	DEBUG(0, "ixj_get_serial(0x%p)\n", link);
 	tuple.TupleData = (cisdata_t *) buf;
 	tuple.TupleOffset = 0;
 	tuple.TupleDataMax = 80;
 	tuple.Attributes = 0;
 	tuple.DesiredTuple = CISTPL_VERS_1;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
 	str = (char *) buf;
 	printk("PCMCIA Version %d.%d\n", str[0], str[1]);
 	str += 2;
@@ -149,22 +128,19 @@
 	return;
 }
 
-static void ixj_config(dev_link_t * link)
+static int ixj_config(struct pcmcia_device * link)
 {
 	IXJ *j;
-	client_handle_t handle;
 	ixj_info_t *info;
 	tuple_t tuple;
 	u_short buf[128];
 	cisparse_t parse;
-	config_info_t conf;
 	cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
 	cistpl_cftable_entry_t dflt =
 	{
 		0
 	};
 	int last_ret, last_fn;
-	handle = link->handle;
 	info = link->priv;
 	DEBUG(0, "ixj_config(0x%p)\n", link);
 	tuple.TupleData = (cisdata_t *) buf;
@@ -172,19 +148,17 @@
 	tuple.TupleDataMax = 255;
 	tuple.Attributes = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
-	link->state |= DEV_CONFIG;
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	tuple.Attributes = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
-				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
 		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
 			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
@@ -195,7 +169,7 @@
 				link->io.BasePort2 = io->win[1].base;
 				link->io.NumPorts2 = io->win[1].len;
 			}
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
+			if (pcmcia_request_io(link, &link->io) != 0)
 				goto next_entry;
 			/* If we've got this far, we're done */
 			break;
@@ -203,10 +177,10 @@
 	      next_entry:
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 			dflt = *cfg;
-		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
 
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	/*
  	 *	Register the card with the core.
@@ -215,46 +189,21 @@
 
 	info->ndev = 1;
 	info->node.major = PHONE_MAJOR;
-	link->dev = &info->node;
+	link->dev_node = &info->node;
 	ixj_get_serial(link, j);
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	return 0;
       cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 	ixj_cs_release(link);
+	return -ENODEV;
 }
 
-static void ixj_cs_release(dev_link_t *link)
+static void ixj_cs_release(struct pcmcia_device *link)
 {
 	ixj_info_t *info = link->priv;
 	DEBUG(0, "ixj_cs_release(0x%p)\n", link);
 	info->ndev = 0;
-	link->dev = NULL;
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	link->state &= ~DEV_CONFIG;
-}
-
-static int ixj_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int ixj_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (DEV_OK(link))
-		pcmcia_request_configuration(link->handle, &link->conf);
-
-	return 0;
+	pcmcia_disable_device(link);
 }
 
 static struct pcmcia_device_id ixj_ids[] = {
@@ -268,11 +217,9 @@
 	.drv		= {
 		.name	= "ixj_cs",
 	},
-	.probe		= ixj_attach,
+	.probe		= ixj_probe,
 	.remove		= ixj_detach,
 	.id_table	= ixj_ids,
-	.suspend	= ixj_suspend,
-	.resume		= ixj_resume,
 };
 
 static int __init ixj_pcmcia_init(void)
diff -urN oldtree/drivers/usb/host/sl811_cs.c newtree/drivers/usb/host/sl811_cs.c
--- oldtree/drivers/usb/host/sl811_cs.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/usb/host/sl811_cs.c	2006-04-01 05:35:44.307389000 -0500
@@ -67,11 +67,11 @@
 static const char driver_name[DEV_NAME_LEN]  = "sl811_cs";
 
 typedef struct local_info_t {
-	dev_link_t		link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t		node;
 } local_info_t;
 
-static void sl811_cs_release(dev_link_t * link);
+static void sl811_cs_release(struct pcmcia_device * link);
 
 /*====================================================================*/
 
@@ -138,41 +138,27 @@
 
 /*====================================================================*/
 
-static void sl811_cs_detach(struct pcmcia_device *p_dev)
+static void sl811_cs_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
-
 	DBG(0, "sl811_cs_detach(0x%p)\n", link);
 
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-		sl811_cs_release(link);
+	sl811_cs_release(link);
 
 	/* This points to the parent local_info_t struct */
 	kfree(link->priv);
 }
 
-static void sl811_cs_release(dev_link_t * link)
+static void sl811_cs_release(struct pcmcia_device * link)
 {
-
 	DBG(0, "sl811_cs_release(0x%p)\n", link);
 
-	/* Unlink the device chain */
-	link->dev = NULL;
-
+	pcmcia_disable_device(link);
 	platform_device_unregister(&platform_dev);
-	pcmcia_release_configuration(link->handle);
-	if (link->io.NumPorts1)
-		pcmcia_release_io(link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
 }
 
-static void sl811_cs_config(dev_link_t *link)
+static int sl811_cs_config(struct pcmcia_device *link)
 {
-	client_handle_t		handle = link->handle;
-	struct device		*parent = &handle_to_dev(handle);
+	struct device		*parent = &handle_to_dev(link);
 	local_info_t		*dev = link->priv;
 	tuple_t			tuple;
 	cisparse_t		parse;
@@ -188,27 +174,23 @@
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 	link->conf.ConfigBase = parse.config.base;
 	link->conf.Present = parse.config.rmask[0];
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
 	/* Look up the current Vcc */
 	CS_CHECK(GetConfigurationInfo,
-			pcmcia_get_configuration_info(handle, &conf));
-	link->conf.Vcc = conf.Vcc;
+			pcmcia_get_configuration_info(link, &conf));
 
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 	while (1) {
 		cistpl_cftable_entry_t	*cfg = &(parse.cftable_entry);
 
-		if (pcmcia_get_tuple_data(handle, &tuple) != 0
-				|| pcmcia_parse_tuple(handle, &tuple, &parse)
+		if (pcmcia_get_tuple_data(link, &tuple) != 0
+				|| pcmcia_parse_tuple(link, &tuple, &parse)
 						!= 0)
 			goto next_entry;
 
@@ -234,10 +216,10 @@
 		}
 
 		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
 		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
+			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
 
 		/* we need an interrupt */
@@ -254,15 +236,14 @@
 			link->io.BasePort1 = io->win[0].base;
 			link->io.NumPorts1 = io->win[0].len;
 
-			if (pcmcia_request_io(link->handle, &link->io) != 0)
+			if (pcmcia_request_io(link, &link->io) != 0)
 				goto next_entry;
 		}
 		break;
 
 next_entry:
-		if (link->io.NumPorts1)
-			pcmcia_release_io(link->handle, &link->io);
-		last_ret = pcmcia_get_next_tuple(handle, &tuple);
+		pcmcia_disable_device(link);
+		last_ret = pcmcia_get_next_tuple(link, &tuple);
 	}
 
 	/* require an IRQ and two registers */
@@ -270,71 +251,46 @@
 		goto cs_failed;
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		CS_CHECK(RequestIRQ,
-			pcmcia_request_irq(link->handle, &link->irq));
+			pcmcia_request_irq(link, &link->irq));
 	else
 		goto cs_failed;
 
 	CS_CHECK(RequestConfiguration,
-		pcmcia_request_configuration(link->handle, &link->conf));
+		pcmcia_request_configuration(link, &link->conf));
 
 	sprintf(dev->node.dev_name, driver_name);
 	dev->node.major = dev->node.minor = 0;
-	link->dev = &dev->node;
+	link->dev_node = &dev->node;
 
-	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-	       dev->node.dev_name, link->conf.ConfigIndex,
-	       link->conf.Vcc/10, link->conf.Vcc%10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	printk(KERN_INFO "%s: index 0x%02x: ",
+	       dev->node.dev_name, link->conf.ConfigIndex);
+	if (link->conf.Vpp)
+		printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
 	printk(", irq %d", link->irq.AssignedIRQ);
 	printk(", io 0x%04x-0x%04x", link->io.BasePort1,
 	       link->io.BasePort1+link->io.NumPorts1-1);
 	printk("\n");
 
-	link->state &= ~DEV_CONFIG_PENDING;
-
 	if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ)
 			< 0) {
 cs_failed:
 		printk("sl811_cs_config failed\n");
-		cs_error(link->handle, last_fn, last_ret);
+		cs_error(link, last_fn, last_ret);
 		sl811_cs_release(link);
-		link->state &= ~DEV_CONFIG_PENDING;
+		return  -ENODEV;
 	}
-}
-
-static int sl811_suspend(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state |= DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
-	return 0;
-}
-
-static int sl811_resume(struct pcmcia_device *dev)
-{
-	dev_link_t *link = dev_to_instance(dev);
-
-	link->state &= ~DEV_SUSPEND;
-	if (link->state & DEV_CONFIG)
-		pcmcia_request_configuration(link->handle, &link->conf);
-
 	return 0;
 }
 
-static int sl811_cs_attach(struct pcmcia_device *p_dev)
+static int sl811_cs_probe(struct pcmcia_device *link)
 {
 	local_info_t *local;
-	dev_link_t *link;
 
 	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local)
 		return -ENOMEM;
 	memset(local, 0, sizeof(local_info_t));
-	link = &local->link;
+	local->p_dev = link;
 	link->priv = local;
 
 	/* Initialize */
@@ -343,16 +299,9 @@
 	link->irq.Handler = NULL;
 
 	link->conf.Attributes = 0;
-	link->conf.Vcc = 33;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	link->handle = p_dev;
-	p_dev->instance = link;
-
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	sl811_cs_config(link);
-
-	return 0;
+	return sl811_cs_config(link);
 }
 
 static struct pcmcia_device_id sl811_ids[] = {
@@ -366,11 +315,9 @@
 	.drv		= {
 		.name	= (char *)driver_name,
 	},
-	.probe		= sl811_cs_attach,
+	.probe		= sl811_cs_probe,
 	.remove		= sl811_cs_detach,
 	.id_table	= sl811_ids,
-	.suspend	= sl811_suspend,
-	.resume		= sl811_resume,
 };
 
 /*====================================================================*/
diff -urN oldtree/drivers/usb/input/hid-input.c newtree/drivers/usb/input/hid-input.c
--- oldtree/drivers/usb/input/hid-input.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/usb/input/hid-input.c	2006-04-01 05:35:38.139003500 -0500
@@ -510,7 +510,7 @@
 				case 0x025: map_key_clear(KEY_TV);		break;
 				case 0x026: map_key_clear(KEY_MENU);		break;
 				case 0x031: map_key_clear(KEY_AUDIO);		break;
-				case 0x032: map_key_clear(KEY_SUBTITLE);	break;
+				case 0x032: map_key_clear(KEY_TEXT);		break;
 				case 0x033: map_key_clear(KEY_LAST);		break;
 				case 0x047: map_key_clear(KEY_MP3);		break;
 				case 0x048: map_key_clear(KEY_DVD);		break;
diff -urN oldtree/drivers/usb/misc/sisusbvga/sisusb.c newtree/drivers/usb/misc/sisusbvga/sisusb.c
--- oldtree/drivers/usb/misc/sisusbvga/sisusb.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/usb/misc/sisusbvga/sisusb.c	2006-04-01 05:35:51.059811000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/usb/misc/sisusbvga/sisusb.h	2006-04-01 05:35:51.059811000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/usb/misc/sisusbvga/sisusb_con.c	2006-04-01 05:35:51.059811000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/video/Kconfig	2006-04-01 05:35:39.507089000 -0500
@@ -725,7 +725,7 @@
 
 config FB_INTEL
 	tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
-	depends on FB && EXPERIMENTAL && PCI && X86_32
+	depends on FB && EXPERIMENTAL && PCI && X86
 	select AGP
 	select AGP_INTEL
 	select FB_MODE_HELPERS
diff -urN oldtree/drivers/video/intelfb/intelfb.h newtree/drivers/video/intelfb/intelfb.h
--- oldtree/drivers/video/intelfb/intelfb.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/video/intelfb/intelfb.h	2006-04-01 05:35:39.507089000 -0500
@@ -8,9 +8,9 @@
 
 
 /*** Version/name ***/
-#define INTELFB_VERSION			"0.9.2"
+#define INTELFB_VERSION			"0.9.4"
 #define INTELFB_MODULE_NAME		"intelfb"
-#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM"
 
 
 /*** Debug/feature defines ***/
@@ -52,6 +52,8 @@
 #define PCI_DEVICE_ID_INTEL_865G	0x2572
 #define PCI_DEVICE_ID_INTEL_915G	0x2582
 #define PCI_DEVICE_ID_INTEL_915GM	0x2592
+#define PCI_DEVICE_ID_INTEL_945G	0x2772
+#define PCI_DEVICE_ID_INTEL_945GM	0x27A2
 
 /* Size of MMIO region */
 #define INTEL_REG_SIZE			0x80000
@@ -125,7 +127,9 @@
 	INTEL_855GME,
 	INTEL_865G,
 	INTEL_915G,
-	INTEL_915GM
+	INTEL_915GM,
+	INTEL_945G,
+	INTEL_945GM,
 };
 
 struct intelfb_hwstate {
@@ -277,8 +281,13 @@
 
 	/* driver registered */
 	int registered;
+	
+	/* index into plls */
+	int pll_index;
 };
 
+#define IS_I9xx(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+
 /*** function prototypes ***/
 
 extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
diff -urN oldtree/drivers/video/intelfb/intelfbdrv.c newtree/drivers/video/intelfb/intelfbdrv.c
--- oldtree/drivers/video/intelfb/intelfbdrv.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/video/intelfb/intelfbdrv.c	2006-04-01 05:35:39.503088750 -0500
@@ -1,11 +1,12 @@
 /*
  * intelfb
  *
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM
- * integrated graphics chips.
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
+ * 945G/945GM integrated graphics chips.
  *
  * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
  *                   2004 Sylvain Meyer
+ *                   2006 David Airlie
  *
  * This driver consists of two parts.  The first part (intelfbdrv.c) provides
  * the basic fbdev interfaces, is derived in part from the radeonfb and
@@ -182,6 +183,8 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
 	{ 0, }
 };
 
@@ -546,11 +549,11 @@
 
 	/* Set base addresses. */
 	if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
-			(ent->device == PCI_DEVICE_ID_INTEL_915GM)) {
+	    (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
+	    (ent->device == PCI_DEVICE_ID_INTEL_945G)  ||
+	    (ent->device == PCI_DEVICE_ID_INTEL_945GM)) {
 		aperture_bar = 2;
 		mmio_bar = 0;
-		/* Disable HW cursor on 915G/M (not implemented yet) */
-		hwcursor = 0;
 	}
 	dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
 	dinfo->aperture.size     = pci_resource_len(pdev, aperture_bar);
@@ -584,8 +587,7 @@
 	/* Get the chipset info. */
 	dinfo->pci_chipset = pdev->device;
 
-	if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
-				  &dinfo->mobile)) {
+	if (intelfbhw_get_chipset(pdev, dinfo)) {
 		cleanup(dinfo);
 		return -ENODEV;
 	}
@@ -1467,7 +1469,7 @@
 intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
         struct intelfb_info *dinfo = GET_DINFO(info);
-
+	u32 physical;
 #if VERBOSE > 0
 	DBG_MSG("intelfb_cursor\n");
 #endif
@@ -1478,7 +1480,10 @@
 	intelfbhw_cursor_hide(dinfo);
 
 	/* If XFree killed the cursor - restore it */
-	if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) {
+	physical = (dinfo->mobile || IS_I9xx(dinfo)) ? dinfo->cursor.physical :
+		   (dinfo->cursor.offset << 12);
+
+	if (INREG(CURSOR_A_BASEADDR) != physical) {
 		u32 fg, bg;
 
 		DBG_MSG("the cursor was killed - restore it !!\n");
diff -urN oldtree/drivers/video/intelfb/intelfbhw.c newtree/drivers/video/intelfb/intelfbhw.c
--- oldtree/drivers/video/intelfb/intelfbhw.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/video/intelfb/intelfbhw.c	2006-04-01 05:35:39.507089000 -0500
@@ -40,68 +40,105 @@
 #include "intelfb.h"
 #include "intelfbhw.h"
 
+struct pll_min_max {
+	int min_m, max_m;
+	int min_m1, max_m1;
+	int min_m2, max_m2;
+	int min_n, max_n;
+	int min_p, max_p;
+	int min_p1, max_p1;
+	int min_vco_freq, max_vco_freq;
+	int p_transition_clock;
+	int p_inc_lo, p_inc_hi;
+};
+
+#define PLLS_I8xx 0
+#define PLLS_I9xx 1
+#define PLLS_MAX 2
+
+static struct pll_min_max plls[PLLS_MAX] = {
+	{ 108, 140, 18, 26, 6, 16, 3, 16, 4, 128, 0, 31, 930000, 1400000, 165000, 4, 22 }, //I8xx
+	{  75, 120, 10, 20, 5, 9, 4,  7, 5, 80, 1, 8, 930000, 2800000, 200000, 10, 5 }  //I9xx
+};
+
 int
-intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
-		      int *mobile)
+intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
 {
 	u32 tmp;
-
-	if (!pdev || !name || !chipset || !mobile)
+	if (!pdev || !dinfo)
 		return 1;
 
 	switch (pdev->device) {
 	case PCI_DEVICE_ID_INTEL_830M:
-		*name = "Intel(R) 830M";
-		*chipset = INTEL_830M;
-		*mobile = 1;
+		dinfo->name = "Intel(R) 830M";
+		dinfo->chipset = INTEL_830M;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_845G:
-		*name = "Intel(R) 845G";
-		*chipset = INTEL_845G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 845G";
+		dinfo->chipset = INTEL_845G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_85XGM:
 		tmp = 0;
-		*mobile = 1;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I8xx;
 		pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
 		switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
 			INTEL_85X_VARIANT_MASK) {
 		case INTEL_VAR_855GME:
-			*name = "Intel(R) 855GME";
-			*chipset = INTEL_855GME;
+			dinfo->name = "Intel(R) 855GME";
+			dinfo->chipset = INTEL_855GME;
 			return 0;
 		case INTEL_VAR_855GM:
-			*name = "Intel(R) 855GM";
-			*chipset = INTEL_855GM;
+			dinfo->name = "Intel(R) 855GM";
+			dinfo->chipset = INTEL_855GM;
 			return 0;
 		case INTEL_VAR_852GME:
-			*name = "Intel(R) 852GME";
-			*chipset = INTEL_852GME;
+			dinfo->name = "Intel(R) 852GME";
+			dinfo->chipset = INTEL_852GME;
 			return 0;
 		case INTEL_VAR_852GM:
-			*name = "Intel(R) 852GM";
-			*chipset = INTEL_852GM;
+			dinfo->name = "Intel(R) 852GM";
+			dinfo->chipset = INTEL_852GM;
 			return 0;
 		default:
-			*name = "Intel(R) 852GM/855GM";
-			*chipset = INTEL_85XGM;
+			dinfo->name = "Intel(R) 852GM/855GM";
+			dinfo->chipset = INTEL_85XGM;
 			return 0;
 		}
 		break;
 	case PCI_DEVICE_ID_INTEL_865G:
-		*name = "Intel(R) 865G";
-		*chipset = INTEL_865G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 865G";
+		dinfo->chipset = INTEL_865G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I8xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_915G:
-		*name = "Intel(R) 915G";
-		*chipset = INTEL_915G;
-		*mobile = 0;
+		dinfo->name = "Intel(R) 915G";
+		dinfo->chipset = INTEL_915G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I9xx;
 		return 0;
 	case PCI_DEVICE_ID_INTEL_915GM:
-		*name = "Intel(R) 915GM";
-		*chipset = INTEL_915GM;
-		*mobile = 1;
+		dinfo->name = "Intel(R) 915GM";
+		dinfo->chipset = INTEL_915GM;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I9xx;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_945G:
+		dinfo->name = "Intel(R) 945G";
+		dinfo->chipset = INTEL_945G;
+		dinfo->mobile = 0;
+		dinfo->pll_index = PLLS_I9xx;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_945GM:
+		dinfo->name = "Intel(R) 945GM";
+		dinfo->chipset = INTEL_945GM;
+		dinfo->mobile = 1;
+		dinfo->pll_index = PLLS_I9xx;
 		return 0;
 	default:
 		return 1;
@@ -529,14 +566,37 @@
 }
 
 
+static int calc_vclock3(int index, int m, int n, int p)
+{
+	if (p == 0 || n == 0)
+		return 0;
+	return PLL_REFCLK * m / n / p;
+}
+
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2)
+{
+	switch(index)
+	{
+	case PLLS_I9xx:
+		if (p1 == 0)
+			return 0;
+		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
+			 ((p1)) * (p2 ? 10 : 5)));
+	case PLLS_I8xx:
+	default:
+		return ((PLL_REFCLK * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) /
+			 ((p1+2) * (1 << (p2 + 1)))));
+	}
+}
+
 void
 intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
 {
 #if REGDUMP
 	int i, m1, m2, n, p1, p2;
-
+	int index = dinfo->pll_index;
 	DBG_MSG("intelfbhw_print_hw_state\n");
-
+	
 	if (!hw || !dinfo)
 		return;
 	/* Read in as much of the HW state as possible. */
@@ -553,9 +613,10 @@
 		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	VGA0: clock is %d\n",
+	       calc_vclock(index, m1, m2, n, p1, p2));
+	
 	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -565,16 +626,16 @@
 		p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 	printk("	DPLL_A:			0x%08x\n", hw->dpll_a);
 	printk("	DPLL_B:			0x%08x\n", hw->dpll_b);
 	printk("	FPA0:			0x%08x\n", hw->fpa0);
 	printk("	FPA1:			0x%08x\n", hw->fpa1);
 	printk("	FPB0:			0x%08x\n", hw->fpb0);
 	printk("	FPB1:			0x%08x\n", hw->fpb1);
-
+	
 	n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -584,9 +645,9 @@
 		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 	n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
 	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -596,16 +657,16 @@
 		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
 	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
 	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
-		m1, m2, n, p1, p2);
-	printk("	PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
-
+	       m1, m2, n, p1, p2);
+	printk("	PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2));
+	
 #if 0
 	printk("	PALETTE_A:\n");
 	for (i = 0; i < PALETTE_8_ENTRIES)
-		printk("	%3d:	0x%08x\n", i, hw->palette_a[i];
+		printk("	%3d:	0x%08x\n", i, hw->palette_a[i]);
 	printk("	PALETTE_B:\n");
 	for (i = 0; i < PALETTE_8_ENTRIES)
-		printk("	%3d:	0x%08x\n", i, hw->palette_b[i];
+		printk("	%3d:	0x%08x\n", i, hw->palette_b[i]);
 #endif
 
 	printk("	HTOTAL_A:		0x%08x\n", hw->htotal_a);
@@ -680,11 +741,11 @@
 	}
 	for (i = 0; i < 3; i++) {
 		printk("	SWF3%d			0x%08x\n", i,
-			hw->swf3x[i]);
+		       hw->swf3x[i]);
 	}
 	for (i = 0; i < 8; i++)
 		printk("	FENCE%d			0x%08x\n", i,
-			hw->fence[i]);
+		       hw->fence[i]);
 
 	printk("	INSTPM			0x%08x\n", hw->instpm);
 	printk("	MEM_MODE		0x%08x\n", hw->mem_mode);
@@ -695,57 +756,84 @@
 #endif
 }
 
+
+
 /* Split the M parameter into M1 and M2. */
 static int
-splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
 {
 	int m1, m2;
-
-	m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
-	if (m1 < MIN_M1)
-		m1 = MIN_M1;
-	if (m1 > MAX_M1)
-		m1 = MAX_M1;
-	m2 = m - 5 * (m1 + 2) - 2;
-	if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
-		return 1;
-	} else {
-		*retm1 = (unsigned int)m1;
-		*retm2 = (unsigned int)m2;
-		return 0;
+	int testm;
+	/* no point optimising too much - brute force m */
+	for (m1 = plls[index].min_m1; m1 < plls[index].max_m1+1; m1++) {
+		for (m2 = plls[index].min_m2; m2 < plls[index].max_m2+1; m2++) {
+			testm  = ( 5 * ( m1 + 2 )) + (m2 + 2);
+			if (testm == m) {
+				*retm1 = (unsigned int)m1;
+				*retm2 = (unsigned int)m2;
+				return 0;
+			}
+		}
 	}
+	return 1;
 }
 
 /* Split the P parameter into P1 and P2. */
 static int
-splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
 {
 	int p1, p2;
 
-	if (p % 4 == 0)
-		p2 = 1;
-	else
-		p2 = 0;
-	p1 = (p / (1 << (p2 + 1))) - 2;
-	if (p % 4 == 0 && p1 < MIN_P1) {
-		p2 = 0;
-		p1 = (p / (1 << (p2 + 1))) - 2;
-	}
-	if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
-		return 1;
-	} else {
+	if (index == PLLS_I9xx) {
+		switch (p) {
+		case 10:
+			p1 = 2;
+			p2 = 0;
+			break;
+		case 20:
+			p1 = 1;
+			p2 = 0;
+			break;
+		default:
+			p1 = (p / 10) + 1;
+			p2 = 0;
+			break;
+		}
+		
 		*retp1 = (unsigned int)p1;
 		*retp2 = (unsigned int)p2;
 		return 0;
 	}
+
+	if (index == PLLS_I8xx) {
+		if (p % 4 == 0)
+			p2 = 1;
+		else
+			p2 = 0;
+		p1 = (p / (1 << (p2 + 1))) - 2;
+		if (p % 4 == 0 && p1 < plls[index].min_p1) {
+			p2 = 0;
+			p1 = (p / (1 << (p2 + 1))) - 2;
+		}
+		if (p1 < plls[index].min_p1 ||
+		    p1 > plls[index].max_p1 ||
+		    (p1 + 2) * (1 << (p2 + 1)) != p) {
+			return 1;
+		} else {
+			*retp1 = (unsigned int)p1;
+			*retp2 = (unsigned int)p2;
+			return 0;
+		}
+	}
+	return 1;
 }
 
 static int
-calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
 		u32 *retp2, u32 *retclock)
 {
-	u32 m1, m2, n, p1, p2, n1;
-	u32 f_vco, p, p_best = 0, m, f_out;
+	u32 m1, m2, n, p1, p2, n1, testm;
+	u32 f_vco, p, p_best = 0, m, f_out = 0;
 	u32 err_max, err_target, err_best = 10000000;
 	u32 n_best = 0, m_best = 0, f_best, f_err;
 	u32 p_min, p_max, p_inc, div_min, div_max;
@@ -756,58 +844,72 @@
 
 	DBG_MSG("Clock is %d\n", clock);
 
-	div_max = MAX_VCO_FREQ / clock;
-	div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+	div_max = plls[index].max_vco_freq / clock;
+	if (index == PLLS_I9xx)
+		div_min = 5;
+	else
+		div_min = ROUND_UP_TO(plls[index].min_vco_freq, clock) / clock;
 
-	if (clock <= P_TRANSITION_CLOCK)
-		p_inc = 4;
+	if (clock <= plls[index].p_transition_clock)
+		p_inc = plls[index].p_inc_lo;
 	else
-		p_inc = 2;
+		p_inc = plls[index].p_inc_hi;
 	p_min = ROUND_UP_TO(div_min, p_inc);
 	p_max = ROUND_DOWN_TO(div_max, p_inc);
-	if (p_min < MIN_P)
-		p_min = 4;
-	if (p_max > MAX_P)
-		p_max = 128;
+	if (p_min < plls[index].min_p)
+		p_min = plls[index].min_p;
+	if (p_max > plls[index].max_p)
+		p_max = plls[index].max_p;
+
+	if (clock < PLL_REFCLK && index == PLLS_I9xx) {
+		p_min = 10;
+		p_max = 20;
+		/* this makes 640x480 work it really shouldn't
+		   - SOMEONE WITHOUT DOCS WOZ HERE */
+		if (clock < 30000)
+			clock *= 4;
+	}
 
 	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
 
 	p = p_min;
 	do {
-		if (splitp(p, &p1, &p2)) {
+		if (splitp(index, p, &p1, &p2)) {
 			WRN_MSG("cannot split p = %d\n", p);
 			p += p_inc;
 			continue;
 		}
-		n = MIN_N;
+		n = plls[index].min_n;
 		f_vco = clock * p;
 
 		do {
 			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
-			if (m < MIN_M)
-				m = MIN_M;
-			if (m > MAX_M)
-				m = MAX_M;
-			f_out = CALC_VCLOCK3(m, n, p);
-			if (splitm(m, &m1, &m2)) {
-				WRN_MSG("cannot split m = %d\n", m);
-				n++;
-				continue;
-			}
-			if (clock > f_out)
-				f_err = clock - f_out;
-			else
-				f_err = f_out - clock;
-
-			if (f_err < err_best) {
-				m_best = m;
-				n_best = n;
-				p_best = p;
-				f_best = f_out;
-				err_best = f_err;
+			if (m < plls[index].min_m)
+				m = plls[index].min_m + 1;
+			if (m > plls[index].max_m)
+				m = plls[index].max_m - 1;
+			for (testm = m - 1; testm <= m; testm++) {
+				f_out = calc_vclock3(index, m, n, p);
+				if (splitm(index, m, &m1, &m2)) {
+					WRN_MSG("cannot split m = %d\n", m);
+					n++;
+					continue;
+				}
+				if (clock > f_out)
+					f_err = clock - f_out;
+				else/* slightly bias the error for bigger clocks */
+					f_err = f_out - clock + 1;
+				
+				if (f_err < err_best) {
+					m_best = m;
+					n_best = n;
+					p_best = p;
+					f_best = f_out;
+					err_best = f_err;
+				}
 			}
 			n++;
-		} while ((n <= MAX_N) && (f_out >= clock));
+		} while ((n <= plls[index].max_n) && (f_out >= clock));
 		p += p_inc;
 	} while ((p <= p_max));
 
@@ -818,21 +920,22 @@
 	m = m_best;
 	n = n_best;
 	p = p_best;
-	splitm(m, &m1, &m2);
-	splitp(p, &p1, &p2);
+	splitm(index, m, &m1, &m2);
+	splitp(index, p, &p1, &p2);
 	n1 = n - 2;
 
 	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
 		"f: %d (%d), VCO: %d\n",
 		m, m1, m2, n, n1, p, p1, p2,
-		CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
-		CALC_VCLOCK3(m, n, p) * p);
+		calc_vclock3(index, m, n, p),
+		calc_vclock(index, m1, m2, n1, p1, p2),
+		calc_vclock3(index, m, n, p) * p);
 	*retm1 = m1;
 	*retm2 = m2;
 	*retn = n1;
 	*retp1 = p1;
 	*retp2 = p2;
-	*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+	*retclock = calc_vclock(index, m1, m2, n1, p1, p2);
 
 	return 0;
 }
@@ -929,7 +1032,8 @@
 	/* Desired clock in kHz */
 	clock_target = 1000000000 / var->pixclock;
 
-	if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2, 
+			    &n, &p1, &p2, &clock)) {
 		WRN_MSG("calc_pll_params failed\n");
 		return 1;
 	}
@@ -1087,6 +1191,7 @@
 	u32 hsync_reg, htotal_reg, hblank_reg;
 	u32 vsync_reg, vtotal_reg, vblank_reg;
 	u32 src_size_reg;
+	u32 count, tmp_val[3];
 
 	/* Assume single pipe, display plane A, analog CRT. */
 
@@ -1155,6 +1260,27 @@
 		src_size_reg = SRC_SIZE_A;
 	}
 
+	/* turn off pipe */
+	tmp = INREG(pipe_conf_reg);
+	tmp &= ~PIPECONF_ENABLE;
+	OUTREG(pipe_conf_reg, tmp);
+	
+	count = 0;
+	do {
+	  tmp_val[count%3] = INREG(0x70000);
+	  if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+	    break;
+	  count++;
+	  udelay(1);
+	  if (count % 200 == 0) {
+	    tmp = INREG(pipe_conf_reg);
+	    tmp &= ~PIPECONF_ENABLE;
+	    OUTREG(pipe_conf_reg, tmp);
+	  }
+	} while(count < 2000);
+
+	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
+
 	/* Disable planes A and B. */
 	tmp = INREG(DSPACNTR);
 	tmp &= ~DISPPLANE_PLANE_ENABLE;
@@ -1172,10 +1298,8 @@
 	tmp |= ADPA_DPMS_D3;
 	OUTREG(ADPA, tmp);
 
-	/* turn off pipe */
-	tmp = INREG(pipe_conf_reg);
-	tmp &= ~PIPECONF_ENABLE;
-	OUTREG(pipe_conf_reg, tmp);
+	/* do some funky magic - xyzzy */
+	OUTREG(0x61204, 0xabcd0000);
 
 	/* turn off PLL */
 	tmp = INREG(dpll_reg);
@@ -1187,26 +1311,30 @@
 	OUTREG(fp0_reg, *fp0);
 	OUTREG(fp1_reg, *fp1);
 
-	/* Set pipe parameters */
-	OUTREG(hsync_reg, *hs);
-	OUTREG(hblank_reg, *hb);
-	OUTREG(htotal_reg, *ht);
-	OUTREG(vsync_reg, *vs);
-	OUTREG(vblank_reg, *vb);
-	OUTREG(vtotal_reg, *vt);
-	OUTREG(src_size_reg, *ss);
+	/* Enable PLL */
+	tmp = INREG(dpll_reg);
+	tmp |= DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
 
 	/* Set DVOs B/C */
 	OUTREG(DVOB, hw->dvob);
 	OUTREG(DVOC, hw->dvoc);
 
+	/* undo funky magic */
+	OUTREG(0x61204, 0x00000000);
+
 	/* Set ADPA */
+	OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
 	OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
 
-	/* Enable PLL */
-	tmp = INREG(dpll_reg);
-	tmp |= DPLL_VCO_ENABLE;
-	OUTREG(dpll_reg, tmp);
+	/* Set pipe parameters */
+	OUTREG(hsync_reg, *hs);
+	OUTREG(hblank_reg, *hb);
+	OUTREG(htotal_reg, *ht);
+	OUTREG(vsync_reg, *vs);
+	OUTREG(vblank_reg, *vb);
+	OUTREG(vtotal_reg, *vt);
+	OUTREG(src_size_reg, *ss);
 
 	/* Enable pipe */
 	OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
@@ -1616,7 +1744,7 @@
 	DBG_MSG("intelfbhw_cursor_init\n");
 #endif
 
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1649,7 +1777,7 @@
 #endif
 
 	dinfo->cursor_on = 0;
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1679,7 +1807,7 @@
 	if (dinfo->cursor_blanked)
 		return;
 
-	if (dinfo->mobile) {
+	if (dinfo->mobile || IS_I9xx(dinfo)) {
 		if (!dinfo->cursor.physical)
 			return;
 		tmp = INREG(CURSOR_A_CONTROL);
@@ -1713,6 +1841,10 @@
 	tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
 	      ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
 	OUTREG(CURSOR_A_POSITION, tmp);
+
+	if (IS_I9xx(dinfo)) {
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+	}
 }
 
 void
diff -urN oldtree/drivers/video/intelfb/intelfbhw.h newtree/drivers/video/intelfb/intelfbhw.h
--- oldtree/drivers/video/intelfb/intelfbhw.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/drivers/video/intelfb/intelfbhw.h	2006-04-01 05:35:39.507089000 -0500
@@ -155,29 +155,8 @@
 /* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
 /* Clock values are in units of kHz */
 #define PLL_REFCLK		48000
-#define MIN_VCO_FREQ		930000
-#define MAX_VCO_FREQ		1400000
 #define MIN_CLOCK		25000
 #define MAX_CLOCK		350000
-#define P_TRANSITION_CLOCK	165000
-#define MIN_M			108
-#define MAX_M			140
-#define MIN_M1			18
-#define MAX_M1			26
-#define MIN_M2			6
-#define MAX_M2			16
-#define MIN_P			4
-#define MAX_P			128
-#define MIN_P1			0
-#define MAX_P1			31
-#define MIN_N			3
-#define MAX_N			16
-
-#define CALC_VCLOCK(m1, m2, n, p1, p2) \
-        ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
-        (((p1) + 2) * (1 << (p2 + 1))))
-
-#define CALC_VCLOCK3(m, n, p)	((PLL_REFCLK * (m) / (n)) / (p))
 
 /* Two pipes */
 #define PIPE_A			0
@@ -522,8 +501,7 @@
 
 
 /* function protoypes */
-extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
-				 int *chipset, int *mobile);
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
 extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
 				int *stolen_size);
 extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
diff -urN oldtree/fs/Kconfig newtree/fs/Kconfig
--- oldtree/fs/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/Kconfig	2006-04-01 05:36:06.812795500 -0500
@@ -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
diff -urN oldtree/fs/Makefile newtree/fs/Makefile
--- oldtree/fs/Makefile	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/Makefile	2006-04-01 05:36:06.812795500 -0500
@@ -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/
diff -urN oldtree/fs/binfmt_elf_fdpic.c newtree/fs/binfmt_elf_fdpic.c
--- oldtree/fs/binfmt_elf_fdpic.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/binfmt_elf_fdpic.c	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/fs/bio.c	2006-04-01 05:35:45.875487000 -0500
@@ -620,10 +620,9 @@
 
 		nr_pages += end - start;
 		/*
-		 * transfer and buffer must be aligned to at least hardsector
-		 * size for now, in the future we can relax this restriction
+		 * buffer must be aligned to at least hardsector size for now
 		 */
-		if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q)))
+		if (uaddr & queue_dma_alignment(q))
 			return ERR_PTR(-EINVAL);
 	}
 
@@ -719,19 +718,21 @@
  *	@uaddr: start of user address
  *	@len: length in bytes
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@support_partial: support partial mappings
  *
  *	Map the user space address into a bio suitable for io to a block
  *	device. Returns an error pointer in case of error.
  */
 struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev,
-			 unsigned long uaddr, unsigned int len, int write_to_vm)
+			 unsigned long uaddr, unsigned int len, int write_to_vm,
+			 int support_partial)
 {
 	struct sg_iovec iov;
 
 	iov.iov_base = (void __user *)uaddr;
 	iov.iov_len = len;
 
-	return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm);
+	return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm, support_partial);
 }
 
 /**
@@ -741,13 +742,14 @@
  *	@iov:	the iovec.
  *	@iov_count: number of elements in the iovec
  *	@write_to_vm: bool indicating writing to pages or not
+ *	@support_partial: support partial mappings
  *
  *	Map the user space address into a bio suitable for io to a block
  *	device. Returns an error pointer in case of error.
  */
 struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev,
 			     struct sg_iovec *iov, int iov_count,
-			     int write_to_vm)
+			     int write_to_vm, int support_partial)
 {
 	struct bio *bio;
 	int len = 0, i;
@@ -768,7 +770,7 @@
 	for (i = 0; i < iov_count; i++)
 		len += iov[i].iov_len;
 
-	if (bio->bi_size == len)
+	if (bio->bi_size == len || support_partial)
 		return bio;
 
 	/*
diff -urN oldtree/fs/cifs/CHANGES newtree/fs/cifs/CHANGES
--- oldtree/fs/cifs/CHANGES	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/CHANGES	2006-04-01 05:35:35.822858750 -0500
@@ -1,3 +1,21 @@
+Version 1.42
+------------
+Fix slow oplock break when mounted to different servers at the same time and
+the tids match and we try to find matching fid on wrong server.
+
+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).  Fix wraparound of bcc on
+read responses when buffer size over 64K and also fix wrap of
+max smb buffer size when CIFSMaxBufSize over 64K.  Fix oops in
+cifs_user_read and cifs_readpages (when EAGAIN on send of smb
+on socket is returned over and over).  Add POSIX (advisory) byte range
+locking support (requires server with newest CIFS UNIX Extensions
+to the protocol implemented). Slow down negprot slightly in port 139
+RFC1001 case to give session_init time on buggy servers.
+
 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-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/Makefile	2006-04-01 05:35:35.822858750 -0500
@@ -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/README newtree/fs/cifs/README
--- oldtree/fs/cifs/README	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/README	2006-04-01 05:35:35.822858750 -0500
@@ -422,6 +422,13 @@
  nomapchars     Do not translate any of these seven characters (default).
  nocase         Request case insensitive path name matching (case
 		sensitive is the default if the server suports it).
+ posixpaths     If CIFS Unix extensions are supported, attempt to
+		negotiate posix path name support which allows certain
+		characters forbidden in typical CIFS filenames, without
+		requiring remapping. (default)
+ noposixpaths   If CIFS Unix extensions are supported, do not request
+		posix path name support (this may cause servers to
+		reject creatingfile with certain reserved characters).
  nobrl          Do not send byte range lock requests to the server.
 		This is necessary for certain applications that break
 		with cifs style mandatory byte range locks (and most
diff -urN oldtree/fs/cifs/cifsencrypt.c newtree/fs/cifs/cifsencrypt.c
--- oldtree/fs/cifs/cifsencrypt.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifsencrypt.c	2006-04-01 05:35:35.822858750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifsfs.c	2006-04-01 05:35:35.826859000 -0500
@@ -93,13 +93,10 @@
 	int rc = 0;
 
 	sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
-	sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+	sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
 	cifs_sb = CIFS_SB(sb);
 	if(cifs_sb == NULL)
 		return -ENOMEM;
-	else
-		memset(cifs_sb,0,sizeof(struct cifs_sb_info));
-	
 
 	rc = cifs_mount(sb, cifs_sb, data, devname);
 
diff -urN oldtree/fs/cifs/cifsfs.h newtree/fs/cifs/cifsfs.h
--- oldtree/fs/cifs/cifsfs.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifsfs.h	2006-04-01 05:35:35.826859000 -0500
@@ -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.42"
 #endif				/* _CIFSFS_H */
diff -urN oldtree/fs/cifs/cifsglob.h newtree/fs/cifs/cifsglob.h
--- oldtree/fs/cifs/cifsglob.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifsglob.h	2006-04-01 05:35:35.826859000 -0500
@@ -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/cifspdu.h newtree/fs/cifs/cifspdu.h
--- oldtree/fs/cifs/cifspdu.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifspdu.h	2006-04-01 05:35:35.826859000 -0500
@@ -859,7 +859,10 @@
 	LOCKING_ANDX_RANGE Locks[1];
 } __attribute__((packed)) LOCK_REQ;
 
-
+/* lock type */
+#define CIFS_RDLCK	0
+#define CIFS_WRLCK	1
+#define CIFS_UNLCK      2
 typedef struct cifs_posix_lock {
 	__le16  lock_type;  /* 0 = Read, 1 = Write, 2 = Unlock */
 	__le16  lock_flags; /* 1 = Wait (only valid for setlock) */
@@ -1786,7 +1789,13 @@
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
-#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Allow POSIX path chars  */
+#ifdef CONFIG_CIFS_POSIX
+#define CIFS_UNIX_CAP_MASK              0x0000001b
+#else 
+#define CIFS_UNIX_CAP_MASK              0x00000013
+#endif /* CONFIG_CIFS_POSIX */
+
 
 #define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
 
diff -urN oldtree/fs/cifs/cifsproto.h newtree/fs/cifs/cifsproto.h
--- oldtree/fs/cifs/cifsproto.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifsproto.h	2006-04-01 05:35:35.826859000 -0500
@@ -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 *);
@@ -257,7 +265,10 @@
 			const __u64 offset, const __u32 numUnlock,
 			const __u32 numLock, const __u8 lockType,
 			const int waitFlag);
-
+extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+			const __u16 smb_file_id, const int get_flag,
+			const __u64 len, const __u64 offset, 
+			const __u16 lock_type, const int waitFlag);
 extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
 
diff -urN oldtree/fs/cifs/cifssmb.c newtree/fs/cifs/cifssmb.c
--- oldtree/fs/cifs/cifssmb.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/cifssmb.c	2006-04-01 05:35:35.830859250 -0500
@@ -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
@@ -1042,7 +1070,7 @@
 		}
 	}
 
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	if(*buf) {
 		if(resp_buf_type == CIFS_SMALL_BUFFER)
 			cifs_small_buf_release(iov[0].iov_base);
@@ -1246,7 +1274,7 @@
 		*nbytes += le16_to_cpu(pSMBr->Count);
 	} 
 
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	if(resp_buf_type == CIFS_SMALL_BUFFER)
 		cifs_small_buf_release(iov[0].iov_base);
 	else if(resp_buf_type == CIFS_LARGE_BUFFER)
@@ -1325,6 +1353,85 @@
 }
 
 int
+CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+		const __u16 smb_file_id, const int get_flag, const __u64 len,
+		const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+	struct cifs_posix_lock *parm_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("Posix Lock"));
+	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+	if (rc)
+		return rc;
+
+	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+	params = 6; 
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+	count = sizeof(struct cifs_posix_lock);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	if(get_flag)
+		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+	else
+		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	parm_data = (struct cifs_posix_lock *) 
+			(((char *) &pSMB->hdr.Protocol) + offset);
+
+	parm_data->lock_type = cpu_to_le16(lock_type);
+	if(waitFlag)
+		parm_data->lock_flags = 1;
+	parm_data->pid = cpu_to_le32(current->tgid);
+	parm_data->start = lkoffset;
+	parm_data->length = len;  /* normalize negative numbers */
+
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = smb_file_id;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in Posix Lock = %d", rc));
+	}
+
+	if (pSMB)
+		cifs_small_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+	   since file handle passed in no longer valid */
+
+	return rc;
+}
+
+
+int
 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
 {
 	int rc = 0;
@@ -2578,7 +2685,7 @@
 		cifs_small_buf_release(iov[0].iov_base);
 	else if(buf_type == CIFS_LARGE_BUFFER)
 		cifs_buf_release(iov[0].iov_base);
-	cifs_small_buf_release(pSMB);
+/*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	return rc;
 }
 
@@ -2954,7 +3061,8 @@
 	pSMB->TotalParameterCount = cpu_to_le16(params);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
 	pSMB->ParameterOffset = cpu_to_le16(
-	  offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
+		- 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
@@ -2977,12 +3085,12 @@
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	cifs_stats_inc(&tcon->num_ffirst);
 
-	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+	if (rc) {/* BB add logic to retry regular search if Unix search
+			rejected unexpectedly by server */
 		/* BB Add code to handle unsupported level rc */
 		cFYI(1, ("Error in FindFirst = %d", rc));
 
-		if (pSMB)
-			cifs_buf_release(pSMB);
+		cifs_buf_release(pSMB);
 
 		/* BB eventually could optimize out free and realloc of buf */
 		/*    for this case */
@@ -2998,6 +3106,7 @@
 				psrch_inf->unicode = FALSE;
 
 			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
+			psrch_inf->smallBuf = 0;
 			psrch_inf->srch_entries_start = 
 				(char *) &pSMBr->hdr.Protocol + 
 					le16_to_cpu(pSMBr->t2.DataOffset);
@@ -3118,9 +3227,14 @@
 			parms = (T2_FNEXT_RSP_PARMS *)response_data;
 			response_data = (char *)&pSMBr->hdr.Protocol +
 				le16_to_cpu(pSMBr->t2.DataOffset);
-			cifs_buf_release(psrch_inf->ntwrk_buf_start);
+			if(psrch_inf->smallBuf)
+				cifs_small_buf_release(
+					psrch_inf->ntwrk_buf_start);
+			else
+				cifs_buf_release(psrch_inf->ntwrk_buf_start);
 			psrch_inf->srch_entries_start = response_data;
 			psrch_inf->ntwrk_buf_start = (char *)pSMB;
+			psrch_inf->smallBuf = 0;
 			if(parms->EndofSearch)
 				psrch_inf->endOfSearch = TRUE;
 			else
@@ -3834,6 +3948,7 @@
 
 	cFYI(1, ("In SETFSUnixInfo"));
 SETFSUnixRetry:
+	/* BB switch to small buf init to save memory */
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
 	if (rc)
diff -urN oldtree/fs/cifs/connect.c newtree/fs/cifs/connect.c
--- oldtree/fs/cifs/connect.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/connect.c	2006-04-01 05:35:35.830859250 -0500
@@ -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
@@ -564,7 +564,7 @@
 	
 
 		dump_smb(smb_buffer, length);
-		if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
+		if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
 			cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
 			continue;
 		}
@@ -1476,6 +1476,14 @@
 			rc = smb_send(*csocket, smb_buf, 0x44,
 				(struct sockaddr *)psin_server);
 			kfree(ses_init_buf);
+			msleep(1); /* RFC1001 layer in at least one server 
+				      requires very short break before negprot
+				      presumably because not expecting negprot
+				      to follow so fast.  This is a simple
+				      solution that works without 
+				      complicating the code and causes no
+				      significant slowing down on mount
+				      for everyone else */
 		}
 		/* else the negprot may still work without this 
 		even though malloc failed */
@@ -1920,27 +1928,34 @@
 		cifs_sb->tcon = tcon;
 		tcon->ses = pSesInfo;
 
-		/* do not care if following two calls succeed - informational only */
+		/* do not care if following two calls succeed - informational */
 		CIFSSMBQFSDeviceInfo(xid, tcon);
 		CIFSSMBQFSAttributeInfo(xid, tcon);
+
 		if (tcon->ses->capabilities & CAP_UNIX) {
 			if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
-				if(!volume_info.no_psx_acl) {
-					if(CIFS_UNIX_POSIX_ACL_CAP & 
-					   le64_to_cpu(tcon->fsUnixInfo.Capability))
-						cFYI(1,("server negotiated posix acl support"));
-						sb->s_flags |= MS_POSIXACL;
+				__u64 cap = 
+				       le64_to_cpu(tcon->fsUnixInfo.Capability);
+				cap &= CIFS_UNIX_CAP_MASK;
+				if(volume_info.no_psx_acl)
+					cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+				else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+					cFYI(1,("negotiated posix acl support"));
+					sb->s_flags |= MS_POSIXACL;
+				}
+
+				if(volume_info.posix_paths == 0)
+					cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+				else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+					cFYI(1,("negotiate posix pathnames"));
+					cifs_sb->mnt_cifs_flags |= 
+						CIFS_MOUNT_POSIX_PATHS;
 				}
+					
+				cFYI(1,("Negotiate caps 0x%x",(int)cap));
 
-				/* Try and negotiate POSIX pathnames if we can. */
-				if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
-				    le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-					if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
-						cFYI(1,("negotiated posix pathnames support"));
-						cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
-					} else {
-						cFYI(1,("posix pathnames support requested but not supported"));
-					}
+				if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+					cFYI(1,("setting capabilities failed"));
 				}
 			}
 		}
@@ -2278,6 +2293,8 @@
 	smb_buffer->Mid = GetNextMid(ses->server);
 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 	pSMB->req.AndXCommand = 0xFF;
+	if(ses->server->maxBuf > 64*1024)
+		ses->server->maxBuf = (64*1023);
 	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
 	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
 
@@ -2525,7 +2542,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 +2592,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 +2606,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 +2680,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 +2688,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 +2821,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 +2833,7 @@
 		}
 	} else {
 		cERROR(1,
-		       (" Invalid Word count %d: ",
+		       (" Invalid Word count %d:",
 			smb_buffer_response->WordCount));
 		rc = -EIO;
 	}
@@ -3447,7 +3450,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 +3458,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/dir.c newtree/fs/cifs/dir.c
--- oldtree/fs/cifs/dir.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/dir.c	2006-04-01 05:35:35.830859250 -0500
@@ -48,13 +48,14 @@
 	struct dentry *temp;
 	int namelen = 0;
 	char *full_path;
-	char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
+	char dirsep;
 
 	if(direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
 		we need to reopen the file after it was closed implicitly
 		when the server crashed */
 
+	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 cifs_bp_rename_retry:
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
@@ -255,12 +256,10 @@
 			CIFSSMBClose(xid, pTcon, fileHandle);
 		} else if(newinode) {
 			pCifsFile =
-			   kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+			   kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
 			
 			if(pCifsFile == NULL)
 				goto cifs_create_out;
-			memset((char *)pCifsFile, 0,
-			       sizeof (struct cifsFileInfo));
 			pCifsFile->netfid = fileHandle;
 			pCifsFile->pid = current->tgid;
 			pCifsFile->pInode = newinode;
diff -urN oldtree/fs/cifs/file.c newtree/fs/cifs/file.c
--- oldtree/fs/cifs/file.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/file.c	2006-04-01 05:35:35.834859500 -0500
@@ -555,7 +555,10 @@
 		if (ptmp) {
 			cFYI(1, ("closedir free smb buf in srch struct"));
 			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-			cifs_buf_release(ptmp);
+			if(pCFileStruct->srch_inf.smallBuf)
+				cifs_small_buf_release(ptmp);
+			else
+				cifs_buf_release(ptmp);
 		}
 		ptmp = pCFileStruct->search_resume_name;
 		if (ptmp) {
@@ -574,13 +577,14 @@
 int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 {
 	int rc, xid;
-	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
 	__u32 numLock = 0;
 	__u32 numUnlock = 0;
 	__u64 length;
 	int wait_flag = FALSE;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
+	__u16 netfid;
+	__u8 lockType = LOCKING_ANDX_LARGE_FILES;
 
 	length = 1 + pfLock->fl_end - pfLock->fl_start;
 	rc = -EACCES;
@@ -592,11 +596,11 @@
 	        pfLock->fl_end));
 
 	if (pfLock->fl_flags & FL_POSIX)
-		cFYI(1, ("Posix "));
+		cFYI(1, ("Posix"));
 	if (pfLock->fl_flags & FL_FLOCK)
-		cFYI(1, ("Flock "));
+		cFYI(1, ("Flock"));
 	if (pfLock->fl_flags & FL_SLEEP) {
-		cFYI(1, ("Blocking lock "));
+		cFYI(1, ("Blocking lock"));
 		wait_flag = TRUE;
 	}
 	if (pfLock->fl_flags & FL_ACCESS)
@@ -612,21 +616,23 @@
 		cFYI(1, ("F_WRLCK "));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_UNLCK) {
-		cFYI(1, ("F_UNLCK "));
+		cFYI(1, ("F_UNLCK"));
 		numUnlock = 1;
+		/* Check if unlock includes more than
+		one lock range */
 	} else if (pfLock->fl_type == F_RDLCK) {
-		cFYI(1, ("F_RDLCK "));
+		cFYI(1, ("F_RDLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else if (pfLock->fl_type == F_EXLCK) {
-		cFYI(1, ("F_EXLCK "));
+		cFYI(1, ("F_EXLCK"));
 		numLock = 1;
 	} else if (pfLock->fl_type == F_SHLCK) {
-		cFYI(1, ("F_SHLCK "));
+		cFYI(1, ("F_SHLCK"));
 		lockType |= LOCKING_ANDX_SHARED_LOCK;
 		numLock = 1;
 	} else
-		cFYI(1, ("Unknown type of lock "));
+		cFYI(1, ("Unknown type of lock"));
 
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
 	pTcon = cifs_sb->tcon;
@@ -635,27 +641,41 @@
 		FreeXid(xid);
 		return -EBADF;
 	}
+	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
+
+	/* BB add code here to normalize offset and length to
+	account for negative length which we can not accept over the
+	wire */
 	if (IS_GETLK(cmd)) {
-		rc = CIFSSMBLock(xid, pTcon,
-				 ((struct cifsFileInfo *)file->
-				  private_data)->netfid,
-				 length,
-				 pfLock->fl_start, 0, 1, lockType,
-				 0 /* wait flag */ );
+		if(experimEnabled && 
+		   (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		   (CIFS_UNIX_FCNTL_CAP & 
+			le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+			int posix_lock_type;
+			if(lockType & LOCKING_ANDX_SHARED_LOCK)
+				posix_lock_type = CIFS_RDLCK;
+			else
+				posix_lock_type = CIFS_WRLCK;
+			rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+					length,	pfLock->fl_start,
+					posix_lock_type, wait_flag);
+			FreeXid(xid);
+			return rc;
+		}
+
+		/* BB we could chain these into one lock request BB */
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				 0, 1, lockType, 0 /* wait flag */ );
 		if (rc == 0) {
-			rc = CIFSSMBLock(xid, pTcon,
-					 ((struct cifsFileInfo *) file->
-					  private_data)->netfid,
-					 length,
+			rc = CIFSSMBLock(xid, pTcon, netfid, length, 
 					 pfLock->fl_start, 1 /* numUnlock */ ,
 					 0 /* numLock */ , lockType,
 					 0 /* wait flag */ );
 			pfLock->fl_type = F_UNLCK;
 			if (rc != 0)
 				cERROR(1, ("Error unlocking previously locked "
-					   "range %d during test of lock ",
-					   rc));
+					   "range %d during test of lock", rc));
 			rc = 0;
 
 		} else {
@@ -667,12 +687,30 @@
 		FreeXid(xid);
 		return rc;
 	}
-
-	rc = CIFSSMBLock(xid, pTcon,
-			 ((struct cifsFileInfo *) file->private_data)->
-			 netfid, length,
-			 pfLock->fl_start, numUnlock, numLock, lockType,
-			 wait_flag);
+	if (experimEnabled &&
+		(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
+		(CIFS_UNIX_FCNTL_CAP &
+			 le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
+		int posix_lock_type;
+		if(lockType & LOCKING_ANDX_SHARED_LOCK)
+			posix_lock_type = CIFS_RDLCK;
+		else
+			posix_lock_type = CIFS_WRLCK;
+		
+		if(numUnlock == 1)
+			posix_lock_type = CIFS_UNLCK;
+		else if(numLock == 0) {
+			/* if no lock or unlock then nothing
+			to do since we do not know what it is */
+			FreeXid(xid);
+			return -EOPNOTSUPP;
+		}
+		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+				      length, pfLock->fl_start,
+				      posix_lock_type, wait_flag);
+	} else
+		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+				numUnlock, numLock, lockType, wait_flag);
 	if (pfLock->fl_flags & FL_POSIX)
 		posix_lock_file_wait(file, pfLock);
 	FreeXid(xid);
diff -urN oldtree/fs/cifs/inode.c newtree/fs/cifs/inode.c
--- oldtree/fs/cifs/inode.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/inode.c	2006-04-01 05:35:35.834859500 -0500
@@ -609,9 +609,8 @@
 		}
 	} else if (rc == -EACCES) {
 		/* try only if r/o attribute set in local lookup data? */
-		pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
+		pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
 		if (pinfo_buf) {
-			memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
 			/* ATTRS set to normal clears r/o bit */
 			pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
 			if (!(pTcon->ses->flags & CIFS_SES_NT4))
@@ -1167,7 +1166,7 @@
 						nfid, npid, FALSE);
 			atomic_dec(&open_file->wrtPending);
 			cFYI(1,("SetFSize for attrs rc = %d", rc));
-			if(rc == -EINVAL) {
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 				int bytes_written;
 				rc = CIFSSMBWrite(xid, pTcon,
 						  nfid, 0, attrs->ia_size,
@@ -1189,7 +1188,7 @@
 					   cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
-			if(rc == -EINVAL) {
+			if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
 				__u16 netfid;
 				int oplock = FALSE;
 
diff -urN oldtree/fs/cifs/link.c newtree/fs/cifs/link.c
--- oldtree/fs/cifs/link.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/link.c	2006-04-01 05:35:35.834859500 -0500
@@ -67,7 +67,7 @@
 					cifs_sb_target->local_nls, 
 					cifs_sb_target->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
-		if(rc == -EIO)
+		if((rc == -EIO) || (rc == -EINVAL))
 			rc = -EOPNOTSUPP;  
 	}
 
diff -urN oldtree/fs/cifs/misc.c newtree/fs/cifs/misc.c
--- oldtree/fs/cifs/misc.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/misc.c	2006-04-01 05:35:35.834859500 -0500
@@ -72,10 +72,9 @@
 	struct cifsSesInfo *ret_buf;
 
 	ret_buf =
-	    (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
+	    (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo),
 					   GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsSesInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&sesInfoAllocCount);
 		ret_buf->status = CifsNew;
@@ -110,10 +109,9 @@
 {
 	struct cifsTconInfo *ret_buf;
 	ret_buf =
-	    (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
+	    (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo),
 					    GFP_KERNEL);
 	if (ret_buf) {
-		memset(ret_buf, 0, sizeof (struct cifsTconInfo));
 		write_lock(&GlobalSMBSeslock);
 		atomic_inc(&tconInfoAllocCount);
 		list_add(&ret_buf->cifsConnectionList,
@@ -423,9 +421,7 @@
 {
 	__u32 len = smb->smb_buf_length;
 	__u32 clc_len;  /* calculated length */
-	cFYI(0,
-	     ("Entering checkSMB with Length: %x, smb_buf_length: %x",
-	      length, len));
+	cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
 	if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
 	    (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
 		if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
@@ -433,29 +429,36 @@
 				sizeof (struct smb_hdr) - 1)
 			    && (smb->Status.CifsError != 0)) {
 				smb->WordCount = 0;
-				return 0;	/* some error cases do not return wct and bcc */
+				/* some error cases do not return wct and bcc */
+				return 0;
 			} else {
 				cERROR(1, ("Length less than smb header size"));
 			}
-
 		}
 		if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
-			cERROR(1,
-			       ("smb_buf_length greater than MaxBufSize"));
-		cERROR(1,
-		       ("bad smb detected. Illegal length. mid=%d",
-			smb->Mid));
+			cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+				   smb->Mid));
 		return 1;
 	}
 
 	if (checkSMBhdr(smb, mid))
 		return 1;
 	clc_len = smbCalcSize_LE(smb);
-	if ((4 + len != clc_len)
-	    || (4 + len != (unsigned int)length)) {
-		cERROR(1, ("Calculated size 0x%x vs actual length 0x%x",
-				clc_len, 4 + len));
-		cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
+
+	if(4 + len != (unsigned int)length) {
+		cERROR(1, ("Length read does not match RFC1001 length %d",len));
+		return 1;
+	}
+
+	if (4 + len != clc_len) {
+		/* check if bcc wrapped around for large read responses */
+		if((len > 64 * 1024) && (len > clc_len)) {
+			/* check if lengths match mod 64K */
+			if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
+				return 0; /* bcc wrapped */			
+		}
+		cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
+				clc_len, 4 + len, smb->Mid));
 		/* Windows XP can return a few bytes too much, presumably
 		an illegal pad, at the end of byte range lock responses 
 		so we allow for that three byte pad, as long as actual
@@ -469,8 +472,11 @@
 		wct and bcc to minimum size and drop the t2 parms and data */
 		if((4+len > clc_len) && (len <= clc_len + 512))
 			return 0;
-		else
+		else {
+			cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
+					len, smb->Mid));
 			return 1;
+		}
 	}
 	return 0;
 }
diff -urN oldtree/fs/cifs/ntlmssp.c newtree/fs/cifs/ntlmssp.c
--- oldtree/fs/cifs/ntlmssp.c	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/cifs/ntlmssp.c	2006-04-01 05:35:35.834859500 -0500
@@ -0,0 +1,129 @@
+/*
+ *   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); */
+	/* SMB request buf freed in SendReceive2 */
+
+	return rc;
+}
+#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff -urN oldtree/fs/cifs/ntlmssp.h newtree/fs/cifs/ntlmssp.h
--- oldtree/fs/cifs/ntlmssp.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/ntlmssp.h	2006-04-01 05:35:35.834859500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/readdir.c	2006-04-01 05:35:35.834859500 -0500
@@ -604,7 +604,12 @@
 		cifsFile->search_resume_name = NULL;
 		if(cifsFile->srch_inf.ntwrk_buf_start) {
 			cFYI(1,("freeing SMB ff cache buf on search rewind"));
-			cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
+			if(cifsFile->srch_inf.smallBuf)
+				cifs_small_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
+			else
+				cifs_buf_release(cifsFile->srch_inf.
+						ntwrk_buf_start);
 		}
 		rc = initiate_cifs_search(xid,file);
 		if(rc) {
diff -urN oldtree/fs/cifs/transport.c newtree/fs/cifs/transport.c
--- oldtree/fs/cifs/transport.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/cifs/transport.c	2006-04-01 05:35:35.838859750 -0500
@@ -309,17 +309,16 @@
 	
 	*pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
 
-	if (ses == NULL) {
-		cERROR(1,("Null smb session"));
-		return -EIO;
-	}
-	if(ses->server == NULL) {
-		cERROR(1,("Null tcp session"));
+	if ((ses == NULL) || (ses->server == NULL)) {
+		cifs_small_buf_release(in_buf);
+		cERROR(1,("Null session"));
 		return -EIO;
 	}
 
-	if(ses->server->tcpStatus == CifsExiting)
+	if(ses->server->tcpStatus == CifsExiting) {
+		cifs_small_buf_release(in_buf);
 		return -ENOENT;
+	}
 
 	/* Ensure that we do not send more than 50 overlapping requests 
 	   to the same server. We may make this configurable later or
@@ -346,6 +345,7 @@
 			} else {
 				if(ses->server->tcpStatus == CifsExiting) {
 					spin_unlock(&GlobalMid_Lock);
+					cifs_small_buf_release(in_buf);
 					return -ENOENT;
 				}
 
@@ -385,6 +385,7 @@
 	midQ = AllocMidQEntry(in_buf, ses);
 	if (midQ == NULL) {
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
@@ -408,14 +409,18 @@
 	if(rc < 0) {
 		DeleteMidQEntry(midQ);
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
 		/* If not lock req, update # of requests on wire to server */
 		if(long_op < 3) {
 			atomic_dec(&ses->server->inFlight); 
 			wake_up(&ses->server->request_q);
 		}
 		return rc;
-	} else
+	} else {
 		up(&ses->server->tcpSem);
+		cifs_small_buf_release(in_buf);
+	}
+
 	if (long_op == -1)
 		goto cifs_no_response_exit2;
 	else if (long_op == 2) /* writes past end of file can take loong time */
@@ -543,6 +548,7 @@
 
 out_unlock2:
 	up(&ses->server->tcpSem);
+	cifs_small_buf_release(in_buf);
 	/* If not lock req, update # of requests on wire to server */
 	if(long_op < 3) {
 		atomic_dec(&ses->server->inFlight); 
diff -urN oldtree/fs/fs-writeback.c newtree/fs/fs-writeback.c
--- oldtree/fs/fs-writeback.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/fs/fs-writeback.c	2006-04-01 05:36:06.756792000 -0500
@@ -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/reiser4/Kconfig newtree/fs/reiser4/Kconfig
--- oldtree/fs/reiser4/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/Kconfig	2006-04-01 05:36:09.000932250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/Makefile	2006-04-01 05:36:10.008995250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/README	2006-04-01 05:36:06.972805500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/as_ops.c	2006-04-01 05:36:11.509089000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/block_alloc.c	2006-04-01 05:36:09.600969750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/block_alloc.h	2006-04-01 05:36:08.956929500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/blocknrset.c	2006-04-01 05:36:09.600969750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/carry.c	2006-04-01 05:36:09.600969750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/carry.h	2006-04-01 05:36:08.960929750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/carry_ops.c	2006-04-01 05:36:09.604970000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/carry_ops.h	2006-04-01 05:36:08.964930000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/context.c	2006-04-01 05:36:11.557092000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/context.h	2006-04-01 05:36:11.557092000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/coord.c	2006-04-01 05:36:09.604970000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/coord.h	2006-04-01 05:36:08.968930250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/debug.c	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/debug.h	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/dformat.h	2006-04-01 05:36:09.460961000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/dscale.c	2006-04-01 05:36:09.464961250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/dscale.h	2006-04-01 05:36:08.972930500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/emergency_flush.c	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/emergency_flush.h	2006-04-01 05:36:09.608970250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/entd.c	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/entd.h	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/eottl.c	2006-04-01 05:36:09.612970500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/estimate.c	2006-04-01 05:36:11.513089250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/export_ops.c	2006-04-01 05:36:08.976930750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/flush.c	2006-04-01 05:36:11.517089500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/flush.h	2006-04-01 05:36:10.008995250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/flush_queue.c	2006-04-01 05:36:11.481087250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/forward.h	2006-04-01 05:36:09.464961250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/fsdata.c	2006-04-01 05:36:11.557092000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/fsdata.h	2006-04-01 05:36:11.557092000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/init_super.c	2006-04-01 05:36:11.517089500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/inode.c	2006-04-01 05:36:11.481087250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/inode.h	2006-04-01 05:36:11.557092000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/ioctl.h	2006-04-01 05:36:06.896800750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/jnode.c	2006-04-01 05:36:11.517089500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/jnode.h	2006-04-01 05:36:11.517089500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/kassign.c	2006-04-01 05:36:09.468961500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/kassign.h	2006-04-01 05:36:09.000932250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/key.c	2006-04-01 05:36:11.517089500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/key.h	2006-04-01 05:36:11.485087500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/ktxnmgrd.c	2006-04-01 05:36:09.468961500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/ktxnmgrd.h	2006-04-01 05:36:09.620971000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/lock.c	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/lock.h	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/oid.c	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/page_cache.c	2006-04-01 05:36:11.521089750 -0500
@@ -0,0 +1,757 @@
+/* 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;
+	*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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/page_cache.h	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/cluster.c	2006-04-01 05:36:10.008995250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/cluster.h	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/compress.c	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/compress.h	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/compress_mode.c	2006-04-01 05:36:11.521089750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/lzoconf.h	2006-04-01 05:36:09.008932750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/minilzo.c	2006-04-01 05:36:09.012933000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/compress/minilzo.h	2006-04-01 05:36:09.012933000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/crypto/cipher.c	2006-04-01 05:36:10.032996750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/crypto/cipher.h	2006-04-01 05:36:10.012995500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/crypto/digest.c	2006-04-01 05:36:10.012995500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/dir/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/dir/dir.h	2006-04-01 05:36:09.020933500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/dir/hashed_dir.c	2006-04-01 05:36:09.024933750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/dir/seekable_dir.c	2006-04-01 05:36:09.024933750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/dir_plugin_common.c	2006-04-01 05:36:11.561092250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/disk_format/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/disk_format/disk_format.c	2006-04-01 05:36:09.028934000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/disk_format/disk_format.h	2006-04-01 05:36:09.028934000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/disk_format/disk_format40.c	2006-04-01 05:36:09.544966250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/disk_format/disk_format40.h	2006-04-01 05:36:09.028934000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/fibration.c	2006-04-01 05:36:09.028934000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/fibration.h	2006-04-01 05:36:09.028934000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/cryptcompress.c	2006-04-01 05:36:11.561092250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/cryptcompress.h	2006-04-01 05:36:11.525090000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/file.c	2006-04-01 05:36:11.581093500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/file.h	2006-04-01 05:36:11.565092500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/funcs.h	2006-04-01 05:36:09.632971750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/invert.c	2006-04-01 05:36:09.040934750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/symfile.c	2006-04-01 05:36:09.044935000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/symlink.c	2006-04-01 05:36:09.044935000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file/tail_conversion.c	2006-04-01 05:36:11.529090250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file_ops.c	2006-04-01 05:36:09.632971750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file_ops_readdir.c	2006-04-01 05:36:11.565092500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/file_plugin_common.c	2006-04-01 05:36:11.565092500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/hash.c	2006-04-01 05:36:09.048935250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/inode_ops.c	2006-04-01 05:36:11.565092500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/inode_ops_rename.c	2006-04-01 05:36:09.048935250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/acl.h	2006-04-01 05:36:09.048935250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/blackbox.c	2006-04-01 05:36:09.048935250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/blackbox.h	2006-04-01 05:36:09.052935500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/cde.c	2006-04-01 05:36:09.476962000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/cde.h	2006-04-01 05:36:09.052935500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/ctail.c	2006-04-01 05:36:11.529090250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/ctail.h	2006-04-01 05:36:09.056935750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/extent.c	2006-04-01 05:36:09.056935750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/extent.h	2006-04-01 05:36:09.476962000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/extent_file_ops.c	2006-04-01 05:36:11.585093750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/extent_flush_ops.c	2006-04-01 05:36:09.636972000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/extent_item_ops.c	2006-04-01 05:36:09.636972000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/internal.c	2006-04-01 05:36:09.640972250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/internal.h	2006-04-01 05:36:09.064936250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/item.c	2006-04-01 05:36:09.064936250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/item.h	2006-04-01 05:36:09.476962000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/sde.c	2006-04-01 05:36:09.480962250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/sde.h	2006-04-01 05:36:09.068936500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/static_stat.c	2006-04-01 05:36:09.640972250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/static_stat.h	2006-04-01 05:36:09.480962250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/tail.c	2006-04-01 05:36:09.260948500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/item/tail.h	2006-04-01 05:36:09.072936750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/node/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/node/node.c	2006-04-01 05:36:09.076937000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/node/node.h	2006-04-01 05:36:09.480962250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/node/node40.c	2006-04-01 05:36:09.640972250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/node/node40.h	2006-04-01 05:36:09.076937000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/object.c	2006-04-01 05:36:11.533090500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/object.h	2006-04-01 05:36:09.952991750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/plugin.c	2006-04-01 05:36:11.489087750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/plugin.h	2006-04-01 05:36:11.533090500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/plugin_header.h	2006-04-01 05:36:10.040997250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/plugin_set.c	2006-04-01 05:36:10.040997250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/plugin_set.h	2006-04-01 05:36:10.040997250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/regular.c	2006-04-01 05:36:09.088937750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/security/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/security/perm.c	2006-04-01 05:36:09.916989500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/security/perm.h	2006-04-01 05:36:09.916989500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/space/Makefile	2006-04-01 05:36:09.896988250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/space/bitmap.c	2006-04-01 05:36:09.644972500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/space/bitmap.h	2006-04-01 05:36:09.320952250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/space/space_allocator.h	2006-04-01 05:36:06.968805250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/plugin/tail_policy.c	2006-04-01 05:36:09.092938000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/pool.c	2006-04-01 05:36:09.096938250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/pool.h	2006-04-01 05:36:09.096938250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/readahead.c	2006-04-01 05:36:11.533090500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/readahead.h	2006-04-01 05:36:11.489087750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/reiser4.h	2006-04-01 05:36:09.644972500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/safe_link.c	2006-04-01 05:36:09.484962500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/safe_link.h	2006-04-01 05:36:09.196944500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/seal.c	2006-04-01 05:36:09.644972500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/seal.h	2006-04-01 05:36:09.196944500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/search.c	2006-04-01 05:36:09.860986000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/status_flags.c	2006-04-01 05:36:09.488962750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/status_flags.h	2006-04-01 05:36:09.200944750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/super.c	2006-04-01 05:36:11.533090500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/super.h	2006-04-01 05:36:11.489087750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/super_ops.c	2006-04-01 05:36:09.648972750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tap.c	2006-04-01 05:36:09.204945000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tap.h	2006-04-01 05:36:09.204945000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree.c	2006-04-01 05:36:11.533090500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree.h	2006-04-01 05:36:11.493088000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree_mod.c	2006-04-01 05:36:09.652973000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree_mod.h	2006-04-01 05:36:07.084812500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree_walk.c	2006-04-01 05:36:11.537090750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/tree_walk.h	2006-04-01 05:36:11.493088000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/txnmgr.c	2006-04-01 05:36:11.537090750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/txnmgr.h	2006-04-01 05:36:11.537090750 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/type_safe_hash.h	2006-04-01 05:36:07.092813000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/vfs_ops.c	2006-04-01 05:36:09.656973250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/vfs_ops.h	2006-04-01 05:36:11.541091000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/wander.c	2006-04-01 05:36:11.541091000 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/wander.h	2006-04-01 05:36:09.224946250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/writeout.h	2006-04-01 05:36:09.660973500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/znode.c	2006-04-01 05:36:09.660973500 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/fs/reiser4/znode.h	2006-04-01 05:36:11.493088000 -0500
@@ -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/include/acpi/acconfig.h newtree/include/acpi/acconfig.h
--- oldtree/include/acpi/acconfig.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/acpi/acconfig.h	2006-04-01 05:35:30.766542750 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/acpi/acdisasm.h	2006-04-01 05:35:30.770543000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/acpi/acutils.h	2006-04-01 05:35:30.770543000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/acpi/pdc_intel.h	2006-04-01 05:35:30.770543000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/acpi/processor.h	2006-04-01 05:35:30.770543000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-alpha/serial.h	2006-04-01 05:36:15.353329250 -0500
@@ -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-at91rm9200/hardware.h newtree/include/asm-arm/arch-at91rm9200/hardware.h
--- oldtree/include/asm-arm/arch-at91rm9200/hardware.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-arm/arch-at91rm9200/hardware.h	2006-04-01 05:35:44.307389000 -0500
@@ -65,6 +65,9 @@
 /* SmartMedia */
 #define AT91_SMARTMEDIA_BASE	0x40000000	/* NCS3: Smartmedia physical base address */
 
+/* Compact Flash */
+#define AT91_CF_BASE		0x50000000	/* NCS4-NCS6: Compact Flash physical base address */
+
 /* Multi-Master Memory controller */
 #define AT91_UHP_BASE		0x00300000	/* USB Host controller */
 
diff -urN oldtree/include/asm-frv/checksum.h newtree/include/asm-frv/checksum.h
--- oldtree/include/asm-frv/checksum.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/checksum.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/highmem.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/io.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/mb-regs.h	2006-04-01 05:36:15.333328000 -0500
@@ -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/serial.h newtree/include/asm-frv/serial.h
--- oldtree/include/asm-frv/serial.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/serial.h	2006-04-01 05:36:15.353329250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/signal.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/uaccess.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-frv/unistd.h	2006-04-01 05:36:15.333328000 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-generic/mutex-dec.h	2006-04-01 05:35:54.412020500 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-generic/mutex-xchg.h	2006-04-01 05:35:54.412020500 -0500
@@ -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-i386/atomic.h newtree/include/asm-i386/atomic.h
--- oldtree/include/asm-i386/atomic.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-i386/atomic.h	2006-04-01 05:36:13.633221750 -0500
@@ -132,6 +132,10 @@
 {
 	unsigned char c;
 
+	if (!atomic_read(v)) {
+		printk("BUG: atomic counter underflow at:\n");
+		dump_stack();
+	}
 	__asm__ __volatile__(
 		LOCK "decl %0; sete %1"
 		:"=m" (v->counter), "=qm" (c)
diff -urN oldtree/include/asm-i386/serial.h newtree/include/asm-i386/serial.h
--- oldtree/include/asm-i386/serial.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-i386/serial.h	2006-04-01 05:36:15.353329250 -0500
@@ -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-m68k/serial.h newtree/include/asm-m68k/serial.h
--- oldtree/include/asm-m68k/serial.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-m68k/serial.h	2006-04-01 05:36:15.353329250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-m68k/signal.h	2006-04-01 05:36:15.305326250 -0500
@@ -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-ppc/pc_serial.h newtree/include/asm-ppc/pc_serial.h
--- oldtree/include/asm-ppc/pc_serial.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-ppc/pc_serial.h	2006-04-01 05:36:15.357329500 -0500
@@ -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-x86_64/acpi.h newtree/include/asm-x86_64/acpi.h
--- oldtree/include/asm-x86_64/acpi.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-x86_64/acpi.h	2006-04-01 05:35:30.770543000 -0500
@@ -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/serial.h newtree/include/asm-x86_64/serial.h
--- oldtree/include/asm-x86_64/serial.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/asm-x86_64/serial.h	2006-04-01 05:36:15.357329500 -0500
@@ -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/linux/bio.h newtree/include/linux/bio.h
--- oldtree/include/linux/bio.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/bio.h	2006-04-01 05:35:45.875487000 -0500
@@ -295,12 +295,13 @@
 extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
 			   unsigned int, unsigned int);
 extern int bio_get_nr_vecs(struct block_device *);
+extern int __bio_get_nr_vecs(struct request_queue *);
 extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
-				unsigned long, unsigned int, int);
+				unsigned long, unsigned int, int, int);
 struct sg_iovec;
 extern struct bio *bio_map_user_iov(struct request_queue *,
 				    struct block_device *,
-				    struct sg_iovec *, int, int);
+				    struct sg_iovec *, int, int, int);
 extern void bio_unmap_user(struct bio *);
 extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
 				gfp_t);
diff -urN oldtree/include/linux/cpufreq.h newtree/include/linux/cpufreq.h
--- oldtree/include/linux/cpufreq.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/cpufreq.h	2006-04-01 05:35:30.770543000 -0500
@@ -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/dlm.h newtree/include/linux/dlm.h
--- oldtree/include/linux/dlm.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/linux/dlm.h	2006-04-01 05:36:00.952429250 -0500
@@ -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	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/linux/dlm_device.h	2006-04-01 05:36:00.712414250 -0500
@@ -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/fs.h newtree/include/linux/fs.h
--- oldtree/include/linux/fs.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/fs.h	2006-04-01 05:36:06.740791000 -0500
@@ -1085,6 +1085,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);
@@ -1449,6 +1451,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 *);
diff -urN oldtree/include/linux/gameport.h newtree/include/linux/gameport.h
--- oldtree/include/linux/gameport.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/gameport.h	2006-04-01 05:35:38.139003500 -0500
@@ -11,6 +11,7 @@
 
 #include <asm/io.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/timer.h>
 
@@ -40,7 +41,7 @@
 	struct gameport *parent, *child;
 
 	struct gameport_driver *drv;
-	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
+	struct mutex drv_mutex;		/* protects serio->drv so attributes can pin driver */
 
 	struct device dev;
 	unsigned int registered;	/* port has been fully registered with driver core */
@@ -137,12 +138,12 @@
  */
 static inline int gameport_pin_driver(struct gameport *gameport)
 {
-	return down_interruptible(&gameport->drv_sem);
+	return mutex_lock_interruptible(&gameport->drv_mutex);
 }
 
 static inline void gameport_unpin_driver(struct gameport *gameport)
 {
-	up(&gameport->drv_sem);
+	mutex_unlock(&gameport->drv_mutex);
 }
 
 void __gameport_register_driver(struct gameport_driver *drv, struct module *owner);
diff -urN oldtree/include/linux/input.h newtree/include/linux/input.h
--- oldtree/include/linux/input.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/input.h	2006-04-01 05:35:38.139003500 -0500
@@ -421,7 +421,7 @@
 #define BTN_GEAR_UP		0x151
 
 #define KEY_OK			0x160
-#define KEY_SELECT 		0x161
+#define KEY_SELECT		0x161
 #define KEY_GOTO		0x162
 #define KEY_CLEAR		0x163
 #define KEY_POWER2		0x164
@@ -929,7 +929,7 @@
 
 	struct input_handle *grab;
 
-	struct semaphore sem;	/* serializes open and close operations */
+	struct mutex mutex;	/* serializes open and close operations */
 	unsigned int users;
 
 	struct class_device cdev;
@@ -995,11 +995,6 @@
 
 struct input_dev *input_allocate_device(void);
 
-static inline void input_free_device(struct input_dev *dev)
-{
-	kfree(dev);
-}
-
 static inline struct input_dev *input_get_device(struct input_dev *dev)
 {
 	return to_input_dev(class_device_get(&dev->cdev));
@@ -1010,6 +1005,11 @@
 	class_device_put(&dev->cdev);
 }
 
+static inline void input_free_device(struct input_dev *dev)
+{
+	input_put_device(dev);
+}
+
 int input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
diff -urN oldtree/include/linux/leds.h newtree/include/linux/leds.h
--- oldtree/include/linux/leds.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/linux/leds.h	2006-04-01 05:35:57.320202250 -0500
@@ -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/libps2.h newtree/include/linux/libps2.h
--- oldtree/include/linux/libps2.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/libps2.h	2006-04-01 05:35:38.139003500 -0500
@@ -28,7 +28,7 @@
 	struct serio *serio;
 
 	/* Ensures that only one command is executing at a time */
-	struct semaphore cmd_sem;
+	struct mutex cmd_mutex;
 
 	/* Used to signal completion from interrupt handler */
 	wait_queue_head_t wait;
diff -urN oldtree/include/linux/mtd/blktrans.h newtree/include/linux/mtd/blktrans.h
--- oldtree/include/linux/mtd/blktrans.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/mtd/blktrans.h	2006-04-01 05:35:39.575093250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/mtd/doc2000.h	2006-04-01 05:35:39.575093250 -0500
@@ -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/netlink.h newtree/include/linux/netlink.h
--- oldtree/include/linux/netlink.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/netlink.h	2006-04-01 05:35:45.879487250 -0500
@@ -21,6 +21,7 @@
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
 #define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */
 #define NETLINK_GENERIC		16
+#define NETLINK_TGT		17	/* SCSI target */
 
 #define MAX_LINKS 32		
 
diff -urN oldtree/include/linux/pci_ids.h newtree/include/linux/pci_ids.h
--- oldtree/include/linux/pci_ids.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/pci_ids.h	2006-04-01 05:35:45.851485500 -0500
@@ -1946,6 +1946,19 @@
 #define PCI_DEVICE_ID_ALTIMA_AC9100	0x03ea
 #define PCI_DEVICE_ID_ALTIMA_AC1003	0x03eb
 
+#define PCI_VENDOR_ID_ARECA		0x17d3
+#define PCI_DEVICE_ID_ARECA_1110	0x1110
+#define PCI_DEVICE_ID_ARECA_1120	0x1120
+#define PCI_DEVICE_ID_ARECA_1130	0x1130
+#define PCI_DEVICE_ID_ARECA_1160	0x1160
+#define PCI_DEVICE_ID_ARECA_1170	0x1170
+#define PCI_DEVICE_ID_ARECA_1210	0x1210
+#define PCI_DEVICE_ID_ARECA_1220	0x1220
+#define PCI_DEVICE_ID_ARECA_1230	0x1230
+#define PCI_DEVICE_ID_ARECA_1260	0x1260
+#define PCI_DEVICE_ID_ARECA_1270	0x1270
+#define PCI_DEVICE_ID_ARECA_1280	0x1280
+
 #define PCI_VENDOR_ID_S2IO		0x17d5
 #define	PCI_DEVICE_ID_S2IO_WIN		0x5731
 #define	PCI_DEVICE_ID_S2IO_UNI		0x5831
diff -urN oldtree/include/linux/serio.h newtree/include/linux/serio.h
--- oldtree/include/linux/serio.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/serio.h	2006-04-01 05:35:38.139003500 -0500
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 
@@ -42,7 +43,7 @@
 	struct serio *parent, *child;
 
 	struct serio_driver *drv;	/* accessed from interrupt, must be protected by serio->lock and serio->sem */
-	struct semaphore drv_sem;	/* protects serio->drv so attributes can pin driver */
+	struct mutex drv_mutex;		/* protects serio->drv so attributes can pin driver */
 
 	struct device dev;
 	unsigned int registered;	/* port has been fully registered with driver core */
@@ -151,17 +152,17 @@
  */
 static inline int serio_pin_driver(struct serio *serio)
 {
-	return down_interruptible(&serio->drv_sem);
+	return mutex_lock_interruptible(&serio->drv_mutex);
 }
 
 static inline void serio_pin_driver_uninterruptible(struct serio *serio)
 {
-	down(&serio->drv_sem);
+	mutex_lock(&serio->drv_mutex);
 }
 
 static inline void serio_unpin_driver(struct serio *serio)
 {
-	up(&serio->drv_sem);
+	mutex_unlock(&serio->drv_mutex);
 }
 
 
diff -urN oldtree/include/linux/uinput.h newtree/include/linux/uinput.h
--- oldtree/include/linux/uinput.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/linux/uinput.h	2006-04-01 05:35:38.143003750 -0500
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
- * 
+ *
  * Changes/Revisions:
  *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
  *		- added force feedback support
@@ -51,7 +51,7 @@
 
 struct uinput_device {
 	struct input_dev	*dev;
-	struct semaphore	sem;
+	struct mutex		mutex;
 	enum uinput_state	state;
 	wait_queue_head_t	waitq;
 	unsigned char		ready;
diff -urN oldtree/include/pcmcia/bulkmem.h newtree/include/pcmcia/bulkmem.h
--- oldtree/include/pcmcia/bulkmem.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/bulkmem.h	2006-04-01 05:35:44.311389250 -0500
@@ -35,7 +35,7 @@
 #define REGION_BAR_MASK		0xe000
 #define REGION_BAR_SHIFT	13
 
-int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn);
-int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn);
+int pcmcia_get_first_region(struct pcmcia_device *handle, region_info_t *rgn);
+int pcmcia_get_next_region(struct pcmcia_device *handle, region_info_t *rgn);
 
 #endif /* _LINUX_BULKMEM_H */
diff -urN oldtree/include/pcmcia/ciscode.h newtree/include/pcmcia/ciscode.h
--- oldtree/include/pcmcia/ciscode.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/ciscode.h	2006-04-01 05:35:44.311389250 -0500
@@ -1,5 +1,5 @@
 /*
- * ciscode.h -- Definitions for bulk memory services
+ * ciscode.h
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -122,4 +122,7 @@
 
 #define MANFID_XIRCOM			0x0105
 
+#define MANFID_POSSIO			0x030c
+#define PRODID_POSSIO_GCC		0x0003
+
 #endif /* _LINUX_CISCODE_H */
diff -urN oldtree/include/pcmcia/cistpl.h newtree/include/pcmcia/cistpl.h
--- oldtree/include/pcmcia/cistpl.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/cistpl.h	2006-04-01 05:35:44.311389250 -0500
@@ -586,12 +586,7 @@
     cisdata_t	Data[CISTPL_MAX_CIS_SIZE];
 } cisdump_t;
 
-int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple);
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple);
-int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple);
-int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse);
 
-int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info);
 int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis);
 
 /* don't use outside of PCMCIA core yet */
@@ -602,4 +597,20 @@
 
 int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info);
 
+/* ... but use these wrappers instead */
+#define pcmcia_get_first_tuple(p_dev, tuple) \
+		pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
+
+#define pcmcia_get_next_tuple(p_dev, tuple) \
+		pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
+
+#define pcmcia_get_tuple_data(p_dev, tuple) \
+		pccard_get_tuple_data(p_dev->socket, tuple)
+
+#define pcmcia_parse_tuple(p_dev, tuple, parse) \
+		pccard_parse_tuple(tuple, parse)
+
+#define pcmcia_validate_cis(p_dev, info) \
+		pccard_validate_cis(p_dev->socket, p_dev->func, info)
+
 #endif /* LINUX_CISTPL_H */
diff -urN oldtree/include/pcmcia/cs.h newtree/include/pcmcia/cs.h
--- oldtree/include/pcmcia/cs.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/cs.h	2006-04-01 05:35:44.311389250 -0500
@@ -109,17 +109,6 @@
 
 #define CLIENT_THIS_SOCKET	0x01
 
-/* For RegisterClient */
-typedef struct client_reg_t {
-    dev_info_t	*dev_info;
-    u_int	Attributes;  /* UNUSED */
-    u_int	EventMask;
-    int		(*event_handler)(event_t event, int priority,
-				 event_callback_args_t *);
-    event_callback_args_t event_callback_args;
-    u_int	Version;
-} client_reg_t;
-
 /* ModifyConfiguration */
 typedef struct modconf_t {
     u_int	Attributes;
@@ -127,15 +116,16 @@
 } modconf_t;
 
 /* Attributes for ModifyConfiguration */
-#define CONF_IRQ_CHANGE_VALID	0x100
-#define CONF_VCC_CHANGE_VALID	0x200
-#define CONF_VPP1_CHANGE_VALID	0x400
-#define CONF_VPP2_CHANGE_VALID	0x800
+#define CONF_IRQ_CHANGE_VALID	0x0100
+#define CONF_VCC_CHANGE_VALID	0x0200
+#define CONF_VPP1_CHANGE_VALID	0x0400
+#define CONF_VPP2_CHANGE_VALID	0x0800
+#define CONF_IO_CHANGE_WIDTH	0x1000
 
 /* For RequestConfiguration */
 typedef struct config_req_t {
     u_int	Attributes;
-    u_int	Vcc, Vpp1, Vpp2;
+    u_int	Vpp; /* both Vpp1 and Vpp2 */
     u_int	IntType;
     u_int	ConfigBase;
     u_char	Status, Pin, Copy, ExtStatus;
@@ -389,23 +379,27 @@
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
-int pcmcia_release_configuration(struct pcmcia_device *p_dev);
-int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req);
-int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req);
 int pcmcia_release_window(window_handle_t win);
 int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
 int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
 int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
 int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
-int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req);
 int pcmcia_suspend_card(struct pcmcia_socket *skt);
 int pcmcia_resume_card(struct pcmcia_socket *skt);
 int pcmcia_eject_card(struct pcmcia_socket *skt);
 int pcmcia_insert_card(struct pcmcia_socket *skt);
+int pccard_reset_card(struct pcmcia_socket *skt);
+
+struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *p_dev);
+void pcmcia_disable_device(struct pcmcia_device *p_dev);
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
 void pcmcia_put_socket(struct pcmcia_socket *skt);
 
+/* compatibility functions */
+#define pcmcia_reset_card(p_dev, req) \
+		pccard_reset_card(p_dev->socket)
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_CS_H */
diff -urN oldtree/include/pcmcia/ds.h newtree/include/pcmcia/ds.h
--- oldtree/include/pcmcia/ds.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/ds.h	2006-04-01 05:35:44.311389250 -0500
@@ -39,7 +39,7 @@
 typedef struct bind_info_t {
     dev_info_t		dev_info;
     u_char		function;
-    struct dev_link_t	*instance;
+    struct pcmcia_device *instance;
     char		name[DEV_NAME_LEN];
     u_short		major, minor;
     void		*next;
@@ -96,6 +96,7 @@
 
 #ifdef __KERNEL__
 #include <linux/device.h>
+#include <pcmcia/ss.h>
 
 typedef struct dev_node_t {
     char		dev_name[DEV_NAME_LEN];
@@ -103,34 +104,9 @@
     struct dev_node_t	*next;
 } dev_node_t;
 
-typedef struct dev_link_t {
-    dev_node_t		*dev;
-    u_int		state, open;
-    wait_queue_head_t	pending;
-    client_handle_t	handle;
-    io_req_t		io;
-    irq_req_t		irq;
-    config_req_t	conf;
-    window_handle_t	win;
-    void		*priv;
-    struct dev_link_t	*next;
-} dev_link_t;
-
-/* Flags for device state */
-#define DEV_PRESENT		0x01
-#define DEV_CONFIG		0x02
-#define DEV_STALE_CONFIG	0x04	/* release on close */
-#define DEV_STALE_LINK		0x08	/* detach on release */
-#define DEV_CONFIG_PENDING	0x10
-#define DEV_RELEASE_PENDING	0x20
-#define DEV_SUSPEND		0x40
-#define DEV_BUSY		0x80
-
-#define DEV_OK(l) \
-    ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
-
 
 struct pcmcia_socket;
+struct config_t;
 
 struct pcmcia_driver {
 	int (*probe)		(struct pcmcia_device *dev);
@@ -148,6 +124,7 @@
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+
 struct pcmcia_device {
 	/* the socket and the device_no [for multifunction devices]
 	   uniquely define a pcmcia_device */
@@ -160,21 +137,40 @@
 	/* the hardware "function" device; certain subdevices can
 	 * share one hardware "function" device. */
 	u8			func;
+	struct config_t*	function_config;
 
 	struct list_head	socket_device_list;
 
-	/* deprecated, a cleaned up version will be moved into this
-	   struct soon */
-	dev_link_t		*instance;
-	u_int			state;
+	/* deprecated, will be cleaned up soon */
+	dev_node_t		*dev_node;
+	u_int			open;
+	io_req_t		io;
+	irq_req_t		irq;
+	config_req_t		conf;
+	window_handle_t		win;
+
+	/* Is the device suspended, or in the process of
+	 * being removed? */
+	u16			suspended:1;
+	u16			_removed:1;
+
+	/* Flags whether io, irq, win configurations were
+	 * requested, and whether the configuration is "locked" */
+	u16			_irq:1;
+	u16			_io:1;
+	u16			_win:4;
+	u16			_locked:1;
+
+	/* Flag whether a "fuzzy" func_id based match is
+	 * allowed. */
+	u16			allow_func_id_match:1;
 
 	/* information about this device */
-	u8			has_manf_id:1;
-	u8			has_card_id:1;
-	u8			has_func_id:1;
+	u16			has_manf_id:1;
+	u16			has_card_id:1;
+	u16			has_func_id:1;
 
-	u8			allow_func_id_match:1;
-	u8			reserved:4;
+	u16			reserved:3;
 
 	u8			func_id;
 	u16			manf_id;
@@ -182,22 +178,24 @@
 
 	char *			prod_id[4];
 
+	struct device		dev;
+
+#ifdef CONFIG_PCMCIA_IOCTL
 	/* device driver wanted by cardmgr */
 	struct pcmcia_driver *	cardmgr;
+#endif
 
-	struct device		dev;
+	/* data private to drivers */
+	void			*priv;
 };
 
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
 #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
 
-#define handle_to_pdev(handle) (handle)
 #define handle_to_dev(handle) (handle->dev)
 
-#define dev_to_instance(dev) (dev->instance)
-
 /* error reporting */
-void cs_error(client_handle_t handle, int func, int ret);
+void cs_error(struct pcmcia_device *handle, int func, int ret);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_DS_H */
diff -urN oldtree/include/pcmcia/ss.h newtree/include/pcmcia/ss.h
--- oldtree/include/pcmcia/ss.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/pcmcia/ss.h	2006-04-01 05:35:44.311389250 -0500
@@ -18,6 +18,7 @@
 #include <linux/config.h>
 #include <linux/device.h>
 #include <linux/sched.h>	/* task_struct, completion */
+#include <linux/mutex.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -152,8 +153,6 @@
 struct pcmcia_socket;
 
 typedef struct io_window_t {
-	u_int			Attributes;
-	kio_addr_t		BasePort, NumPorts;
 	kio_addr_t		InUse, Config;
 	struct resource		*res;
 } io_window_t;
@@ -162,7 +161,7 @@
 typedef struct window_t {
 	u_short			magic;
 	u_short			index;
-	client_handle_t		handle;
+	struct pcmcia_device	*handle;
 	struct pcmcia_socket 	*sock;
 	pccard_mem_map		ctl;
 } window_t;
@@ -186,7 +185,6 @@
 	u_short				lock_count;
 	pccard_mem_map			cis_mem;
 	void __iomem 			*cis_virt;
-	struct config_t			*config;
 	struct {
 		u_int			AssignedIRQ;
 		u_int			Config;
@@ -241,7 +239,7 @@
 #endif
 
 	/* state thread */
-	struct semaphore		skt_sem;	/* protects socket h/w state */
+	struct mutex			skt_mutex;	/* protects socket h/w state */
 
 	struct task_struct		*thread;
 	struct completion		thread_done;
diff -urN oldtree/include/scsi/sas/sas.h newtree/include/scsi/sas/sas.h
--- oldtree/include/scsi/sas/sas.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,164 @@
+/*
+ * SAS structures and definitions header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas.h#25 $
+ */
+
+#ifndef _SAS_H_
+#define _SAS_H_
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define SAS_ADDR_SIZE        8
+#define HASHED_SAS_ADDR_SIZE 3
+#define SAS_ADDR(_sa)   (be64_to_cpu(*(__be64 *)(_sa)))
+
+enum sas_oob_mode {
+	OOB_NOT_CONNECTED,
+	SATA_OOB_MODE,
+	SAS_OOB_MODE
+};
+
+/* See sas_discover.c if you plan on changing these.
+ */
+enum sas_dev_type {
+	NO_DEVICE   = 0,	  /* protocol */
+	SAS_END_DEV = 1,	  /* protocol */
+	EDGE_DEV    = 2,	  /* protocol */
+	FANOUT_DEV  = 3,	  /* protocol */
+	SAS_HA      = 4,
+	SATA_DEV    = 5,
+	SATA_PM     = 7,
+	SATA_PM_PORT= 8,
+};
+
+enum sas_phy_linkrate {
+	PHY_LINKRATE_NONE = 0,
+	PHY_LINKRATE_UNKNOWN = 0,
+	PHY_DISABLED,
+	PHY_RESET_PROBLEM,
+	PHY_SPINUP_HOLD,
+	PHY_PORT_SELECTOR,
+	PHY_LINKRATE_1_5 = 0x08,
+	PHY_LINKRATE_G1  = PHY_LINKRATE_1_5,
+	PHY_LINKRATE_3   = 0x09,
+	PHY_LINKRATE_G2  = PHY_LINKRATE_3,
+	PHY_LINKRATE_6   = 0x0A,
+};
+
+/* Partly from IDENTIFY address frame. */
+enum sas_proto {
+	SATA_PROTO    = 1,
+	SAS_PROTO_SMP = 2,	  /* protocol */
+	SAS_PROTO_STP = 4,	  /* protocol */
+	SAS_PROTO_SSP = 8,	  /* protocol */
+	SAS_PROTO_ALL = 0xE,
+};
+
+/* From the spec; local phys only */
+enum phy_func {
+	PHY_FUNC_NOP,
+	PHY_FUNC_LINK_RESET,		  /* Enables the phy */
+	PHY_FUNC_HARD_RESET,
+	PHY_FUNC_DISABLE,
+	PHY_FUNC_CLEAR_ERROR_LOG = 5,
+	PHY_FUNC_CLEAR_AFFIL,
+	PHY_FUNC_TX_SATA_PS_SIGNAL,
+	PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */
+};
+
+#include <scsi/sas/sas_frames.h>
+
+/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST.
+ * Most of those are here for completeness.
+ */
+enum sas_prim {
+	SAS_PRIM_AIP_NORMAL = 1,
+	SAS_PRIM_AIP_R0     = 2,
+	SAS_PRIM_AIP_R1     = 3,
+	SAS_PRIM_AIP_R2     = 4,
+	SAS_PRIM_AIP_WC     = 5,
+	SAS_PRIM_AIP_WD     = 6,
+	SAS_PRIM_AIP_WP     = 7,
+	SAS_PRIM_AIP_RWP    = 8,
+
+	SAS_PRIM_BC_CH      = 9,
+	SAS_PRIM_BC_RCH0    = 10,
+	SAS_PRIM_BC_RCH1    = 11,
+	SAS_PRIM_BC_R0      = 12,
+	SAS_PRIM_BC_R1      = 13,
+	SAS_PRIM_BC_R2      = 14,
+	SAS_PRIM_BC_R3      = 15,
+	SAS_PRIM_BC_R4      = 16,
+
+	SAS_PRIM_NOTIFY_ENSP= 17,
+	SAS_PRIM_NOTIFY_R0  = 18,
+	SAS_PRIM_NOTIFY_R1  = 19,
+	SAS_PRIM_NOTIFY_R2  = 20,
+
+	SAS_PRIM_CLOSE_CLAF = 21,
+	SAS_PRIM_CLOSE_NORM = 22,
+	SAS_PRIM_CLOSE_R0   = 23,
+	SAS_PRIM_CLOSE_R1   = 24,
+
+	SAS_PRIM_OPEN_RTRY  = 25,
+	SAS_PRIM_OPEN_RJCT  = 26,
+	SAS_PRIM_OPEN_ACPT  = 27,
+
+	SAS_PRIM_DONE       = 28,
+	SAS_PRIM_BREAK      = 29,
+
+	SATA_PRIM_DMAT      = 33,
+	SATA_PRIM_PMNAK     = 34,
+	SATA_PRIM_PMACK     = 35,
+	SATA_PRIM_PMREQ_S   = 36,
+	SATA_PRIM_PMREQ_P   = 37,
+	SATA_SATA_R_ERR     = 38,
+};
+
+enum sas_open_rej_reason {
+	/* Abandon open */
+	SAS_OREJ_UNKNOWN   = 0,
+	SAS_OREJ_BAD_DEST  = 1,
+	SAS_OREJ_CONN_RATE = 2,
+	SAS_OREJ_EPROTO    = 3,
+	SAS_OREJ_RESV_AB0  = 4,
+	SAS_OREJ_RESV_AB1  = 5,
+	SAS_OREJ_RESV_AB2  = 6,
+	SAS_OREJ_RESV_AB3  = 7,
+	SAS_OREJ_WRONG_DEST= 8,
+	SAS_OREJ_STP_NORES = 9,
+
+	/* Retry open */
+	SAS_OREJ_NO_DEST   = 10,
+	SAS_OREJ_PATH_BLOCKED = 11,
+	SAS_OREJ_RSVD_CONT0 = 12,
+	SAS_OREJ_RSVD_CONT1 = 13,
+	SAS_OREJ_RSVD_INIT0 = 14,
+	SAS_OREJ_RSVD_INIT1 = 15,
+	SAS_OREJ_RSVD_STOP0 = 16,
+	SAS_OREJ_RSVD_STOP1 = 17,
+	SAS_OREJ_RSVD_RETRY = 18,
+};
+#endif /* _SAS_H_ */
diff -urN oldtree/include/scsi/sas/sas_class.h newtree/include/scsi/sas/sas_class.h
--- oldtree/include/scsi/sas/sas_class.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_class.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,316 @@
+/*
+ * Serial Attached SCSI (SAS) class header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_class.h#66 $
+ */
+
+#ifndef _SAS_CLASS_H_
+#define _SAS_CLASS_H_
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <asm/semaphore.h>
+#include <scsi/scsi_device.h>
+#include <scsi/sas/sas.h>
+
+struct block_device;
+
+enum sas_class {
+	SAS,
+	EXPANDER
+};
+
+enum sas_phy_role {
+	PHY_ROLE_NONE = 0,
+	PHY_ROLE_TARGET = 0x40,
+	PHY_ROLE_INITIATOR = 0x80,
+};
+
+enum sas_phy_type {
+        PHY_TYPE_PHYSICAL,
+        PHY_TYPE_VIRTUAL
+};
+
+/* The events are mnemonically described in sas_dump.c
+ * so when updating/adding events here, please also
+ * update the other file too.
+ */
+enum ha_event {
+	HAE_RESET = 0U,
+};
+#define HA_NUM_EVENTS 1
+
+enum port_event {
+	PORTE_BYTES_DMAED     = 0U,
+	PORTE_BROADCAST_RCVD  = 1,
+	PORTE_LINK_RESET_ERR  = 2,
+	PORTE_TIMER_EVENT     = 3,
+	PORTE_HARD_RESET      = 4,
+};
+#define PORT_NUM_EVENTS 5
+
+enum phy_event {
+	PHYE_LOSS_OF_SIGNAL   = 0U,
+	PHYE_OOB_DONE         = 1,
+	PHYE_OOB_ERROR        = 2,
+	PHYE_SPINUP_HOLD      = 3, /* hot plug SATA, no COMWAKE sent */
+};
+#define PHY_NUM_EVENTS 4
+
+enum discover_event {
+	DISCE_DISCOVER_DOMAIN   = 0U,
+	DISCE_REVALIDATE_DOMAIN = 1,
+	DISCE_PORT_GONE         = 2,
+};
+#define DISC_NUM_EVENTS 3
+
+struct sas_event {
+	int    event;
+	struct list_head el;
+};
+
+/* The phy pretty much is controlled by the LLDD.
+ * The class only reads those fields.
+ */
+struct sas_phy {
+/* private: */
+	struct kobject phy_kobj;
+
+	/* protected by ha->event_lock */
+	struct list_head   port_event_list;
+	struct list_head   phy_event_list;
+	struct sas_event   port_events[PORT_NUM_EVENTS];
+	struct sas_event   phy_events[PHY_NUM_EVENTS];
+
+	int error;
+
+/* public: */
+	/* The following are class:RO, driver:R/W */
+	int            enabled;	  /* must be set */
+
+	int            id;	  /* must be set */
+	enum sas_class class;
+	enum sas_proto iproto;
+	enum sas_proto tproto;
+
+	enum sas_phy_type  type;
+	enum sas_phy_role  role;
+	enum sas_oob_mode  oob_mode;
+	enum sas_phy_linkrate linkrate;
+
+	u8   *sas_addr;		  /* must be set */
+	u8   attached_sas_addr[SAS_ADDR_SIZE]; /* class:RO, driver: R/W */
+
+	spinlock_t     frame_rcvd_lock;
+	u8             *frame_rcvd; /* must be set */
+	int            frame_rcvd_size;
+
+	spinlock_t     sas_prim_lock;
+	u32            sas_prim;
+
+	struct list_head port_phy_el; /* driver:RO */
+	struct sas_port      *port; /* Class:RW, driver: RO */
+
+	struct sas_ha_struct *ha; /* may be set; the class sets it anyway */
+
+	void *lldd_phy;		  /* not touched by the sas_class_code */
+};
+
+struct sas_port;
+
+struct sas_discovery {
+	spinlock_t disc_event_lock;
+	int        disc_thread_quit;
+	struct list_head disc_event_list;
+	struct sas_event disc_events[DISC_NUM_EVENTS];
+	struct task_struct *disc_thread;
+	struct semaphore  disc_sema;
+
+	u8     fanout_sas_addr[8];
+	u8     eeds_a[8];
+	u8     eeds_b[8];
+	int    max_level;
+};
+
+struct scsi_id_map {
+	int         max_ids;
+	spinlock_t  id_bitmap_lock;
+	int         id_bitmap_size;
+	void       *id_bitmap;
+};
+
+struct domain_device;
+
+/* The port struct is Class:RW, driver:RO */
+struct sas_port {
+/* private: */
+	struct kobject port_kobj;
+	struct kset    phy_kset;
+	struct kset    dev_kset;
+
+	struct completion port_gone_completion;
+
+	struct sas_discovery disc;
+	struct domain_device *port_dev;
+	struct list_head dev_list;
+	enum   sas_phy_linkrate linkrate;
+
+	struct scsi_id_map id_map;
+
+/* public: */
+	int id;
+
+	enum sas_class   class;
+	u8               sas_addr[SAS_ADDR_SIZE];
+	u8               attached_sas_addr[SAS_ADDR_SIZE];
+	enum sas_proto   iproto;
+	enum sas_proto   tproto;
+
+	enum sas_oob_mode oob_mode;
+
+	spinlock_t       phy_list_lock;
+	struct list_head phy_list;
+	int              num_phys;
+	u32              phy_mask;
+
+	struct sas_ha_struct *ha;
+
+	void *lldd_port;	  /* not touched by the sas class code */
+};
+
+struct sas_task;
+
+struct scsi_core {
+	struct kobject scsi_core_obj;
+
+	struct scsi_host_template *sht;
+	struct Scsi_Host *shost;
+
+	spinlock_t        task_queue_lock;
+	struct list_head  task_queue;
+	int               task_queue_size;
+
+	struct semaphore  queue_thread_sema;
+	int               queue_thread_kill;
+};
+
+struct sas_ha_struct {
+/* private: */
+	struct kset      ha_kset; /* "this" */
+	struct kset      phy_kset;
+	struct kset      port_kset;
+
+	struct semaphore event_sema;
+	int              event_thread_kill;
+
+	spinlock_t       event_lock;
+	struct list_head ha_event_list;
+	struct sas_event ha_events[HA_NUM_EVENTS];
+	u32              porte_mask; /* mask of phys for port events */
+	u32              phye_mask; /* mask of phys for phy events */
+
+	struct scsi_core core;
+
+/* public: */
+	char *sas_ha_name;
+	struct pci_dev *pcidev;	  /* should be set */
+	struct module *lldd_module; /* should be set */
+
+	u8 *sas_addr;		  /* must be set */
+	u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
+
+	spinlock_t      phy_port_lock;
+	struct sas_phy  **sas_phy; /* array of valid pointers, must be set */
+	struct sas_port **sas_port; /* array of valid pointers, must be set */
+	int             num_phys; /* must be set, gt 0, static */
+
+	/* LLDD calls these to notify the class of an event. */
+	void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
+	void (*notify_port_event)(struct sas_phy *, enum port_event);
+	void (*notify_phy_event)(struct sas_phy *, enum phy_event);
+
+	/* The class calls these to notify the LLDD of an event. */
+	void (*lldd_port_formed)(struct sas_phy *);
+	void (*lldd_port_deformed)(struct sas_phy *);
+
+	/* The class calls these when a device is found or gone. */
+	int  (*lldd_dev_found)(struct domain_device *);
+	void (*lldd_dev_gone)(struct domain_device *);
+
+	/* The class calls this to send a task for execution. */
+	int lldd_max_execute_num;
+	int lldd_queue_size;
+	int (*lldd_execute_task)(struct sas_task *, int num,
+				 unsigned long gfp_flags);
+
+	/* Task Management Functions. Must be called from process context. */
+	int (*lldd_abort_task)(struct sas_task *);
+	int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
+	int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
+	int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
+	int (*lldd_I_T_nexus_reset)(struct domain_device *);
+	int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
+	int (*lldd_query_task)(struct sas_task *);
+
+	/* Port and Adapter management */
+	int (*lldd_clear_nexus_port)(struct sas_port *);
+	int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
+
+	/* Phy management */
+	int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
+
+	void *lldd_ha;		  /* not touched by sas class code */
+};
+
+#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
+
+void sas_hash_addr(u8 *hashed, const u8 *sas_addr);
+
+/* Before calling a notify event, LLDD should use this function
+ * when the link is severed (possibly from its tasklet).
+ * The idea is that the Class only reads those, while the LLDD,
+ * can R/W these (thus avoiding a race).
+ */
+static inline void sas_phy_disconnected(struct sas_phy *phy)
+{
+	phy->oob_mode = OOB_NOT_CONNECTED;
+	phy->linkrate = PHY_LINKRATE_NONE;
+}
+
+extern int sas_register_ha(struct sas_ha_struct *, const struct scsi_host_template *);
+extern int sas_unregister_ha(struct sas_ha_struct *);
+
+extern int sas_queuecommand(struct scsi_cmnd *cmd,
+		     void (*scsi_done)(struct scsi_cmnd *));
+extern int sas_scsi_recover_host(struct Scsi_Host *shost);
+extern enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd);
+extern int sas_slave_alloc(struct scsi_device *scsi_dev);
+extern int sas_slave_configure(struct scsi_device *scsi_dev);
+extern void sas_slave_destroy(struct scsi_device *scsi_dev);
+extern int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth);
+extern int sas_change_queue_type(struct scsi_device *scsi_dev, int qt);
+extern int sas_bios_param(struct scsi_device *scsi_dev,
+			  struct block_device *bdev,
+			  sector_t capacity, int *hsc);
+
+#endif /* _SAS_CLASS_H_ */
diff -urN oldtree/include/scsi/sas/sas_discover.h newtree/include/scsi/sas/sas_discover.h
--- oldtree/include/scsi/sas/sas_discover.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_discover.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,231 @@
+/*
+ * Serial Attached SCSI (SAS) Discover process header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_discover.h#41 $
+ */
+
+#ifndef _SAS_DISCOVER_H_
+#define _SAS_DISCOVER_H_
+
+#include <scsi/sas/sas_class.h>
+#include <scsi/sas/sas_frames.h>
+
+/* ---------- SMP ---------- */
+
+#define SMP_REPORT_GENERAL       0x00
+#define SMP_REPORT_MANUF_INFO    0x01
+#define SMP_READ_GPIO_REG        0x02
+#define SMP_DISCOVER             0x10
+#define SMP_REPORT_PHY_ERR_LOG   0x11
+#define SMP_REPORT_PHY_SATA      0x12
+#define SMP_REPORT_ROUTE_INFO    0x13
+#define SMP_WRITE_GPIO_REG       0x82
+#define SMP_CONF_ROUTE_INFO      0x90
+#define SMP_PHY_CONTROL          0x91
+#define SMP_PHY_TEST_FUNCTION    0x92
+
+#define SMP_RESP_FUNC_ACC        0x00
+#define SMP_RESP_FUNC_UNK        0x01
+#define SMP_RESP_FUNC_FAILED     0x02
+#define SMP_RESP_INV_FRM_LEN     0x03
+#define SMP_RESP_NO_PHY          0x10
+#define SMP_RESP_NO_INDEX        0x11
+#define SMP_RESP_PHY_NO_SATA     0x12
+#define SMP_RESP_PHY_UNK_OP      0x13
+#define SMP_RESP_PHY_UNK_TESTF   0x14
+#define SMP_RESP_PHY_TEST_INPROG 0x15
+#define SMP_RESP_PHY_VACANT      0x16
+
+/* ---------- Domain Devices ---------- */
+
+/* See sas_discover.c before changing these.
+ */
+
+/* ---------- SATA device ---------- */
+
+enum ata_command_set {
+	ATA_COMMAND_SET   = 0,
+	ATAPI_COMMAND_SET = 1,
+};
+
+struct domain_device;
+
+struct sata_device {
+	struct kset  pm_port_kset;
+	enum   ata_command_set command_set;
+	struct smp_resp        rps_resp; /* report_phy_sata_resp */
+	__le16 *identify_device;
+	__le16 *identify_packet_device;
+
+	u8     port_no;	       /* port number, if this is a PM (Port) */
+	struct list_head children; /* PM Ports if this is a PM */
+};
+
+/* ---------- SAS end device ---------- */
+
+#define SAS_INQUIRY_DATA_LEN 36
+
+struct scsi_core_mapping {
+	int  channel;
+	int  id;
+};
+
+enum task_management_type {
+	TASK_MANAGEMENT_NONE  = 0,
+	TASK_MANAGEMENT_FULL  = 1,
+	TASK_MANAGEMENT_BASIC = 2,
+};
+
+struct LU {
+	struct kobject   lu_obj;
+	struct list_head list;
+
+	struct domain_device *parent;
+
+	u8     LUN[8];
+	int    inquiry_valid_data_len;
+	u8     inquiry_data[SAS_INQUIRY_DATA_LEN];
+	struct scsi_core_mapping map;
+
+	enum task_management_type tm_type;
+
+	void  *uldd_dev;
+};
+
+struct end_device {
+	u8     ms_10:1;
+	u8     ready_led_meaning:1;
+	u8     rl_wlun:1;
+	u16    itnl_timeout; 	  /* 0 if you do not know it */
+	u16    iresp_timeout;
+
+	struct kset LU_kset;
+	struct list_head LU_list;
+};
+
+#include <scsi/sas/sas_expander.h>
+
+/* ---------- Domain device ---------- */
+
+struct domain_device {
+	struct kobject    dev_obj;
+	enum sas_dev_type dev_type;
+
+	enum sas_phy_linkrate linkrate;
+	enum sas_phy_linkrate min_linkrate;
+	enum sas_phy_linkrate max_linkrate;
+
+	int  pathways;
+
+	struct domain_device *parent;
+	struct list_head siblings; /* devices on the same level */
+	struct sas_port *port;	  /* shortcut to root of the tree */
+
+	struct list_head dev_list_node;
+
+	enum sas_proto    iproto;
+	enum sas_proto    tproto;
+
+	u8  sas_addr[SAS_ADDR_SIZE];
+	u8  hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
+
+	u8  frame_rcvd[32];
+
+	union {
+		struct expander_device ex_dev;
+		struct end_device      end_dev;
+		struct sata_device     sata_dev; /* STP & directly attached */
+	};
+
+	void *lldd_dev;
+};
+
+#define list_for_each_entry_reverse_safe(pos, n, head, member)		\
+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
+		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+
+static inline int sas_notify_lldd_dev_found(struct domain_device *dev)
+{
+	int res = 0;
+	struct sas_ha_struct *sas_ha = dev->port->ha;
+
+	if (!try_module_get(sas_ha->lldd_module))
+		return -ENOMEM;
+	if (sas_ha->lldd_dev_found) {
+		res = sas_ha->lldd_dev_found(dev);
+		if (res) {
+			printk("sas: driver on pcidev %s cannot handle "
+			       "device %llx, error:%d\n",
+			       pci_name(sas_ha->pcidev),
+			       SAS_ADDR(dev->sas_addr), res);
+		}
+	}
+	return res;
+}
+
+static inline void sas_notify_lldd_dev_gone(struct domain_device *dev)
+{
+	if (dev->port->ha->lldd_dev_gone)
+		dev->port->ha->lldd_dev_gone(dev);
+	module_put(dev->port->ha->lldd_module);
+}
+
+static inline void sas_init_dev(struct domain_device *dev)
+{
+	INIT_LIST_HEAD(&dev->siblings);
+	INIT_LIST_HEAD(&dev->dev_list_node);
+	switch (dev->dev_type) {
+	case SAS_END_DEV:
+		INIT_LIST_HEAD(&dev->end_dev.LU_list);
+		break;
+	case EDGE_DEV:
+	case FANOUT_DEV:
+		INIT_LIST_HEAD(&dev->ex_dev.children);
+		break;
+	case SATA_DEV:
+	case SATA_PM:
+	case SATA_PM_PORT:
+		INIT_LIST_HEAD(&dev->sata_dev.children);
+		break;
+	default:
+		break;
+	}
+}
+
+void sas_init_disc(struct sas_discovery *disc, struct sas_port *port);
+void sas_kill_disc_thread(struct sas_port *port);
+int  sas_discover_event(struct sas_port *sas_port, enum discover_event ev);
+
+int  sas_discover_sata(struct domain_device *dev);
+int  sas_discover_end_dev(struct domain_device *dev);
+
+void sas_unregister_dev(struct domain_device *dev);
+
+int  sas_register_with_scsi(struct LU *lu);
+void sas_unregister_with_scsi(struct LU *lu);
+
+void sas_unregister_devices(struct sas_ha_struct *sas_ha);
+
+#endif /* _SAS_DISCOVER_H_ */
diff -urN oldtree/include/scsi/sas/sas_expander.h newtree/include/scsi/sas/sas_expander.h
--- oldtree/include/scsi/sas/sas_expander.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_expander.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,133 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_expander.h#19 $
+ */
+
+#ifndef _SAS_EXPANDER_H_
+#define _SAS_EXPANDER_H_
+
+#define ETASK 0xFA
+
+#define to_lu_device(_obj) container_of(_obj, struct LU, lu_obj)
+#define to_lu_attr(_attr) container_of(_attr, struct lu_dev_attribute, attr)
+#define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
+#define to_dev_attr(_attr)  container_of(_attr, struct domain_dev_attribute,\
+                                         attr)
+
+/* ---------- Expander device ---------- */
+
+enum routing_attribute {
+	DIRECT_ROUTING,
+	SUBTRACTIVE_ROUTING,
+	TABLE_ROUTING,
+};
+
+enum ex_phy_state {
+	PHY_EMPTY,
+	PHY_VACANT,
+	PHY_NOT_PRESENT,
+	PHY_DEVICE_DISCOVERED
+};
+
+struct ex_phy {
+	int    phy_id;
+
+	enum ex_phy_state phy_state;
+
+	enum sas_dev_type attached_dev_type;
+	enum sas_phy_linkrate linkrate;
+
+	u8   attached_sata_host:1;
+	u8   attached_sata_dev:1;
+	u8   attached_sata_ps:1;
+
+	enum sas_proto attached_tproto;
+	enum sas_proto attached_iproto;
+
+	u8   attached_sas_addr[SAS_ADDR_SIZE];
+	u8   attached_phy_id;
+
+	u8   phy_change_count;
+	enum routing_attribute routing_attr;
+	u8   virtual:1;
+
+	int  last_da_index;
+};
+
+struct expander_device {
+	struct list_head children;
+
+	int    level;
+
+	u16    ex_change_count;
+	u16    max_route_indexes;
+	u8     num_phys;
+	u8     configuring:1;
+	u8     conf_route_table:1;
+	u8     enclosure_logical_id[8];
+
+	char   vendor_id[8+1];
+	char   product_id[16+1];
+	char   product_rev[4+1];
+	char   component_vendor_id[8+1];
+	u16    component_id;
+	u8     component_revision_id;
+
+	struct ex_phy *ex_phy;
+
+	struct bin_attribute smp_bin_attr;
+	void *smp_req;
+	int   smp_req_size;
+	int   smp_portal_pid;
+	struct semaphore smp_sema;
+};
+
+/* ---------- Attributes and inlined ---------- */
+
+struct domain_dev_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct domain_device *dev, char *);
+	ssize_t (*store)(struct domain_device *dev, const char *, size_t);
+};
+
+void sas_kobj_set(struct domain_device *dev);
+
+extern struct kobj_type ex_dev_ktype;
+extern struct sysfs_ops dev_sysfs_ops;
+
+ssize_t dev_show_type(struct domain_device *dev, char *page);
+ssize_t dev_show_iproto(struct domain_device *dev, char *page);
+ssize_t dev_show_tproto(struct domain_device *dev, char *page);
+ssize_t dev_show_sas_addr(struct domain_device *dev, char *page);
+ssize_t dev_show_linkrate(struct domain_device *dev, char *page);
+ssize_t dev_show_min_linkrate(struct domain_device *dev, char *page);
+ssize_t dev_show_max_linkrate(struct domain_device *dev, char *page);
+ssize_t dev_show_pathways(struct domain_device *dev, char *page);
+
+int  sas_discover_root_expander(struct domain_device *dev);
+
+void sas_init_ex_attr(void);
+
+int  sas_ex_revalidate_domain(struct domain_device *port_dev);
+
+#endif /* _SAS_EXPANDER_H_ */
diff -urN oldtree/include/scsi/sas/sas_frames.h newtree/include/scsi/sas/sas_frames.h
--- oldtree/include/scsi/sas/sas_frames.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_frames.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,97 @@
+/*
+ * SAS Frames
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_frames.h#5 $
+ */
+
+#ifndef _SAS_FRAMES_
+#define _SAS_FRAMES_
+
+#define SMP_REQUEST             0x40
+#define SMP_RESPONSE            0x41
+
+#define SSP_DATA                0x01
+#define SSP_XFER_RDY            0x05
+#define SSP_COMMAND             0x06
+#define SSP_RESPONSE            0x07
+#define SSP_TASK                0x16
+
+struct  dev_to_host_fis {
+	u8     fis_type;	  /* 0x34 */
+	u8     flags;
+	u8     status;
+	u8     error;
+
+	u8     lbal;
+	union { u8 lbam; u8 byte_count_low; };
+	union { u8 lbah; u8 byte_count_high; };
+	u8     device;
+
+	u8     lbal_exp;
+	u8     lbam_exp;
+	u8     lbah_exp;
+	u8     _r_a;
+
+	union { u8  sector_count; u8 interrupt_reason; };
+	u8     sector_count_exp;
+	u8     _r_b;
+	u8     _r_c;
+
+	u32    _r_d;
+} __attribute__ ((packed));
+
+struct host_to_dev_fis {
+	u8     fis_type;	  /* 0x27 */
+	u8     flags;
+	u8     command;
+	u8     features;
+
+	u8     lbal;
+	union { u8 lbam; u8 byte_count_low; };
+	union { u8 lbah; u8 byte_count_high; };
+	u8     device;
+
+	u8     lbal_exp;
+	u8     lbam_exp;
+	u8     lbah_exp;
+	u8     features_exp;
+
+	union { u8  sector_count; u8 interrupt_reason; };
+	u8     sector_count_exp;
+	u8     _r_a;
+	u8     control;
+
+	u32    _r_b;
+} __attribute__ ((packed));
+
+/* Prefer to have code clarity over header file clarity.
+ */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+#include <scsi/sas/sas_frames_le.h>
+#elif defined(__BIG_ENDIAN_BITFIELD)
+#include <scsi/sas/sas_frames_be.h>
+#else
+#error "Bitfield order not defined!"
+#endif
+
+#endif /* _SAS_FRAMES_ */
diff -urN oldtree/include/scsi/sas/sas_frames_be.h newtree/include/scsi/sas/sas_frames_be.h
--- oldtree/include/scsi/sas/sas_frames_be.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_frames_be.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,222 @@
+/*
+ * SAS Frames Big endian bitfield order
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_frames_be.h#11 $
+ */
+
+#ifndef _SAS_FRAMES_BE_H_
+#define _SAS_FRAMES_BE_H_
+
+#ifndef __BIG_ENDIAN_BITFIELD
+#error "Wrong header file included!"
+#endif
+
+struct sas_identify_frame {
+	/* Byte 0 */
+	u8  _un0:1;
+	u8  dev_type:3;
+	u8  frame_type:4;
+
+	/* Byte 1 */
+	u8  _un1;
+
+	/* Byte 2 */
+	union {
+		struct {
+			u8  _un247:4;
+			u8  ssp_iport:1;
+			u8  stp_iport:1;
+			u8  smp_iport:1;
+			u8  _un20:1;
+		};
+		u8 initiator_bits;
+	};
+
+	/* Byte 3 */
+	union {
+		struct {
+			u8 _un347:4;
+			u8 ssp_tport:1;
+			u8 stp_tport:1;
+			u8 smp_tport:1;
+			u8 _un30:1;
+		};
+		u8 target_bits;
+	};
+
+	/* Byte 4 - 11 */
+	u8 _un4_11[8];
+
+	/* Byte 12 - 19 */
+	u8 sas_addr[SAS_ADDR_SIZE];
+
+	/* Byte 20 */
+	u8 phy_id;
+
+	u8 _un21_27[7];
+
+	__be32 crc;
+} __attribute__ ((packed));
+
+struct ssp_frame_hdr {
+	u8     frame_type;
+	u8     hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
+	u8     _r_a;
+	u8     hashed_src_addr[HASHED_SAS_ADDR_SIZE];
+	__be16 _r_b;
+
+	u8     _r_c:5;
+	u8     retry_data_frames:1;
+	u8     retransmit:1;
+	u8     changing_data_ptr:1;
+
+	u8     _r_d:6;
+	u8     num_fill_bytes:2;
+
+	u32    _r_e;
+	__be16 tag;
+	__be16 tptt;
+	__be32 data_offs;
+} __attribute__ ((packed));
+
+struct ssp_response_iu {
+	u8     _r_a[10];
+
+	u8     _r_b:6;
+	u8     datapres:2;
+
+	u8     status;
+
+	u32    _r_c;
+
+	__be32 sense_data_len;
+	__be32 response_data_len;
+
+	u8     resp_data[0];
+	u8     sense_data[0];
+} __attribute__ ((packed));
+
+/* ---------- SMP ---------- */
+
+struct report_general_resp {
+	__be16  change_count;
+	__be16  route_indexes;
+	u8      _r_a;
+	u8      num_phys;
+
+	u8      _r_b:6;
+	u8      configuring:1;
+	u8      conf_route_table:1;
+
+	u8      _r_c;
+
+	u8      enclosure_logical_id[8];
+
+	u8      _r_d[12];
+} __attribute__ ((packed));
+
+struct discover_resp {
+	u8    _r_a[5];
+
+	u8    phy_id;
+	__be16 _r_b;
+
+	u8    _r_d:1;
+	u8    attached_dev_type:3;
+	u8    _r_c:4;
+
+	u8    _r_e:4;
+	u8    linkrate:4;
+
+	u8    _r_f:4;
+	u8    iproto:3;
+	u8    attached_sata_host:1;
+
+	u8    attached_sata_ps:1;
+	u8    _r_g:3;
+	u8    tproto:3;
+	u8    attached_sata_dev:1;
+
+	u8    sas_addr[8];
+	u8    attached_sas_addr[8];
+	u8    attached_phy_id;
+
+	u8    _r_h[7];
+
+	u8    pmin_linkrate:4;
+	u8    hmin_linkrate:4;
+	u8    pmax_linkrate:4;
+	u8    hmax_linkrate:4;
+
+	u8    change_count;
+
+	u8    virtual:1;
+	u8    _r_i:3;
+	u8    pptv:4;
+
+	u8    _r_j:4;
+	u8    routing_attr:4;
+
+	u8    conn_type;
+	u8    conn_el_index;
+	u8    conn_phy_link;
+
+	u8    _r_k[8];
+} __attribute__ ((packed));
+
+struct report_phy_sata_resp {
+	u8    _r_a[5];
+
+	u8    phy_id;
+	u8    _r_b;
+
+	u8    _r_c:6;
+	u8    affil_supp:1;
+	u8    affil_valid:1;
+
+	u32   _r_d;
+
+	u8    stp_sas_addr[8];
+
+	struct dev_to_host_fis fis;
+
+	u32   _r_e;
+
+	u8    affil_stp_ini_addr[8];
+
+	__be32 crc;
+} __attribute__ ((packed));
+
+struct smp_resp {
+	u8    frame_type;
+	u8    function;
+	u8    result;
+	u8    reserved;
+	union {
+		struct report_general_resp  rg;
+		struct discover_resp        disc;
+		struct report_phy_sata_resp rps;
+	};
+} __attribute__ ((packed));
+
+#endif /* _SAS_FRAMES_BE_H_ */
diff -urN oldtree/include/scsi/sas/sas_frames_le.h newtree/include/scsi/sas/sas_frames_le.h
--- oldtree/include/scsi/sas/sas_frames_le.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_frames_le.h	2006-04-01 05:35:45.931490500 -0500
@@ -0,0 +1,223 @@
+/*
+ * SAS Frames Little endian bitfield order
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * $Id: //depot/sas-class/sas_frames_le.h#10 $
+ */
+
+#ifndef _SAS_FRAMES_LE_H_
+#define _SAS_FRAMES_LE_H_
+
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#error "Wrong header file included!"
+#endif
+
+struct sas_identify_frame {
+	/* Byte 0 */
+	u8  frame_type:4;
+	u8  dev_type:3;
+	u8  _un0:1;
+
+	/* Byte 1 */
+	u8  _un1;
+
+	/* Byte 2 */
+	union {
+		struct {
+			u8  _un20:1;
+			u8  smp_iport:1;
+			u8  stp_iport:1;
+			u8  ssp_iport:1;
+			u8  _un247:4;
+		};
+		u8 initiator_bits;
+	};
+
+	/* Byte 3 */
+	union {
+		struct {
+			u8  _un30:1;
+			u8 smp_tport:1;
+			u8 stp_tport:1;
+			u8 ssp_tport:1;
+			u8 _un347:4;
+		};
+		u8 target_bits;
+	};
+
+	/* Byte 4 - 11 */
+	u8 _un4_11[8];
+
+	/* Byte 12 - 19 */
+	u8 sas_addr[SAS_ADDR_SIZE];
+
+	/* Byte 20 */
+	u8 phy_id;
+
+	u8 _un21_27[7];
+
+	__be32 crc;
+} __attribute__ ((packed));
+
+struct ssp_frame_hdr {
+	u8     frame_type;
+	u8     hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
+	u8     _r_a;
+	u8     hashed_src_addr[HASHED_SAS_ADDR_SIZE];
+	__be16 _r_b;
+
+	u8     changing_data_ptr:1;
+	u8     retransmit:1;
+	u8     retry_data_frames:1;
+	u8     _r_c:5;
+
+	u8     num_fill_bytes:2;
+	u8     _r_d:6;
+
+	u32    _r_e;
+	__be16 tag;
+	__be16 tptt;
+	__be32 data_offs;
+} __attribute__ ((packed));
+
+struct ssp_response_iu {
+	u8     _r_a[10];
+
+	u8     datapres:2;
+	u8     _r_b:6;
+
+	u8     status;
+
+	u32    _r_c;
+
+	__be32 sense_data_len;
+	__be32 response_data_len;
+
+	u8     resp_data[0];
+	u8     sense_data[0];
+} __attribute__ ((packed));
+
+/* ---------- SMP ---------- */
+
+struct report_general_resp {
+	__be16  change_count;
+	__be16  route_indexes;
+	u8      _r_a;
+	u8      num_phys;
+
+	u8      conf_route_table:1;
+	u8      configuring:1;
+	u8      _r_b:6;
+
+	u8      _r_c;
+
+	u8      enclosure_logical_id[8];
+
+	u8      _r_d[12];
+} __attribute__ ((packed));
+
+struct discover_resp {
+	u8    _r_a[5];
+
+	u8    phy_id;
+	__be16 _r_b;
+
+	u8    _r_c:4;
+	u8    attached_dev_type:3;
+	u8    _r_d:1;
+
+	u8    linkrate:4;
+	u8    _r_e:4;
+
+	u8    attached_sata_host:1;
+	u8    iproto:3;
+	u8    _r_f:4;
+
+	u8    attached_sata_dev:1;
+	u8    tproto:3;
+	u8    _r_g:3;
+	u8    attached_sata_ps:1;
+
+	u8    sas_addr[8];
+	u8    attached_sas_addr[8];
+	u8    attached_phy_id;
+
+	u8    _r_h[7];
+
+	u8    hmin_linkrate:4;
+	u8    pmin_linkrate:4;
+	u8    hmax_linkrate:4;
+	u8    pmax_linkrate:4;
+
+	u8    change_count;
+
+	u8    pptv:4;
+	u8    _r_i:3;
+	u8    virtual:1;
+
+	u8    routing_attr:4;
+	u8    _r_j:4;
+
+	u8    conn_type;
+	u8    conn_el_index;
+	u8    conn_phy_link;
+
+	u8    _r_k[8];
+} __attribute__ ((packed));
+
+struct report_phy_sata_resp {
+	u8    _r_a[5];
+
+	u8    phy_id;
+	u8    _r_b;
+
+	u8    affil_valid:1;
+	u8    affil_supp:1;
+	u8    _r_c:6;
+
+	u32    _r_d;
+
+	u8    stp_sas_addr[8];
+
+	struct dev_to_host_fis fis;
+
+	u32   _r_e;
+
+	u8    affil_stp_ini_addr[8];
+
+	__be32 crc;
+} __attribute__ ((packed));
+
+struct smp_resp {
+	u8    frame_type;
+	u8    function;
+	u8    result;
+	u8    reserved;
+	union {
+		struct report_general_resp  rg;
+		struct discover_resp        disc;
+		struct report_phy_sata_resp rps;
+	};
+} __attribute__ ((packed));
+
+#endif /* _SAS_FRAMES_LE_H_ */
+
diff -urN oldtree/include/scsi/sas/sas_task.h newtree/include/scsi/sas/sas_task.h
--- oldtree/include/scsi/sas/sas_task.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/sas/sas_task.h	2006-04-01 05:35:45.935490750 -0500
@@ -0,0 +1,234 @@
+/*
+ * Serial Attached SCSI (SAS) Task interface
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * $Id: //depot/sas-class/sas_task.h#27 $
+ */
+
+#ifndef _SAS_TASK_H_
+#define _SAS_TASK_H_
+
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <scsi/sas/sas_discover.h>
+
+/* SAM TMFs */
+#define TMF_ABORT_TASK      0x01
+#define TMF_ABORT_TASK_SET  0x02
+#define TMF_CLEAR_TASK_SET  0x04
+#define TMF_LU_RESET        0x08
+#define TMF_CLEAR_ACA       0x40
+#define TMF_QUERY_TASK      0x80
+
+/* SAS TMF responses */
+#define TMF_RESP_FUNC_COMPLETE   0x00
+#define TMF_RESP_INVALID_FRAME   0x02
+#define TMF_RESP_FUNC_ESUPP      0x04
+#define TMF_RESP_FUNC_FAILED     0x05
+#define TMF_RESP_FUNC_SUCC       0x08
+#define TMF_RESP_NO_LUN          0x09
+#define TMF_RESP_OVERLAPPED_TAG  0x0A
+
+/*
+      service_response |  SAS_TASK_COMPLETE  |  SAS_TASK_UNDELIVERED |
+  exec_status          |                     |                       |
+  ---------------------+---------------------+-----------------------+
+       SAM_...         |         X           |                       |
+       DEV_NO_RESPONSE |         X           |           X           |
+       INTERRUPTED     |         X           |                       |
+       QUEUE_FULL      |                     |           X           |
+       DEVICE_UNKNOWN  |                     |           X           |
+       SG_ERR          |                     |           X           |
+  ---------------------+---------------------+-----------------------+
+ */
+
+enum service_response {
+	SAS_TASK_COMPLETE,
+	SAS_TASK_UNDELIVERED = -1,
+};
+
+enum exec_status {
+	SAM_GOOD         = 0,
+	SAM_CHECK_COND   = 2,
+	SAM_COND_MET     = 4,
+	SAM_BUSY         = 8,
+	SAM_INTERMEDIATE = 0x10,
+	SAM_IM_COND_MET  = 0x12,
+	SAM_RESV_CONFLICT= 0x14,
+	SAM_TASK_SET_FULL= 0x28,
+	SAM_ACA_ACTIVE   = 0x30,
+	SAM_TASK_ABORTED = 0x40,
+
+	SAS_DEV_NO_RESPONSE = 0x80,
+	SAS_DATA_UNDERRUN,
+	SAS_DATA_OVERRUN,
+	SAS_INTERRUPTED,
+	SAS_QUEUE_FULL,
+	SAS_DEVICE_UNKNOWN,
+	SAS_SG_ERR,
+	SAS_OPEN_REJECT,
+	SAS_OPEN_TO,
+	SAS_PROTO_RESPONSE,
+	SAS_PHY_DOWN,
+	SAS_NAK_R_ERR,
+	SAS_PENDING,
+	SAS_ABORTED_TASK,
+};
+
+/* When a task finishes with a response, the LLDD examines the
+ * response:
+ * 	- For an ATA task task_status_struct::stat is set to
+ * SAS_PROTO_RESPONSE, and the task_status_struct::buf is set to the
+ * contents of struct ata_task_resp.
+ * 	- For SSP tasks, if no data is present or status/TMF response
+ * is valid, task_status_struct::stat is set.  If data is present
+ * (SENSE data), the LLDD copies up to SAS_STATUS_BUF_SIZE, sets
+ * task_status_struct::buf_valid_size, and task_status_struct::stat is
+ * set to SAM_CHECK_COND.
+ *
+ * "buf" has format SCSI Sense for SSP task, or struct ata_task_resp
+ * for ATA task.
+ *
+ * "frame_len" is the total frame length, which could be more or less
+ * than actually copied.
+ *
+ * Tasks ending with response, always set the residual field.
+ */
+struct ata_task_resp {
+	u16  frame_len;
+	u8   ending_fis[24];	  /* dev to host or data-in */
+	u32  sstatus;
+	u32  serror;
+	u32  scontrol;
+	u32  sactive;
+};
+
+#define SAS_STATUS_BUF_SIZE 96
+
+struct task_status_struct {
+	enum service_response resp;
+	enum exec_status      stat;
+	int  buf_valid_size;
+
+	u8   buf[SAS_STATUS_BUF_SIZE];
+
+	u32  residual;
+	enum sas_open_rej_reason open_rej_reason;
+};
+
+/* ATA and ATAPI task queuable to a SAS LLDD.
+ */
+struct sas_ata_task {
+	struct host_to_dev_fis fis;
+	u8     atapi_packet[16];  /* 0 if not ATAPI task */
+
+	u8     retry_count;	  /* hardware retry, should be > 0 */
+
+	u8     dma_xfer:1;	  /* PIO:0 or DMA:1 */
+	u8     use_ncq:1;
+	u8     set_affil_pol:1;
+	u8     stp_affil_pol:1;
+
+	u8     device_control_reg_update:1;
+};
+
+struct sas_smp_task {
+	struct scatterlist smp_req;
+	struct scatterlist smp_resp;
+};
+
+enum task_attribute {
+	TASK_ATTR_SIMPLE = 0,
+	TASK_ATTR_HOQ    = 1,
+	TASK_ATTR_ORDERED= 2,
+	TASK_ATTR_ACA    = 4,
+};
+
+struct sas_ssp_task {
+	u8     retry_count;	  /* hardware retry, should be > 0 */
+
+	u8     LUN[8];
+	u8     enable_first_burst:1;
+	enum   task_attribute task_attr;
+	u8     task_prio;
+	u8     cdb[16];
+};
+
+#define SAS_TASK_STATE_PENDING  1
+#define SAS_TASK_STATE_DONE     2
+#define SAS_TASK_STATE_ABORTED  4
+
+struct sas_task {
+	struct domain_device *dev;
+	struct list_head      list;
+
+	spinlock_t   task_state_lock;
+	unsigned     task_state_flags;
+
+	enum   sas_proto      task_proto;
+
+	/* Used by the discovery code. */
+	struct timer_list     timer;
+	struct completion     completion;
+
+	union {
+		struct sas_ata_task ata_task;
+		struct sas_smp_task smp_task;
+		struct sas_ssp_task ssp_task;
+	};
+
+	struct scatterlist *scatter;
+	int    num_scatter;
+	u32    total_xfer_len;
+	u8     data_dir:2;	  /* Use PCI_DMA_... */
+
+	struct task_status_struct task_status;
+	void   (*task_done)(struct sas_task *task);
+
+	void   *lldd_task;	  /* for use by LLDDs */
+	void   *uldd_task;
+};
+
+static inline struct sas_task *sas_alloc_task(unsigned long flags)
+{
+	extern kmem_cache_t *sas_task_cache;
+	struct sas_task *task = kmem_cache_alloc(sas_task_cache, flags);
+
+	memset(task, 0, sizeof(*task));
+	INIT_LIST_HEAD(&task->list);
+	spin_lock_init(&task->task_state_lock);
+	task->task_state_flags = SAS_TASK_STATE_PENDING;
+	init_timer(&task->timer);
+	init_completion(&task->completion);
+
+	return task;
+}
+
+static inline void sas_free_task(struct sas_task *task)
+{
+	if (task) {
+		extern kmem_cache_t *sas_task_cache;
+		BUG_ON(!list_empty(&task->list));
+		kmem_cache_free(sas_task_cache, task);
+	}
+}
+
+#endif /* _SAS_TASK_H_ */
diff -urN oldtree/include/scsi/scsi_cmnd.h newtree/include/scsi/scsi_cmnd.h
--- oldtree/include/scsi/scsi_cmnd.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/scsi/scsi_cmnd.h	2006-04-01 05:35:45.879487250 -0500
@@ -8,6 +8,7 @@
 
 struct request;
 struct scatterlist;
+struct Scsi_Host;
 struct scsi_device;
 struct scsi_request;
 
@@ -84,6 +85,8 @@
 	unsigned short sglist_len;	/* size of malloc'd scatter-gather list */
 	unsigned bufflen;	/* Size of data buffer */
 	void *buffer;		/* Data buffer */
+	/* offset in cmd we are at (for multi-transfer tgt cmds) */
+	unsigned offset;
 
 	unsigned underflow;	/* Return error if less than
 				   this amount is transferred */
@@ -147,9 +150,14 @@
 #define SCSI_STATE_MLQUEUE         0x100b
 
 
+extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
+					       enum dma_data_direction, gfp_t);
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
+extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
 extern void scsi_put_command(struct scsi_cmnd *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
+extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
+extern void scsi_free_sgtable(struct scatterlist *, int);
 
 #endif /* _SCSI_SCSI_CMND_H */
diff -urN oldtree/include/scsi/scsi_host.h newtree/include/scsi/scsi_host.h
--- oldtree/include/scsi/scsi_host.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/include/scsi/scsi_host.h	2006-04-01 05:35:45.879487250 -0500
@@ -7,6 +7,7 @@
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
 
+struct request_queue;
 struct block_device;
 struct completion;
 struct module;
@@ -123,6 +124,36 @@
 			     void (*done)(struct scsi_cmnd *));
 
 	/*
+	 * The transfer functions are used to queue a scsi command to
+	 * the LLD. When the driver is finished processing the command
+	 * the done callback is invoked.
+	 *
+	 * return values: see queuecommand
+	 *
+	 * If the LLD accepts the cmd, it should set the result to an
+	 * appropriate value when completed before calling the done function.
+	 *
+	 * STATUS: REQUIRED FOR TARGET DRIVERS
+	 */
+	/* TODO: rename */
+	int (* transfer_response)(struct scsi_cmnd *,
+				  void (*done)(struct scsi_cmnd *));
+	/*
+	 * This is called to inform the LLD to transfer cmd->request_bufflen
+	 * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
+	 * speciefies the number of scatterlist entried in the command
+	 * and cmd->request_buffer contains the scatterlist.
+	 *
+	 * If the command cannot be processed in one transfer_data call
+	 * becuase a scatterlist within the LLD's limits cannot be
+	 * created then transfer_data will be called multiple times.
+	 * It is initially called from process context, and later
+	 * calls are from the interrup context.
+	 */
+	int (* transfer_data)(struct scsi_cmnd *,
+			      void (*done)(struct scsi_cmnd *));
+
+	/*
 	 * This is an error handling strategy routine.  You don't need to
 	 * define one of these if you don't want to - there is a default
 	 * routine that is present that should work in most cases.  For those
@@ -572,6 +603,12 @@
 	 */
 	unsigned int max_host_blocked;
 
+	/*
+	 * q used for scsi_tgt msgs, async events or any other requests that
+	 * need to be processed in userspace
+ 	 */
+	struct request_queue *uspace_req_q;
+
 	/* legacy crap */
 	unsigned long base;
 	unsigned long io_port;
@@ -674,6 +711,9 @@
 extern void scsi_block_requests(struct Scsi_Host *);
 
 struct class_container;
+
+extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+					     void (*) (struct request_queue *));
 /*
  * These two functions are used to allocate and free a pseudo device
  * which will connect to the host adapter itself rather than any
diff -urN oldtree/include/scsi/scsi_tgt.h newtree/include/scsi/scsi_tgt.h
--- oldtree/include/scsi/scsi_tgt.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/scsi_tgt.h	2006-04-01 05:35:45.879487250 -0500
@@ -0,0 +1,11 @@
+/*
+ * SCSI target definitions
+ */
+
+struct Scsi_Host;
+struct scsi_cmnd;
+struct scsi_lun;
+
+extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd);
+extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
+extern void scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, int);
diff -urN oldtree/include/scsi/scsi_tgt_if.h newtree/include/scsi/scsi_tgt_if.h
--- oldtree/include/scsi/scsi_tgt_if.h	1969-12-31 19:00:00.000000000 -0500
+++ newtree/include/scsi/scsi_tgt_if.h	2006-04-01 05:35:45.879487250 -0500
@@ -0,0 +1,88 @@
+/*
+ * SCSI target kernel/user interface
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2005 Mike Christie <michaelc@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 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __SCSI_TARGET_IF_H
+#define __SCSI_TARGET_IF_H
+
+enum tgt_event_type {
+	/* user -> kernel */
+	TGT_UEVENT_TGTD_BIND,
+	TGT_UEVENT_TARGET_SETUP,
+	TGT_UEVENT_CMD_RES,
+
+	/* kernel -> user */
+	TGT_KEVENT_RESPONSE,
+	TGT_KEVENT_CMD_REQ,
+	TGT_KEVENT_CMD_DONE,
+};
+
+struct tgt_event {
+	/* user-> kernel */
+	union {
+		struct {
+			int pk_fd;
+		} tgtd_bind;
+		struct {
+			int host_no;
+			uint32_t cid;
+			uint32_t len;
+			int result;
+			uint64_t uaddr;
+			uint64_t offset;
+			uint8_t rw;
+			uint8_t try_map;
+		} cmd_res;
+	} u;
+
+	/* kernel -> user */
+	union {
+		struct {
+			int err;
+		} event_res;
+		struct {
+			int host_no;
+			uint32_t cid;
+			uint32_t data_len;
+			uint64_t dev_id;
+		} cmd_req;
+		struct {
+			int host_no;
+			uint32_t cid;
+			int result;
+		} cmd_done;
+	} k;
+
+	/*
+	 * I think a pointer is a unsigned long but this struct
+	 * gets passed around from the kernel to userspace and
+	 * back again so to handle some ppc64 setups where userspace is
+	 * 32 bits but the kernel is 64 we do this odd thing
+	 */
+	uint64_t data[0];
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+struct tgt_cmd {
+	uint8_t scb[16];
+	uint8_t lun[8];
+	int tags;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+#endif
diff -urN oldtree/kernel/cpu.c newtree/kernel/cpu.c
--- oldtree/kernel/cpu.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/cpu.c	2006-04-01 05:35:51.095813250 -0500
@@ -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/mutex-debug.c newtree/kernel/mutex-debug.c
--- oldtree/kernel/mutex-debug.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/mutex-debug.c	2006-04-01 05:35:51.079812250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/mutex-debug.h	2006-04-01 05:35:51.079812250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/mutex.c	2006-04-01 05:35:51.079812250 -0500
@@ -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-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/mutex.h	2006-04-01 05:35:51.079812250 -0500
@@ -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/power/Kconfig newtree/kernel/power/Kconfig
--- oldtree/kernel/power/Kconfig	2006-04-01 04:48:27.000000000 -0500
+++ newtree/kernel/power/Kconfig	2006-04-01 05:36:15.333328000 -0500
@@ -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/lib/radix-tree.c newtree/lib/radix-tree.c
--- oldtree/lib/radix-tree.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/lib/radix-tree.c	2006-04-01 05:36:06.788794000 -0500
@@ -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/scripts/ver_linux newtree/scripts/ver_linux
--- oldtree/scripts/ver_linux	2006-04-01 04:48:27.000000000 -0500
+++ newtree/scripts/ver_linux	2006-04-01 05:36:07.460836000 -0500
@@ -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/sound/pcmcia/pdaudiocf/pdaudiocf.c newtree/sound/pcmcia/pdaudiocf/pdaudiocf.c
--- oldtree/sound/pcmcia/pdaudiocf/pdaudiocf.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/sound/pcmcia/pdaudiocf/pdaudiocf.c	2006-04-01 05:35:44.311389250 -0500
@@ -57,18 +57,12 @@
 /*
  * prototypes
  */
-static void pdacf_config(dev_link_t *link);
+static int pdacf_config(struct pcmcia_device *link);
 static void snd_pdacf_detach(struct pcmcia_device *p_dev);
 
-static void pdacf_release(dev_link_t *link)
+static void pdacf_release(struct pcmcia_device *link)
 {
-	if (link->state & DEV_CONFIG) {
-		/* release cs resources */
-		pcmcia_release_configuration(link->handle);
-		pcmcia_release_io(link->handle, &link->io);
-		pcmcia_release_irq(link->handle, &link->irq);
-		link->state &= ~DEV_CONFIG;
-	}
+	pcmcia_disable_device(link);
 }
 
 /*
@@ -76,7 +70,7 @@
  */
 static int snd_pdacf_free(struct snd_pdacf *pdacf)
 {
-	dev_link_t *link = &pdacf->link;
+	struct pcmcia_device *link = pdacf->p_dev;
 
 	pdacf_release(link);
 
@@ -96,10 +90,9 @@
 /*
  * snd_pdacf_attach - attach callback for cs
  */
-static int snd_pdacf_attach(struct pcmcia_device *p_dev)
+static int snd_pdacf_probe(struct pcmcia_device *link)
 {
 	int i;
-	dev_link_t *link;               /* Info for cardmgr */
 	struct snd_pdacf *pdacf;
 	struct snd_card *card;
 	static struct snd_device_ops ops = {
@@ -139,7 +132,7 @@
 	pdacf->index = i;
 	card_list[i] = card;
 
-	link = &pdacf->link;
+	pdacf->p_dev = link;
 	link->priv = pdacf;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
@@ -156,13 +149,7 @@
 	link->conf.ConfigIndex = 1;
 	link->conf.Present = PRESENT_OPTION;
 
-	/* Chain drivers */
-	link->next = NULL;
-
-	link->handle = p_dev;
-	pdacf_config(link);
-
-	return 0;
+	return pdacf_config(link);
 }
 
 
@@ -209,9 +196,8 @@
 /*
  * snd_pdacf_detach - detach callback for cs
  */
-static void snd_pdacf_detach(struct pcmcia_device *p_dev)
+static void snd_pdacf_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct snd_pdacf *chip = link->priv;
 
 	snd_printdd(KERN_DEBUG "pdacf_detach called\n");
@@ -230,13 +216,11 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void pdacf_config(dev_link_t *link)
+static int pdacf_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	struct snd_pdacf *pdacf = link->priv;
 	tuple_t tuple;
 	cisparse_t *parse = NULL;
-	config_info_t conf;
 	u_short buf[32];
 	int last_fn, last_ret;
 
@@ -244,7 +228,7 @@
 	parse = kmalloc(sizeof(*parse), GFP_KERNEL);
 	if (! parse) {
 		snd_printk(KERN_ERR "pdacf_config: cannot allocate\n");
-		return;
+		return -ENOMEM;
 	}
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	tuple.Attributes = 0;
@@ -252,71 +236,51 @@
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse));
 	link->conf.ConfigBase = parse->config.base;
 	link->conf.ConfigIndex = 0x5;
 	kfree(parse);
 
-	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-	link->conf.Vcc = conf.Vcc;
-
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
-	CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
 	if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
 		goto failed;
 
-	link->dev = &pdacf->node;
-	link->state &= ~DEV_CONFIG_PENDING;
-	return;
+	link->dev_node = &pdacf->node;
+	return 0;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 failed:
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
+	pcmcia_disable_device(link);
+	return -ENODEV;
 }
 
 #ifdef CONFIG_PM
 
-static int pdacf_suspend(struct pcmcia_device *dev)
+static int pdacf_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	struct snd_pdacf *chip = link->priv;
 
 	snd_printdd(KERN_DEBUG "SUSPEND\n");
-	link->state |= DEV_SUSPEND;
 	if (chip) {
 		snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n");
 		snd_pdacf_suspend(chip, PMSG_SUSPEND);
 	}
 
-	snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
-
 	return 0;
 }
 
-static int pdacf_resume(struct pcmcia_device *dev)
+static int pdacf_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	struct snd_pdacf *chip = link->priv;
 
 	snd_printdd(KERN_DEBUG "RESUME\n");
-	link->state &= ~DEV_SUSPEND;
-
-	snd_printdd(KERN_DEBUG "CARD_RESET\n");
-	if (DEV_OK(link)) {
-		snd_printdd(KERN_DEBUG "requestconfig...\n");
-		pcmcia_request_configuration(link->handle, &link->conf);
+	if (pcmcia_dev_present(link)) {
 		if (chip) {
 			snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n");
 			snd_pdacf_resume(chip);
@@ -343,7 +307,7 @@
 	.drv		= {
 		.name	= "snd-pdaudiocf",
 	},
-	.probe		= snd_pdacf_attach,
+	.probe		= snd_pdacf_probe,
 	.remove		= snd_pdacf_detach,
 	.id_table	= snd_pdacf_ids,
 #ifdef CONFIG_PM
diff -urN oldtree/sound/pcmcia/pdaudiocf/pdaudiocf.h newtree/sound/pcmcia/pdaudiocf/pdaudiocf.h
--- oldtree/sound/pcmcia/pdaudiocf/pdaudiocf.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/sound/pcmcia/pdaudiocf/pdaudiocf.h	2006-04-01 05:35:44.311389250 -0500
@@ -116,7 +116,7 @@
 	void *pcm_area;
 	
 	/* pcmcia stuff */
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 };
 
diff -urN oldtree/sound/pcmcia/vx/vxpocket.c newtree/sound/pcmcia/vx/vxpocket.c
--- oldtree/sound/pcmcia/vx/vxpocket.c	2006-04-01 04:48:27.000000000 -0500
+++ newtree/sound/pcmcia/vx/vxpocket.c	2006-04-01 05:35:44.315389500 -0500
@@ -59,15 +59,9 @@
 
 /*
  */
-static void vxpocket_release(dev_link_t *link)
+static void vxpocket_release(struct pcmcia_device *link)
 {
-	if (link->state & DEV_CONFIG) {
-		/* release cs resources */
-		pcmcia_release_configuration(link->handle);
-		pcmcia_release_io(link->handle, &link->io);
-		pcmcia_release_irq(link->handle, &link->irq);
-		link->state &= ~DEV_CONFIG;
-	}
+	pcmcia_disable_device(link);
 }
 
 /*
@@ -132,9 +126,9 @@
 /*
  * create vxpocket instance
  */
-static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl)
+static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl,
+					     struct pcmcia_device *link)
 {
-	dev_link_t *link;		/* Info for cardmgr */
 	struct vx_core *chip;
 	struct snd_vxpocket *vxp;
 	static struct snd_device_ops ops = {
@@ -154,7 +148,7 @@
 
 	vxp = (struct snd_vxpocket *)chip;
 
-	link = &vxp->link;
+	vxp->p_dev = link;
 	link->priv = chip;
 
 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
@@ -167,7 +161,6 @@
 	link->irq.Instance = chip;
 
 	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 	link->conf.ConfigIndex = 1;
 	link->conf.Present = PRESENT_OPTION;
@@ -215,9 +208,8 @@
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void vxpocket_config(dev_link_t *link)
+static int vxpocket_config(struct pcmcia_device *link)
 {
-	client_handle_t handle = link->handle;
 	struct vx_core *chip = link->priv;
 	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
 	tuple_t tuple;
@@ -229,24 +221,24 @@
 	parse = kmalloc(sizeof(*parse), GFP_KERNEL);
 	if (! parse) {
 		snd_printk(KERN_ERR "vx: cannot allocate\n");
-		return;
+		return -ENOMEM;
 	}
 	tuple.Attributes = 0;
 	tuple.TupleData = (cisdata_t *)buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
 	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse));
 	link->conf.ConfigBase = parse->config.base;
 	link->conf.Present = parse->config.rmask[0];
 
 	/* redefine hardware record according to the VERSION1 string */
 	tuple.DesiredTuple = CISTPL_VERS_1;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse));
 	if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) {
 		snd_printdd("VX-pocket is detected\n");
 	} else {
@@ -257,67 +249,50 @@
 		strcpy(chip->card->driver, vxp440_hw.name);
 	}
 
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
-	CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+	CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
-	chip->dev = &handle_to_dev(link->handle);
+	chip->dev = &handle_to_dev(link);
 	snd_card_set_dev(chip->card, chip->dev);
 
 	if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
 		goto failed;
 
-	link->dev = &vxp->node;
-	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev_node = &vxp->node;
 	kfree(parse);
-	return;
+	return 9;
 
 cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	cs_error(link, last_fn, last_ret);
 failed:
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
+	pcmcia_disable_device(link);
 	kfree(parse);
+	return -ENODEV;
 }
 
 #ifdef CONFIG_PM
 
-static int vxp_suspend(struct pcmcia_device *dev)
+static int vxp_suspend(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	struct vx_core *chip = link->priv;
 
 	snd_printdd(KERN_DEBUG "SUSPEND\n");
-	link->state |= DEV_SUSPEND;
 	if (chip) {
 		snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
 		snd_vx_suspend(chip, PMSG_SUSPEND);
 	}
-	snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
-	if (link->state & DEV_CONFIG)
-		pcmcia_release_configuration(link->handle);
 
 	return 0;
 }
 
-static int vxp_resume(struct pcmcia_device *dev)
+static int vxp_resume(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(dev);
 	struct vx_core *chip = link->priv;
 
 	snd_printdd(KERN_DEBUG "RESUME\n");
-	link->state &= ~DEV_SUSPEND;
-
-	snd_printdd(KERN_DEBUG "CARD_RESET\n");
-	if (DEV_OK(link)) {
+	if (pcmcia_dev_present(link)) {
 		//struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-		snd_printdd(KERN_DEBUG "requestconfig...\n");
-		pcmcia_request_configuration(link->handle, &link->conf);
 		if (chip) {
 			snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
 			snd_vx_resume(chip);
@@ -333,7 +308,7 @@
 
 /*
  */
-static int vxpocket_attach(struct pcmcia_device *p_dev)
+static int vxpocket_probe(struct pcmcia_device *p_dev)
 {
 	struct snd_card *card;
 	struct snd_vxpocket *vxp;
@@ -358,7 +333,7 @@
 		return -ENOMEM;
 	}
 
-	vxp = snd_vxpocket_new(card, ibl[i]);
+	vxp = snd_vxpocket_new(card, ibl[i], p_dev);
 	if (! vxp) {
 		snd_card_free(card);
 		return -ENODEV;
@@ -368,20 +343,13 @@
 	vxp->index = i;
 	card_alloc |= 1 << i;
 
-	/* Chain drivers */
-	vxp->link.next = NULL;
-
-	vxp->link.handle = p_dev;
-	vxp->link.state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	p_dev->instance = &vxp->link;
-	vxpocket_config(&vxp->link);
+	vxp->p_dev = p_dev;
 
-	return 0;
+	return vxpocket_config(p_dev);
 }
 
-static void vxpocket_detach(struct pcmcia_device *p_dev)
+static void vxpocket_detach(struct pcmcia_device *link)
 {
-	dev_link_t *link = dev_to_instance(p_dev);
 	struct snd_vxpocket *vxp;
 	struct vx_core *chip;
 
@@ -413,7 +381,7 @@
 	.drv		= {
 		.name	= "snd-vxpocket",
 	},
-	.probe		= vxpocket_attach,
+	.probe		= vxpocket_probe,
 	.remove		= vxpocket_detach,
 	.id_table	= vxp_ids,
 #ifdef CONFIG_PM
diff -urN oldtree/sound/pcmcia/vx/vxpocket.h newtree/sound/pcmcia/vx/vxpocket.h
--- oldtree/sound/pcmcia/vx/vxpocket.h	2006-04-01 04:48:27.000000000 -0500
+++ newtree/sound/pcmcia/vx/vxpocket.h	2006-04-01 05:35:44.315389500 -0500
@@ -42,7 +42,7 @@
 	int index;	/* card index */
 
 	/* pcmcia stuff */
-	dev_link_t link;
+	struct pcmcia_device	*p_dev;
 	dev_node_t node;
 };
 
