Merge master.kernel.org:/home/rmk/linux-2.6-serial
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index dd311cf..6bd30fd 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -143,7 +143,7 @@
 	http://kernelnewbies.org/
 
 Linux USB project:
-	http://linux-usb.sourceforge.net/
+	http://www.linux-usb.org/
 
 How to NOT write kernel driver by arjanv@redhat.com
 	http://people.redhat.com/arjanv/olspaper.pdf
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 6198e5e..c2c85bc 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -478,10 +478,11 @@
 Jeff Garzik, "Linux kernel patch submission format."
   <http://linux.yyz.us/patch-format.html>
 
-Greg Kroah, "How to piss off a kernel subsystem maintainer".
+Greg Kroah-Hartman "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/2005/03/31/>
   <http://www.kroah.com/log/2005/07/08/>
   <http://www.kroah.com/log/2005/10/19/>
+  <http://www.kroah.com/log/2006/01/11/>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!.
   <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 9474501..b4a1ea7 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -123,6 +123,15 @@
 
 ---------------------------
 
+What:	CONFIG_FORCED_INLINING
+When:	June 2006
+Why:	Config option is there to see if gcc is good enough. (in january
+        2006). If it is, the behavior should just be the default. If it's not,
+	the option should just go away entirely.
+Who:    Arjan van de Ven
+
+---------------------------
+
 What:	START_ARRAY ioctl for md
 When:	July 2006
 Files:	drivers/md/md.c
diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt
index 0d783c5..dbe4d87 100644
--- a/Documentation/filesystems/tmpfs.txt
+++ b/Documentation/filesystems/tmpfs.txt
@@ -78,6 +78,18 @@
 that instance in a system with many cpus making intensive use of it.
 
 
+tmpfs has a mount option to set the NUMA memory allocation policy for
+all files in that instance:
+mpol=interleave		prefers to allocate memory from each node in turn
+mpol=default		prefers to allocate memory from the local node
+mpol=bind		prefers to allocate from mpol_nodelist
+mpol=preferred		prefers to allocate from first node in mpol_nodelist
+
+The following mount option is used in conjunction with mpol=interleave,
+mpol=bind or mpol=preferred:
+mpol_nodelist:	nodelist suitable for parsing with nodelist_parse.
+
+
 To specify the initial root directory you can use the following mount
 options:
 
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index fe11fcc..1cbcf65 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -471,7 +471,7 @@
 			arch/i386/kernel/cpu/cpufreq/elanfreq.c.
 
 	elevator=	[IOSCHED]
-			Format: {"as" | "cfq" | "deadline" | "noop"}
+			Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
 			See Documentation/block/as-iosched.txt and
 			Documentation/block/deadline-iosched.txt for details.
 
@@ -712,9 +712,17 @@
 	load_ramdisk=	[RAM] List of ramdisks to load from floppy
 			See Documentation/ramdisk.txt.
 
-	lockd.udpport=	[NFS]
+	lockd.nlm_grace_period=P  [NFS] Assign grace period.
+			Format: <integer>
 
-	lockd.tcpport=	[NFS]
+	lockd.nlm_tcpport=N	[NFS] Assign TCP port.
+			Format: <integer>
+
+	lockd.nlm_timeout=T	[NFS] Assign timeout value.
+			Format: <integer>
+
+	lockd.nlm_udpport=M	[NFS] Assign UDP port.
+			Format: <integer>
 
 	logibm.irq=	[HW,MOUSE] Logitech Bus Mouse Driver
 			Format: <irq>
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
new file mode 100644
index 0000000..820fd07
--- /dev/null
+++ b/Documentation/scsi/aacraid.txt
@@ -0,0 +1,108 @@
+AACRAID Driver for Linux (take two)
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+RAID controllers. This is a major rewrite from the original
+Adaptec supplied driver. It has signficantly cleaned up both the code
+and the running binary size (the module is less than half the size of
+the original).
+
+Supported Cards/Chipsets
+-------------------------
+	PCI ID (pci.ids)	OEM	Product
+	9005:0285:9005:028a	Adaptec	2020ZCR (Skyhawk)
+	9005:0285:9005:028e	Adaptec	2020SA (Skyhawk)
+	9005:0285:9005:028b	Adaptec 2025ZCR (Terminator)
+	9005:0285:9005:028f	Adaptec 2025SA (Terminator)
+	9005:0285:9005:0286	Adaptec	2120S (Crusader)
+	9005:0286:9005:028d	Adaptec	2130S (Lancer)
+	9005:0285:9005:0285	Adaptec	2200S (Vulcan)
+	9005:0285:9005:0287	Adaptec	2200S (Vulcan-2m)
+	9005:0286:9005:028c	Adaptec	2230S (Lancer)
+	9005:0286:9005:028c	Adaptec	2230SLP (Lancer)
+	9005:0285:9005:0296	Adaptec	2240S (SabreExpress)
+	9005:0285:9005:0290	Adaptec	2410SA (Jaguar)
+	9005:0285:9005:0293	Adaptec 21610SA (Corsair-16)
+	9005:0285:103c:3227	Adaptec 2610SA (Bearcat)
+	9005:0285:9005:0292	Adaptec	2810SA (Corsair-8)
+	9005:0285:9005:0294	Adaptec	Prowler
+	9005:0286:9005:029d	Adaptec	2420SA (Intruder)
+	9005:0286:9005:029c	Adaptec	2620SA (Intruder)
+	9005:0286:9005:029b	Adaptec	2820SA (Intruder)
+	9005:0286:9005:02a7	Adaptec	2830SA (Skyray)
+	9005:0286:9005:02a8	Adaptec	2430SA (Skyray)
+	9005:0285:9005:0288	Adaptec	3230S (Harrier)
+	9005:0285:9005:0289	Adaptec	3240S (Tornado)
+	9005:0285:9005:0298	Adaptec	4000SAS (BlackBird)
+	9005:0285:9005:0297	Adaptec	4005SAS (AvonPark)
+	9005:0285:9005:0299	Adaptec	4800SAS (Marauder-X)
+	9005:0285:9005:029a	Adaptec	4805SAS (Marauder-E)
+	9005:0286:9005:02a2	Adaptec	4810SAS (Hurricane)
+	1011:0046:9005:0364	Adaptec	5400S (Mustang)
+	1011:0046:9005:0365	Adaptec	5400S (Mustang)
+	9005:0283:9005:0283	Adaptec	Catapult (3210S with arc firmware)
+	9005:0284:9005:0284	Adaptec	Tomcat (3410S with arc firmware)
+	9005:0287:9005:0800	Adaptec	Themisto (Jupiter)
+	9005:0200:9005:0200	Adaptec	Themisto (Jupiter)
+	9005:0286:9005:0800	Adaptec	Callisto (Jupiter)
+	1011:0046:9005:1364	Dell	PERC 2/QC (Quad Channel, Mustang)
+	1028:0001:1028:0001	Dell	PERC 2/Si (Iguana)
+	1028:0003:1028:0003	Dell	PERC 3/Si (SlimFast)
+	1028:0002:1028:0002	Dell	PERC 3/Di (Opal)
+	1028:0004:1028:0004	Dell	PERC 3/DiF (Iguana)
+	1028:0002:1028:00d1	Dell	PERC 3/DiV (Viper)
+	1028:0002:1028:00d9	Dell	PERC 3/DiL (Lexus)
+	1028:000a:1028:0106	Dell	PERC 3/DiJ (Jaguar)
+	1028:000a:1028:011b	Dell	PERC 3/DiD (Dagger)
+	1028:000a:1028:0121	Dell	PERC 3/DiB (Boxster)
+	9005:0285:1028:0287	Dell	PERC 320/DC (Vulcan)
+	9005:0285:1028:0291	Dell	CERC 2 (DellCorsair)
+	1011:0046:103c:10c2	HP	NetRAID-4M (Mustang)
+	9005:0285:17aa:0286	Legend	S220 (Crusader)
+	9005:0285:17aa:0287	Legend	S230 (Vulcan)
+	9005:0285:9005:0290	IBM	ServeRAID 7t (Jaguar)
+	9005:0285:1014:02F2	IBM	ServeRAID 8i (AvonPark)
+	9005:0285:1014:0312	IBM	ServeRAID 8i (AvonParkLite)
+	9005:0286:1014:9580	IBM	ServeRAID 8k/8k-l8 (Aurora)
+	9005:0286:1014:9540	IBM	ServeRAID 8k/8k-l4 (AuroraLite)
+	9005:0286:9005:029f	ICP	ICP9014R0 (Lancer)
+	9005:0286:9005:029e	ICP	ICP9024R0 (Lancer)
+	9005:0286:9005:02a0	ICP	ICP9047MA (Lancer)
+	9005:0286:9005:02a1	ICP	ICP9087MA (Lancer)
+	9005:0286:9005:02a4	ICP	ICP9085LI (Marauder-X)
+	9005:0286:9005:02a5	ICP	ICP5085BR (Marauder-E)
+	9005:0286:9005:02a3	ICP	ICP5085AU (Hurricane)
+	9005:0286:9005:02a6	ICP	ICP9067MA (Intruder-6)
+	9005:0286:9005:02a9	ICP	ICP5087AU (Skyray)
+	9005:0286:9005:02aa	ICP	ICP5047AU (Skyray)
+
+People
+-------------------------
+Alan Cox <alan@redhat.com>
+Christoph Hellwig <hch@infradead.org>	(updates for new-style PCI probing and SCSI host registration,
+					 small cleanups/fixes)
+Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
+Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
+					 added new ioctls, changed scsi interface to use new error handler,
+					 increased the number of fibs and outstanding commands to a container)
+
+					(fixed 64bit and 64G memory model, changed confusing naming convention
+					 where fibs that go to the hardware are consistently called hw_fibs and
+					 not just fibs like the name of the driver tracking structure)
+Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas. Performance tuning, card failover and bug mitigations.
+
+Original Driver
+-------------------------
+Adaptec Unix OEM Product Group
+
+Mailing List
+-------------------------
+linux-scsi@vger.kernel.org (Interested parties troll here)
+Also note this is very different to Brian's original driver
+so don't expect him to support it.
+Adaptec does support this driver.  Contact Adaptec tech support or
+aacraid@adaptec.com
+
+Original by Brian Boerner February 2001
+Rewritten by Alan Cox, November 2001
diff --git a/Documentation/spi/butterfly b/Documentation/spi/butterfly
new file mode 100644
index 0000000..a2e8c8d
--- /dev/null
+++ b/Documentation/spi/butterfly
@@ -0,0 +1,57 @@
+spi_butterfly - parport-to-butterfly adapter driver
+===================================================
+
+This is a hardware and software project that includes building and using
+a parallel port adapter cable, together with an "AVR Butterfly" to run
+firmware for user interfacing and/or sensors.  A Butterfly is a $US20
+battery powered card with an AVR microcontroller and lots of goodies:
+sensors, LCD, flash, toggle stick, and more.  You can use AVR-GCC to
+develop firmware for this, and flash it using this adapter cable.
+
+You can make this adapter from an old printer cable and solder things
+directly to the Butterfly.  Or (if you have the parts and skills) you
+can come up with something fancier, providing ciruit protection to the
+Butterfly and the printer port, or with a better power supply than two
+signal pins from the printer port.
+
+
+The first cable connections will hook Linux up to one SPI bus, with the
+AVR and a DataFlash chip; and to the AVR reset line.  This is all you
+need to reflash the firmware, and the pins are the standard Atmel "ISP"
+connector pins (used also on non-Butterfly AVR boards).
+
+	Signal	  Butterfly	  Parport (DB-25)
+	------	  ---------	  ---------------
+	SCK	= J403.PB1/SCK	= pin 2/D0
+	RESET	= J403.nRST	= pin 3/D1
+	VCC	= J403.VCC_EXT	= pin 8/D6
+	MOSI	= J403.PB2/MOSI	= pin 9/D7
+	MISO	= J403.PB3/MISO	= pin 11/S7,nBUSY
+	GND	= J403.GND	= pin 23/GND
+
+Then to let Linux master that bus to talk to the DataFlash chip, you must
+(a) flash new firmware that disables SPI (set PRR.2, and disable pullups
+by clearing PORTB.[0-3]); (b) configure the mtd_dataflash driver; and
+(c) cable in the chipselect.
+
+	Signal	  Butterfly	  Parport (DB-25)
+	------	  ---------	  ---------------
+	VCC	= J400.VCC_EXT	= pin 7/D5
+	SELECT	= J400.PB0/nSS	= pin 17/C3,nSELECT
+	GND	= J400.GND	= pin 24/GND
+
+The "USI" controller, using J405, can be used for a second SPI bus.  That
+would let you talk to the AVR over SPI, running firmware that makes it act
+as an SPI slave, while letting either Linux or the AVR use the DataFlash.
+There are plenty of spare parport pins to wire this one up, such as:
+
+	Signal	  Butterfly	  Parport (DB-25)
+	------	  ---------	  ---------------
+	SCK	= J403.PE4/USCK	= pin 5/D3
+	MOSI	= J403.PE5/DI	= pin 6/D4
+	MISO	= J403.PE6/DO	= pin 12/S5,nPAPEROUT
+	GND	= J403.GND	= pin 22/GND
+
+	IRQ	= J402.PF4	= pin 10/S6,ACK
+	GND	= J402.GND(P2)	= pin 25/GND
+
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
new file mode 100644
index 0000000..a5ffba3
--- /dev/null
+++ b/Documentation/spi/spi-summary
@@ -0,0 +1,457 @@
+Overview of Linux kernel SPI support
+====================================
+
+02-Dec-2005
+
+What is SPI?
+------------
+The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial
+link used to connect microcontrollers to sensors, memory, and peripherals.
+
+The three signal wires hold a clock (SCLK, often on the order of 10 MHz),
+and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In,
+Slave Out" (MISO) signals.  (Other names are also used.)  There are four
+clocking modes through which data is exchanged; mode-0 and mode-3 are most
+commonly used.  Each clock cycle shifts data out and data in; the clock
+doesn't cycle except when there is data to shift.
+
+SPI masters may use a "chip select" line to activate a given SPI slave
+device, so those three signal wires may be connected to several chips
+in parallel.  All SPI slaves support chipselects.  Some devices have
+other signals, often including an interrupt to the master.
+
+Unlike serial busses like USB or SMBUS, even low level protocols for
+SPI slave functions are usually not interoperable between vendors
+(except for cases like SPI memory chips).
+
+  - SPI may be used for request/response style device protocols, as with
+    touchscreen sensors and memory chips.
+
+  - It may also be used to stream data in either direction (half duplex),
+    or both of them at the same time (full duplex).
+
+  - Some devices may use eight bit words.  Others may different word
+    lengths, such as streams of 12-bit or 20-bit digital samples.
+
+In the same way, SPI slaves will only rarely support any kind of automatic
+discovery/enumeration protocol.  The tree of slave devices accessible from
+a given SPI master will normally be set up manually, with configuration
+tables.
+
+SPI is only one of the names used by such four-wire protocols, and
+most controllers have no problem handling "MicroWire" (think of it as
+half-duplex SPI, for request/response protocols), SSP ("Synchronous
+Serial Protocol"), PSP ("Programmable Serial Protocol"), and other
+related protocols.
+
+Microcontrollers often support both master and slave sides of the SPI
+protocol.  This document (and Linux) currently only supports the master
+side of SPI interactions.
+
+
+Who uses it?  On what kinds of systems?
+---------------------------------------
+Linux developers using SPI are probably writing device drivers for embedded
+systems boards.  SPI is used to control external chips, and it is also a
+protocol supported by every MMC or SD memory card.  (The older "DataFlash"
+cards, predating MMC cards but using the same connectors and card shape,
+support only SPI.)  Some PC hardware uses SPI flash for BIOS code.
+
+SPI slave chips range from digital/analog converters used for analog
+sensors and codecs, to memory, to peripherals like USB controllers
+or Ethernet adapters; and more.
+
+Most systems using SPI will integrate a few devices on a mainboard.
+Some provide SPI links on expansion connectors; in cases where no
+dedicated SPI controller exists, GPIO pins can be used to create a
+low speed "bitbanging" adapter.  Very few systems will "hotplug" an SPI
+controller; the reasons to use SPI focus on low cost and simple operation,
+and if dynamic reconfiguration is important, USB will often be a more
+appropriate low-pincount peripheral bus.
+
+Many microcontrollers that can run Linux integrate one or more I/O
+interfaces with SPI modes.  Given SPI support, they could use MMC or SD
+cards without needing a special purpose MMC/SD/SDIO controller.
+
+
+How do these driver programming interfaces work?
+------------------------------------------------
+The <linux/spi/spi.h> header file includes kerneldoc, as does the
+main source code, and you should certainly read that.  This is just
+an overview, so you get the big picture before the details.
+
+SPI requests always go into I/O queues.  Requests for a given SPI device
+are always executed in FIFO order, and complete asynchronously through
+completion callbacks.  There are also some simple synchronous wrappers
+for those calls, including ones for common transaction types like writing
+a command and then reading its response.
+
+There are two types of SPI driver, here called:
+
+  Controller drivers ... these are often built in to System-On-Chip
+	processors, and often support both Master and Slave roles.
+	These drivers touch hardware registers and may use DMA.
+	Or they can be PIO bitbangers, needing just GPIO pins.
+
+  Protocol drivers ... these pass messages through the controller
+	driver to communicate with a Slave or Master device on the
+	other side of an SPI link.
+
+So for example one protocol driver might talk to the MTD layer to export
+data to filesystems stored on SPI flash like DataFlash; and others might
+control audio interfaces, present touchscreen sensors as input interfaces,
+or monitor temperature and voltage levels during industrial processing.
+And those might all be sharing the same controller driver.
+
+A "struct spi_device" encapsulates the master-side interface between
+those two types of driver.  At this writing, Linux has no slave side
+programming interface.
+
+There is a minimal core of SPI programming interfaces, focussing on
+using driver model to connect controller and protocol drivers using
+device tables provided by board specific initialization code.  SPI
+shows up in sysfs in several locations:
+
+   /sys/devices/.../CTLR/spiB.C ... spi_device for on bus "B",
+	chipselect C, accessed through CTLR.
+
+   /sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver
+	that should be used with this device (for hotplug/coldplug)
+
+   /sys/bus/spi/devices/spiB.C ... symlink to the physical
+   	spiB-C device
+
+   /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
+
+   /sys/class/spi_master/spiB ... class device for the controller
+	managing bus "B".  All the spiB.* devices share the same
+	physical SPI bus segment, with SCLK, MOSI, and MISO.
+
+
+How does board-specific init code declare SPI devices?
+------------------------------------------------------
+Linux needs several kinds of information to properly configure SPI devices.
+That information is normally provided by board-specific code, even for
+chips that do support some of automated discovery/enumeration.
+
+DECLARE CONTROLLERS
+
+The first kind of information is a list of what SPI controllers exist.
+For System-on-Chip (SOC) based boards, these will usually be platform
+devices, and the controller may need some platform_data in order to
+operate properly.  The "struct platform_device" will include resources
+like the physical address of the controller's first register and its IRQ.
+
+Platforms will often abstract the "register SPI controller" operation,
+maybe coupling it with code to initialize pin configurations, so that
+the arch/.../mach-*/board-*.c files for several boards can all share the
+same basic controller setup code.  This is because most SOCs have several
+SPI-capable controllers, and only the ones actually usable on a given
+board should normally be set up and registered.
+
+So for example arch/.../mach-*/board-*.c files might have code like:
+
+	#include <asm/arch/spi.h>	/* for mysoc_spi_data */
+
+	/* if your mach-* infrastructure doesn't support kernels that can
+	 * run on multiple boards, pdata wouldn't benefit from "__init".
+	 */
+	static struct mysoc_spi_data __init pdata = { ... };
+
+	static __init board_init(void)
+	{
+		...
+		/* this board only uses SPI controller #2 */
+		mysoc_register_spi(2, &pdata);
+		...
+	}
+
+And SOC-specific utility code might look something like:
+
+	#include <asm/arch/spi.h>
+
+	static struct platform_device spi2 = { ... };
+
+	void mysoc_register_spi(unsigned n, struct mysoc_spi_data *pdata)
+	{
+		struct mysoc_spi_data *pdata2;
+
+		pdata2 = kmalloc(sizeof *pdata2, GFP_KERNEL);
+		*pdata2 = pdata;
+		...
+		if (n == 2) {
+			spi2->dev.platform_data = pdata2;
+			register_platform_device(&spi2);
+
+			/* also: set up pin modes so the spi2 signals are
+			 * visible on the relevant pins ... bootloaders on
+			 * production boards may already have done this, but
+			 * developer boards will often need Linux to do it.
+			 */
+		}
+		...
+	}
+
+Notice how the platform_data for boards may be different, even if the
+same SOC controller is used.  For example, on one board SPI might use
+an external clock, where another derives the SPI clock from current
+settings of some master clock.
+
+
+DECLARE SLAVE DEVICES
+
+The second kind of information is a list of what SPI slave devices exist
+on the target board, often with some board-specific data needed for the
+driver to work correctly.
+
+Normally your arch/.../mach-*/board-*.c files would provide a small table
+listing the SPI devices on each board.  (This would typically be only a
+small handful.)  That might look like:
+
+	static struct ads7846_platform_data ads_info = {
+		.vref_delay_usecs	= 100,
+		.x_plate_ohms		= 580,
+		.y_plate_ohms		= 410,
+	};
+
+	static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias	= "ads7846",
+		.platform_data	= &ads_info,
+		.mode		= SPI_MODE_0,
+		.irq		= GPIO_IRQ(31),
+		.max_speed_hz	= 120000 /* max sample rate at 3V */ * 16,
+		.bus_num	= 1,
+		.chip_select	= 0,
+	},
+	};
+
+Again, notice how board-specific information is provided; each chip may need
+several types.  This example shows generic constraints like the fastest SPI
+clock to allow (a function of board voltage in this case) or how an IRQ pin
+is wired, plus chip-specific constraints like an important delay that's
+changed by the capacitance at one pin.
+
+(There's also "controller_data", information that may be useful to the
+controller driver.  An example would be peripheral-specific DMA tuning
+data or chipselect callbacks.  This is stored in spi_device later.)
+
+The board_info should provide enough information to let the system work
+without the chip's driver being loaded.  The most troublesome aspect of
+that is likely the SPI_CS_HIGH bit in the spi_device.mode field, since
+sharing a bus with a device that interprets chipselect "backwards" is
+not possible.
+
+Then your board initialization code would register that table with the SPI
+infrastructure, so that it's available later when the SPI master controller
+driver is registered:
+
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+Like with other static board-specific setup, you won't unregister those.
+
+The widely used "card" style computers bundle memory, cpu, and little else
+onto a card that's maybe just thirty square centimeters.  On such systems,
+your arch/.../mach-.../board-*.c file would primarily provide information
+about the devices on the mainboard into which such a card is plugged.  That
+certainly includes SPI devices hooked up through the card connectors!
+
+
+NON-STATIC CONFIGURATIONS
+
+Developer boards often play by different rules than product boards, and one
+example is the potential need to hotplug SPI devices and/or controllers.
+
+For those cases you might need to use use spi_busnum_to_master() to look
+up the spi bus master, and will likely need spi_new_device() to provide the
+board info based on the board that was hotplugged.  Of course, you'd later
+call at least spi_unregister_device() when that board is removed.
+
+When Linux includes support for MMC/SD/SDIO/DataFlash cards through SPI, those
+configurations will also be dynamic.  Fortunately, those devices all support
+basic device identification probes, so that support should hotplug normally.
+
+
+How do I write an "SPI Protocol Driver"?
+----------------------------------------
+All SPI drivers are currently kernel drivers.  A userspace driver API
+would just be another kernel driver, probably offering some lowlevel
+access through aio_read(), aio_write(), and ioctl() calls and using the
+standard userspace sysfs mechanisms to bind to a given SPI device.
+
+SPI protocol drivers somewhat resemble platform device drivers:
+
+	static struct spi_driver CHIP_driver = {
+		.driver = {
+			.name		= "CHIP",
+			.bus		= &spi_bus_type,
+			.owner		= THIS_MODULE,
+		},
+
+		.probe		= CHIP_probe,
+		.remove		= __devexit_p(CHIP_remove),
+		.suspend	= CHIP_suspend,
+		.resume		= CHIP_resume,
+	};
+
+The driver core will autmatically attempt to bind this driver to any SPI
+device whose board_info gave a modalias of "CHIP".  Your probe() code
+might look like this unless you're creating a class_device:
+
+	static int __devinit CHIP_probe(struct spi_device *spi)
+	{
+		struct CHIP			*chip;
+		struct CHIP_platform_data	*pdata;
+
+		/* assuming the driver requires board-specific data: */
+		pdata = &spi->dev.platform_data;
+		if (!pdata)
+			return -ENODEV;
+
+		/* get memory for driver's per-chip state */
+		chip = kzalloc(sizeof *chip, GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+		dev_set_drvdata(&spi->dev, chip);
+
+		... etc
+		return 0;
+	}
+
+As soon as it enters probe(), the driver may issue I/O requests to
+the SPI device using "struct spi_message".  When remove() returns,
+the driver guarantees that it won't submit any more such messages.
+
+  - An spi_message is a sequence of of protocol operations, executed
+    as one atomic sequence.  SPI driver controls include:
+
+      + when bidirectional reads and writes start ... by how its
+        sequence of spi_transfer requests is arranged;
+
+      + optionally defining short delays after transfers ... using
+        the spi_transfer.delay_usecs setting;
+
+      + whether the chipselect becomes inactive after a transfer and
+        any delay ... by using the spi_transfer.cs_change flag;
+
+      + hinting whether the next message is likely to go to this same
+        device ... using the spi_transfer.cs_change flag on the last
+	transfer in that atomic group, and potentially saving costs
+	for chip deselect and select operations.
+
+  - Follow standard kernel rules, and provide DMA-safe buffers in
+    your messages.  That way controller drivers using DMA aren't forced
+    to make extra copies unless the hardware requires it (e.g. working
+    around hardware errata that force the use of bounce buffering).
+
+    If standard dma_map_single() handling of these buffers is inappropriate,
+    you can use spi_message.is_dma_mapped to tell the controller driver
+    that you've already provided the relevant DMA addresses.
+
+  - The basic I/O primitive is spi_async().  Async requests may be
+    issued in any context (irq handler, task, etc) and completion
+    is reported using a callback provided with the message.
+    After any detected error, the chip is deselected and processing
+    of that spi_message is aborted.
+
+  - There are also synchronous wrappers like spi_sync(), and wrappers
+    like spi_read(), spi_write(), and spi_write_then_read().  These
+    may be issued only in contexts that may sleep, and they're all
+    clean (and small, and "optional") layers over spi_async().
+
+  - The spi_write_then_read() call, and convenience wrappers around
+    it, should only be used with small amounts of data where the
+    cost of an extra copy may be ignored.  It's designed to support
+    common RPC-style requests, such as writing an eight bit command
+    and reading a sixteen bit response -- spi_w8r16() being one its
+    wrappers, doing exactly that.
+
+Some drivers may need to modify spi_device characteristics like the
+transfer mode, wordsize, or clock rate.  This is done with spi_setup(),
+which would normally be called from probe() before the first I/O is
+done to the device.
+
+While "spi_device" would be the bottom boundary of the driver, the
+upper boundaries might include sysfs (especially for sensor readings),
+the input layer, ALSA, networking, MTD, the character device framework,
+or other Linux subsystems.
+
+Note that there are two types of memory your driver must manage as part
+of interacting with SPI devices.
+
+  - I/O buffers use the usual Linux rules, and must be DMA-safe.
+    You'd normally allocate them from the heap or free page pool.
+    Don't use the stack, or anything that's declared "static".
+
+  - The spi_message and spi_transfer metadata used to glue those
+    I/O buffers into a group of protocol transactions.  These can
+    be allocated anywhere it's convenient, including as part of
+    other allocate-once driver data structures.  Zero-init these.
+
+If you like, spi_message_alloc() and spi_message_free() convenience
+routines are available to allocate and zero-initialize an spi_message
+with several transfers.
+
+
+How do I write an "SPI Master Controller Driver"?
+-------------------------------------------------
+An SPI controller will probably be registered on the platform_bus; write
+a driver to bind to the device, whichever bus is involved.
+
+The main task of this type of driver is to provide an "spi_master".
+Use spi_alloc_master() to allocate the master, and class_get_devdata()
+to get the driver-private data allocated for that device.
+
+	struct spi_master	*master;
+	struct CONTROLLER	*c;
+
+	master = spi_alloc_master(dev, sizeof *c);
+	if (!master)
+		return -ENODEV;
+
+	c = class_get_devdata(&master->cdev);
+
+The driver will initialize the fields of that spi_master, including the
+bus number (maybe the same as the platform device ID) and three methods
+used to interact with the SPI core and SPI protocol drivers.  It will
+also initialize its own internal state.
+
+    master->setup(struct spi_device *spi)
+	This sets up the device clock rate, SPI mode, and word sizes.
+	Drivers may change the defaults provided by board_info, and then
+	call spi_setup(spi) to invoke this routine.  It may sleep.
+
+    master->transfer(struct spi_device *spi, struct spi_message *message)
+    	This must not sleep.  Its responsibility is arrange that the
+	transfer happens and its complete() callback is issued; the two
+	will normally happen later, after other transfers complete.
+
+    master->cleanup(struct spi_device *spi)
+	Your controller driver may use spi_device.controller_state to hold
+	state it dynamically associates with that device.  If you do that,
+	be sure to provide the cleanup() method to free that state.
+
+The bulk of the driver will be managing the I/O queue fed by transfer().
+
+That queue could be purely conceptual.  For example, a driver used only
+for low-frequency sensor acess might be fine using synchronous PIO.
+
+But the queue will probably be very real, using message->queue, PIO,
+often DMA (especially if the root filesystem is in SPI flash), and
+execution contexts like IRQ handlers, tasklets, or workqueues (such
+as keventd).  Your driver can be as fancy, or as simple, as you need.
+
+
+THANKS TO
+---------
+Contributors to Linux-SPI discussions include (in alphabetical order,
+by last name):
+
+David Brownell
+Russell King
+Dmitry Pervushin
+Stephen Street
+Mark Underwood
+Andrew Victor
+Vitaly Wool
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 0db72a3..513f3b6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1300,6 +1300,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
+P:      Sylvain Meyer
+M:      sylvain.meyer@worldonline.fr
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
+
 INTEL 810/815 FRAMEBUFFER DRIVER
 P:      Antonino Daplas
 M:      adaplas@pol.net
@@ -1889,11 +1895,11 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git
 S:	Maintained
 
-NVIDIA (RIVA) FRAMEBUFFER DRIVER
-P:	Ani Joshi
-M:	ajoshi@shell.unixbox.com
-L:	linux-nvidia@lists.surfsouth.com
-S:	Maintained
+NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
+P:      Antonino Daplas
+M:      adaplas@pol.net
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
 
 ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 P:	Mark Fasheh
@@ -2188,6 +2194,12 @@
 W:	www.rtlinux.org
 S:	Maintained
 
+S3 SAVAGE FRAMEBUFFER DRIVER
+P:      Antonino Daplas
+M:      adaplas@pol.net
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
+
 S390
 P:	Martin Schwidefsky
 M:	schwidefsky@de.ibm.com
@@ -2519,6 +2531,19 @@
 M:     roms@lpg.ticalc.org
 S:     Maintained
 
+TIPC NETWORK LAYER
+P:	Per Liden
+M:	per.liden@nospam.ericsson.com
+P:	Jon Maloy
+M:	jon.maloy@nospam.ericsson.com
+P:	Allan Stephens
+M:	allan.stephens@nospam.windriver.com
+L:	tipc-discussion@lists.sourceforge.net
+W:	http://tipc.sourceforge.net/
+W:	http://tipc.cslab.ericsson.net/
+T:	git tipc.cslab.ericsson.net:/pub/git/tipc.git
+S:	Maintained
+
 TLAN NETWORK DRIVER
 P:	Samuel Chessman
 M:	chessman@tux.org
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 50b9afa..5959e36 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -180,6 +180,7 @@
 config ARCH_VERSATILE
 	bool "Versatile"
 	select ARM_AMBA
+	select ARM_VIC
 	select ICST307
 	help
 	  This enables support for ARM Ltd Versatile board.
@@ -400,6 +401,38 @@
 	  Currently at least OMAP, PXA2xx and SA11x0 platforms are known
 	  to have accurate timekeeping with dynamic tick.
 
+config AEABI
+	bool "Use the ARM EABI to compile the kernel"
+	help
+	  This option allows for the kernel to be compiled using the latest
+	  ARM ABI (aka EABI).  This is only useful if you are using a user
+	  space environment that is also compiled with EABI.
+
+	  Since there are major incompatibilities between the legacy ABI and
+	  EABI, especially with regard to structure member alignment, this
+	  option also changes the kernel syscall calling convention to
+	  disambiguate both ABIs and allow for backward compatibility support
+	  (selected with CONFIG_OABI_COMPAT).
+
+	  To use this you need GCC version 4.0.0 or later.
+
+config OABI_COMPAT
+	bool "Allow old ABI binaries to run with this kernel"
+	depends on AEABI
+	default y
+	help
+	  This option preserves the old syscall interface along with the
+	  new (ARM EABI) one. It also provides a compatibility layer to
+	  intercept syscalls that have structure arguments which layout
+	  in memory differs between the legacy ABI and the new ARM EABI
+	  (only for non "thumb" binaries). This option adds a tiny
+	  overhead to all syscalls and produces a slightly larger kernel.
+	  If you know you'll be using only pure EABI user space then you
+	  can say N here. If this option is not selected and you attempt
+	  to execute a legacy ABI binary then the result will be
+	  UNPREDICTABLE (in fact it can be predicted that it won't work
+	  at all). If in doubt say Y.
+
 config ARCH_DISCONTIGMEM_ENABLE
 	bool
 	default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
@@ -586,6 +619,7 @@
 
 config FPE_NWFPE
 	bool "NWFPE math emulation"
+	depends on !AEABI || OABI_COMPAT
 	---help---
 	  Say Y to include the NWFPE floating point emulator in the kernel.
 	  This is necessary to run most binaries. Linux does not currently
@@ -609,7 +643,7 @@
 
 config FPE_FASTFPE
 	bool "FastFPE math emulation (EXPERIMENTAL)"
-	depends on !CPU_32v3 && EXPERIMENTAL
+	depends on (!AEABI || OABI_COMPAT) && !CPU_32v3 && EXPERIMENTAL
 	---help---
 	  Say Y here to include the FAST floating point emulator in the kernel.
 	  This is an experimental much faster emulator which now also has full
@@ -641,6 +675,7 @@
 
 config ARTHUR
 	tristate "RISC OS personality"
+	depends on !AEABI
 	help
 	  Say Y here to include the kernel code necessary if you want to run
 	  Acorn RISC OS/Arthur binaries under Linux. This code is still very
@@ -729,6 +764,8 @@
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 source "drivers/hwmon/Kconfig"
 
 #source "drivers/l3/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 1fa2a10..fbfc14a 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -56,8 +56,13 @@
 tune-$(CONFIG_CPU_XSCALE)	:=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
 tune-$(CONFIG_CPU_V6)		:=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 
-# Need -Uarm for gcc < 3.x
+ifeq ($(CONFIG_AEABI),y)
+CFLAGS_ABI	:=-mabi=aapcs -mno-thumb-interwork
+else
 CFLAGS_ABI	:=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
+endif
+
+# Need -Uarm for gcc < 3.x
 CFLAGS		+=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
 AFLAGS		+=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float
 
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index d7509c7..5e34ca6 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,7 +1,10 @@
-config ICST525
+config ARM_GIC
 	bool
 
-config ARM_GIC
+config ARM_VIC
+	bool
+
+config ICST525
 	bool
 
 config ICST307
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index ec8d17c..c81a2ff 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -4,6 +4,7 @@
 
 obj-y				+= rtctime.o
 obj-$(CONFIG_ARM_GIC)		+= gic.o
+obj-$(CONFIG_ARM_VIC)		+= vic.o
 obj-$(CONFIG_ICST525)		+= icst525.o
 obj-$(CONFIG_ICST307)		+= icst307.o
 obj-$(CONFIG_SA1111)		+= sa1111.o
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 1b7eaab..159ad7e 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -1103,14 +1103,14 @@
 struct bus_type locomo_bus_type = {
 	.name		= "locomo-bus",
 	.match		= locomo_match,
+	.probe		= locomo_bus_probe,
+	.remove		= locomo_bus_remove,
 	.suspend	= locomo_bus_suspend,
 	.resume		= locomo_bus_resume,
 };
 
 int locomo_driver_register(struct locomo_driver *driver)
 {
-	driver->drv.probe = locomo_bus_probe;
-	driver->drv.remove = locomo_bus_remove;
 	driver->drv.bus = &locomo_bus_type;
 	return driver_register(&driver->drv);
 }
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index d0d6e6d..1475089 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -1247,14 +1247,14 @@
 struct bus_type sa1111_bus_type = {
 	.name		= "sa1111-rab",
 	.match		= sa1111_match,
+	.probe		= sa1111_bus_probe,
+	.remove		= sa1111_bus_remove,
 	.suspend	= sa1111_bus_suspend,
 	.resume		= sa1111_bus_resume,
 };
 
 int sa1111_driver_register(struct sa1111_driver *driver)
 {
-	driver->drv.probe = sa1111_bus_probe;
-	driver->drv.remove = sa1111_bus_remove;
 	driver->drv.bus = &sa1111_bus_type;
 	return driver_register(&driver->drv);
 }
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
new file mode 100644
index 0000000..a45ed16
--- /dev/null
+++ b/arch/arm/common/vic.c
@@ -0,0 +1,92 @@
+/*
+ *  linux/arch/arm/common/vic.c
+ *
+ *  Copyright (C) 1999 - 2003 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/vic.h>
+
+static void __iomem *vic_base;
+
+static void vic_mask_irq(unsigned int irq)
+{
+	irq -= IRQ_VIC_START;
+	writel(1 << irq, vic_base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void vic_unmask_irq(unsigned int irq)
+{
+	irq -= IRQ_VIC_START;
+	writel(1 << irq, vic_base + VIC_INT_ENABLE);
+}
+
+static struct irqchip vic_chip = {
+	.ack	= vic_mask_irq,
+	.mask	= vic_mask_irq,
+	.unmask	= vic_unmask_irq,
+};
+
+void __init vic_init(void __iomem *base, u32 vic_sources)
+{
+	unsigned int i;
+
+	vic_base = base;
+
+	/* Disable all interrupts initially. */
+
+	writel(0, vic_base + VIC_INT_SELECT);
+	writel(0, vic_base + VIC_INT_ENABLE);
+	writel(~0, vic_base + VIC_INT_ENABLE_CLEAR);
+	writel(0, vic_base + VIC_IRQ_STATUS);
+	writel(0, vic_base + VIC_ITCR);
+	writel(~0, vic_base + VIC_INT_SOFT_CLEAR);
+
+	/*
+	 * Make sure we clear all existing interrupts
+	 */
+	writel(0, vic_base + VIC_VECT_ADDR);
+	for (i = 0; i < 19; i++) {
+		unsigned int value;
+
+		value = readl(vic_base + VIC_VECT_ADDR);
+		writel(value, vic_base + VIC_VECT_ADDR);
+	}
+
+	for (i = 0; i < 16; i++) {
+		void __iomem *reg = vic_base + VIC_VECT_CNTL0 + (i * 4);
+		writel(VIC_VECT_CNTL_ENABLE | i, reg);
+	}
+
+	writel(32, vic_base + VIC_DEF_VECT_ADDR);
+
+	for (i = 0; i < 32; i++) {
+		unsigned int irq = IRQ_VIC_START + i;
+
+		set_irq_chip(irq, &vic_chip);
+
+		if (vic_sources & (1 << i)) {
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+	}
+}
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index de94b0f..2ce0e3a 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o
 obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 9997098..1574941 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -35,6 +35,16 @@
 extern void __umodsi3(void);
 extern void __do_div64(void);
 
+extern void __aeabi_idiv(void);
+extern void __aeabi_idivmod(void);
+extern void __aeabi_lasr(void);
+extern void __aeabi_llsl(void);
+extern void __aeabi_llsr(void);
+extern void __aeabi_lmul(void);
+extern void __aeabi_uidiv(void);
+extern void __aeabi_uidivmod(void);
+extern void __aeabi_ulcmp(void);
+
 extern void fpundefinstr(void);
 extern void fp_enter(void);
 
@@ -141,6 +151,18 @@
 EXPORT_SYMBOL(__umodsi3);
 EXPORT_SYMBOL(__do_div64);
 
+#ifdef CONFIG_AEABI
+EXPORT_SYMBOL(__aeabi_idiv);
+EXPORT_SYMBOL(__aeabi_idivmod);
+EXPORT_SYMBOL(__aeabi_lasr);
+EXPORT_SYMBOL(__aeabi_llsl);
+EXPORT_SYMBOL(__aeabi_llsr);
+EXPORT_SYMBOL(__aeabi_lmul);
+EXPORT_SYMBOL(__aeabi_uidiv);
+EXPORT_SYMBOL(__aeabi_uidivmod);
+EXPORT_SYMBOL(__aeabi_ulcmp);
+#endif
+
 	/* bitops */
 EXPORT_SYMBOL(_set_bit_le);
 EXPORT_SYMBOL(_test_and_set_bit_le);
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 55076a7..75e6f9a 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -13,7 +13,7 @@
 #define NR_syscalls 328
 #else
 
-__syscall_start:
+100:
 /* 0 */		.long	sys_restart_syscall
 		.long	sys_exit
 		.long	sys_fork_wrapper
@@ -27,7 +27,7 @@
 /* 10 */	.long	sys_unlink
 		.long	sys_execve_wrapper
 		.long	sys_chdir
-		.long	sys_time		/* used by libc4 */
+		.long	OBSOLETE(sys_time)	/* used by libc4 */
 		.long	sys_mknod
 /* 15 */	.long	sys_chmod
 		.long	sys_lchown16
@@ -36,15 +36,15 @@
 		.long	sys_lseek
 /* 20 */	.long	sys_getpid
 		.long	sys_mount
-		.long	sys_oldumount		/* used by libc4 */
+		.long	OBSOLETE(sys_oldumount)	/* used by libc4 */
 		.long	sys_setuid16
 		.long	sys_getuid16
-/* 25 */	.long	sys_stime
+/* 25 */	.long	OBSOLETE(sys_stime)
 		.long	sys_ptrace
-		.long	sys_alarm		/* used by libc4 */
+		.long	OBSOLETE(sys_alarm)	/* used by libc4 */
 		.long	sys_ni_syscall		/* was sys_fstat */
 		.long	sys_pause
-/* 30 */	.long	sys_utime		/* used by libc4 */
+/* 30 */	.long	OBSOLETE(sys_utime)	/* used by libc4 */
 		.long	sys_ni_syscall		/* was sys_stty */
 		.long	sys_ni_syscall		/* was sys_getty */
 		.long	sys_access
@@ -90,21 +90,21 @@
 		.long	sys_sigpending
 		.long	sys_sethostname
 /* 75 */	.long	sys_setrlimit
-		.long	sys_old_getrlimit	/* used by libc4 */
+		.long	OBSOLETE(sys_old_getrlimit) /* used by libc4 */
 		.long	sys_getrusage
 		.long	sys_gettimeofday
 		.long	sys_settimeofday
 /* 80 */	.long	sys_getgroups16
 		.long	sys_setgroups16
-		.long	old_select		/* used by libc4 */
+		.long	OBSOLETE(old_select)	/* used by libc4 */
 		.long	sys_symlink
 		.long	sys_ni_syscall		/* was sys_lstat */
 /* 85 */	.long	sys_readlink
 		.long	sys_uselib
 		.long	sys_swapon
 		.long	sys_reboot
-		.long	old_readdir		/* used by libc4 */
-/* 90 */	.long	old_mmap		/* used by libc4 */
+		.long	OBSOLETE(old_readdir)	/* used by libc4 */
+/* 90 */	.long	OBSOLETE(old_mmap)	/* used by libc4 */
 		.long	sys_munmap
 		.long	sys_truncate
 		.long	sys_ftruncate
@@ -116,7 +116,7 @@
 		.long	sys_statfs
 /* 100 */	.long	sys_fstatfs
 		.long	sys_ni_syscall
-		.long	sys_socketcall
+		.long	OBSOLETE(sys_socketcall)
 		.long	sys_syslog
 		.long	sys_setitimer
 /* 105 */	.long	sys_getitimer
@@ -127,11 +127,11 @@
 /* 110 */	.long	sys_ni_syscall		/* was sys_iopl */
 		.long	sys_vhangup
 		.long	sys_ni_syscall
-		.long	sys_syscall		/* call a syscall */
+		.long	OBSOLETE(sys_syscall)	/* call a syscall */
 		.long	sys_wait4
 /* 115 */	.long	sys_swapoff
 		.long	sys_sysinfo
-		.long	sys_ipc
+		.long	OBSOLETE(ABI(sys_ipc, sys_oabi_ipc))
 		.long	sys_fsync
 		.long	sys_sigreturn_wrapper
 /* 120 */	.long	sys_clone_wrapper
@@ -194,8 +194,8 @@
 		.long	sys_rt_sigtimedwait
 		.long	sys_rt_sigqueueinfo
 		.long	sys_rt_sigsuspend_wrapper
-/* 180 */	.long	sys_pread64
-		.long	sys_pwrite64
+/* 180 */	.long	ABI(sys_pread64, sys_oabi_pread64)
+		.long	ABI(sys_pwrite64, sys_oabi_pwrite64)
 		.long	sys_chown16
 		.long	sys_getcwd
 		.long	sys_capget
@@ -207,11 +207,11 @@
 /* 190 */	.long	sys_vfork_wrapper
 		.long	sys_getrlimit
 		.long	sys_mmap2
-		.long	sys_truncate64
-		.long	sys_ftruncate64
-/* 195 */	.long	sys_stat64
-		.long	sys_lstat64
-		.long	sys_fstat64
+		.long	ABI(sys_truncate64, sys_oabi_truncate64)
+		.long	ABI(sys_ftruncate64, sys_oabi_ftruncate64)
+/* 195 */	.long	ABI(sys_stat64, sys_oabi_stat64)
+		.long	ABI(sys_lstat64, sys_oabi_lstat64)
+		.long	ABI(sys_fstat64, sys_oabi_fstat64)
 		.long	sys_lchown
 		.long	sys_getuid
 /* 200 */	.long	sys_getgid
@@ -235,11 +235,11 @@
 		.long	sys_pivot_root
 		.long	sys_mincore
 /* 220 */	.long	sys_madvise
-		.long	sys_fcntl64
+		.long	ABI(sys_fcntl64, sys_oabi_fcntl64)
 		.long	sys_ni_syscall /* TUX */
 		.long	sys_ni_syscall
 		.long	sys_gettid
-/* 225 */	.long	sys_readahead
+/* 225 */	.long	ABI(sys_readahead, sys_oabi_readahead)
 		.long	sys_setxattr
 		.long	sys_lsetxattr
 		.long	sys_fsetxattr
@@ -265,8 +265,8 @@
 		.long	sys_exit_group
 		.long	sys_lookup_dcookie
 /* 250 */	.long	sys_epoll_create
-		.long	sys_epoll_ctl
-		.long	sys_epoll_wait
+		.long	ABI(sys_epoll_ctl, sys_oabi_epoll_ctl)
+		.long	ABI(sys_epoll_wait, sys_oabi_epoll_wait)
 	 	.long	sys_remap_file_pages
 		.long	sys_ni_syscall	/* sys_set_thread_area */
 /* 255 */	.long	sys_ni_syscall	/* sys_get_thread_area */
@@ -280,8 +280,8 @@
 		.long	sys_clock_gettime
 		.long	sys_clock_getres
 /* 265 */	.long	sys_clock_nanosleep
-		.long	sys_statfs64
-		.long	sys_fstatfs64
+		.long	sys_statfs64_wrapper
+		.long	sys_fstatfs64_wrapper
 		.long	sys_tgkill
 		.long	sys_utimes
 /* 270 */	.long	sys_arm_fadvise64_64
@@ -312,7 +312,7 @@
 /* 295 */	.long	sys_getsockopt
 		.long	sys_sendmsg
 		.long	sys_recvmsg
-		.long	sys_semop
+		.long	ABI(sys_semop, sys_oabi_semop)
 		.long	sys_semget
 /* 300 */	.long	sys_semctl
 		.long	sys_msgsnd
@@ -326,7 +326,7 @@
 		.long	sys_add_key
 /* 310 */	.long	sys_request_key
 		.long	sys_keyctl
-		.long	sys_semtimedop
+		.long	ABI(sys_semtimedop, sys_oabi_semtimedop)
 /* vserver */	.long	sys_ni_syscall
 		.long	sys_ioprio_set
 /* 315 */	.long	sys_ioprio_get
@@ -336,9 +336,8 @@
 		.long	sys_mbind
 /* 320 */	.long	sys_get_mempolicy
 		.long	sys_set_mempolicy
-__syscall_end:
 
-		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
+		.rept	NR_syscalls - (. - 100b) / 4
 			.long	sys_ni_syscall
 		.endr
 #endif
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 96fd919..74ea29c 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -1147,9 +1147,11 @@
 	struct ecard_driver *drv = ECARD_DRV(dev->driver);
 	struct ecard_request req;
 
-	if (drv->shutdown)
-		drv->shutdown(ec);
-	ecard_release(ec);
+	if (dev->driver) {
+		if (drv->shutdown)
+			drv->shutdown(ec);
+		ecard_release(ec);
+	}
 
 	/*
 	 * If this card has a loader, call the reset handler.
@@ -1164,9 +1166,6 @@
 int ecard_register_driver(struct ecard_driver *drv)
 {
 	drv->drv.bus = &ecard_bus_type;
-	drv->drv.probe = ecard_drv_probe;
-	drv->drv.remove = ecard_drv_remove;
-	drv->drv.shutdown = ecard_drv_shutdown;
 
 	return driver_register(&drv->drv);
 }
@@ -1195,6 +1194,9 @@
 	.name		= "ecard",
 	.dev_attrs	= ecard_dev_attrs,
 	.match		= ecard_match,
+	.probe		= ecard_drv_probe,
+	.remove		= ecard_drv_remove,
+	.shutdown	= ecard_drv_shutdown,
 };
 
 static int ecard_bus_init(void)
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a52baed..874e6bb 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1996,1997,1998 Russell King.
  *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
+ *  nommu support by Hyok S. Choi (hyok.choi@samsung.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
@@ -104,14 +105,24 @@
 /*
  * SVC mode handlers
  */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
 	.macro	svc_entry
 	sub	sp, sp, #S_FRAME_SIZE
+ SPFIX(	tst	sp, #4		)
+ SPFIX(	bicne	sp, sp, #4	)
 	stmib	sp, {r1 - r12}
 
 	ldmia	r0, {r1 - r3}
 	add	r5, sp, #S_SP		@ here for interlock avoidance
 	mov	r4, #-1			@  ""  ""      ""       ""
 	add	r0, sp, #S_FRAME_SIZE   @  ""  ""      ""       ""
+ SPFIX(	addne	r0, r0, #4	)
 	str	r1, [sp]		@ save the "real" r0 copied
 					@ from the exception stack
 
@@ -302,7 +313,14 @@
 
 /*
  * User mode handlers
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
 	.macro	usr_entry
 	sub	sp, sp, #S_FRAME_SIZE
 	stmib	sp, {r1 - r12}
@@ -538,7 +556,11 @@
 	add	ip, r1, #TI_CPU_SAVE
 	ldr	r3, [r2, #TI_TP_VALUE]
 	stmia	ip!, {r4 - sl, fp, sp, lr}	@ Store most regs on stack
+#ifndef CONFIG_MMU
+	add	r2, r2, #TI_CPU_DOMAIN
+#else
 	ldr	r6, [r2, #TI_CPU_DOMAIN]!
+#endif
 #if __LINUX_ARM_ARCH__ >= 6
 #ifdef CONFIG_CPU_MPCORE
 	clrex
@@ -556,7 +578,9 @@
 	mov	r4, #0xffff0fff
 	str	r3, [r4, #-15]			@ TLS val at 0xffff0ff0
 #endif
+#ifdef CONFIG_MMU
 	mcr	p15, 0, r6, c3, c0, 0		@ Set domain register
+#endif
 #ifdef CONFIG_VFP
 	@ Always disable VFP so we can lazily save/restore the old
 	@ state. This occurs in the context of the previous thread.
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e2b4299..2b92ce8 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -98,20 +98,14 @@
 	   run on an ARM7 and we can save a couple of instructions.  
 								--pb */
 #ifdef CONFIG_CPU_ARM710
-	.macro	arm710_bug_check, instr, temp
-	and	\temp, \instr, #0x0f000000	@ check for SWI
-	teq	\temp, #0x0f000000
-	bne	.Larm700bug
-	.endm
-
-.Larm700bug:
+#define A710(code...) code
+.Larm710bug:
 	ldmia	sp, {r0 - lr}^			@ Get calling r0 - lr
 	mov	r0, r0
 	add	sp, sp, #S_FRAME_SIZE
 	subs	pc, lr, #4
 #else
-	.macro	arm710_bug_check, instr, temp
-	.endm
+#define A710(code...)
 #endif
 
 	.align	5
@@ -129,14 +123,50 @@
 	/*
 	 * Get the system call number.
 	 */
+
+#if defined(CONFIG_OABI_COMPAT)
+
+	/*
+	 * If we have CONFIG_OABI_COMPAT then we need to look at the swi
+	 * value to determine if it is an EABI or an old ABI call.
+	 */
 #ifdef CONFIG_ARM_THUMB
+	tst	r8, #PSR_T_BIT
+	movne	r10, #0				@ no thumb OABI emulation
+	ldreq	r10, [lr, #-4]			@ get SWI instruction
+#else
+	ldr	r10, [lr, #-4]			@ get SWI instruction
+  A710(	and	ip, r10, #0x0f000000		@ check for SWI		)
+  A710(	teq	ip, #0x0f000000						)
+  A710(	bne	.Larm710bug						)
+#endif
+
+#elif defined(CONFIG_AEABI)
+
+	/*
+	 * Pure EABI user space always put syscall number into scno (r7).
+	 */
+  A710(	ldr	ip, [lr, #-4]			@ get SWI instruction	)
+  A710(	and	ip, ip, #0x0f000000		@ check for SWI		)
+  A710(	teq	ip, #0x0f000000						)
+  A710(	bne	.Larm710bug						)
+
+#elif defined(CONFIG_ARM_THUMB)
+
+	/* Legacy ABI only, possibly thumb mode. */
 	tst	r8, #PSR_T_BIT			@ this is SPSR from save_user_regs
 	addne	scno, r7, #__NR_SYSCALL_BASE	@ put OS number in
 	ldreq	scno, [lr, #-4]
+
 #else
+
+	/* Legacy ABI only. */
 	ldr	scno, [lr, #-4]			@ get SWI instruction
+  A710(	and	ip, scno, #0x0f000000		@ check for SWI		)
+  A710(	teq	ip, #0x0f000000						)
+  A710(	bne	.Larm710bug						)
+
 #endif
-	arm710_bug_check scno, ip
 
 #ifdef CONFIG_ALIGNMENT_TRAP
 	ldr	ip, __cr_alignment
@@ -145,18 +175,31 @@
 #endif
 	enable_irq
 
-	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
-
 	get_thread_info tsk
+	adr	tbl, sys_call_table		@ load syscall table pointer
 	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
+
+#if defined(CONFIG_OABI_COMPAT)
+	/*
+	 * If the swi argument is zero, this is an EABI call and we do nothing.
+	 *
+	 * If this is an old ABI call, get the syscall number into scno and
+	 * get the old ABI syscall table address.
+	 */
+	bics	r10, r10, #0xff000000
+	eorne	scno, r10, #__NR_OABI_SYSCALL_BASE
+	ldrne	tbl, =sys_oabi_call_table
+#elif !defined(CONFIG_AEABI)
 	bic	scno, scno, #0xff000000		@ mask off SWI op-code
 	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
-	adr	tbl, sys_call_table		@ load syscall table pointer
+#endif
+
+	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
 	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
 
-	adr	lr, ret_fast_syscall		@ return address
 	cmp	scno, #NR_syscalls		@ check upper syscall limit
+	adr	lr, ret_fast_syscall		@ return address
 	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
 
 	add	r1, sp, #S_OFF
@@ -171,11 +214,13 @@
 	 * context switches, and waiting for our parent to respond.
 	 */
 __sys_trace:
+	mov	r2, scno
 	add	r1, sp, #S_OFF
 	mov	r0, #0				@ trace entry [IP = 0]
 	bl	syscall_trace
 
 	adr	lr, __sys_trace_return		@ return address
+	mov	scno, r0			@ syscall number (possibly new)
 	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
 	cmp	scno, #NR_syscalls		@ check upper syscall limit
 	ldmccia	r1, {r0 - r3}			@ have to reload r0 - r3
@@ -184,6 +229,7 @@
 
 __sys_trace_return:
 	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
+	mov	r2, scno
 	mov	r1, sp
 	mov	r0, #1				@ trace exit [IP = 1]
 	bl	syscall_trace
@@ -195,10 +241,24 @@
 __cr_alignment:
 	.word	cr_alignment
 #endif
+	.ltorg
+
+/*
+ * This is the syscall table declaration for native ABI syscalls.
+ * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall.
+ */
+#define ABI(native, compat) native
+#ifdef CONFIG_AEABI
+#define OBSOLETE(syscall) sys_ni_syscall
+#else
+#define OBSOLETE(syscall) syscall
+#endif
 
 	.type	sys_call_table, #object
 ENTRY(sys_call_table)
 #include "calls.S"
+#undef ABI
+#undef OBSOLETE
 
 /*============================================================================
  * Special system call wrappers
@@ -207,7 +267,7 @@
 @ r8 = syscall table
 		.type	sys_syscall, #function
 sys_syscall:
-		eor	scno, r0, #__NR_SYSCALL_BASE
+		eor	scno, r0, #__NR_OABI_SYSCALL_BASE
 		cmp	scno, #__NR_syscall - __NR_SYSCALL_BASE
 		cmpne	scno, #NR_syscalls	@ check range
 		stmloia	sp, {r5, r6}		@ shuffle args
@@ -255,6 +315,16 @@
 		ldr	r2, [sp, #S_OFF + S_SP]
 		b	do_sigaltstack
 
+sys_statfs64_wrapper:
+		teq	r1, #88
+		moveq	r1, #84
+		b	sys_statfs64
+
+sys_fstatfs64_wrapper:
+		teq	r1, #88
+		moveq	r1, #84
+		b	sys_fstatfs64
+
 /*
  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
  * offset, we return EINVAL.
@@ -271,3 +341,49 @@
 		str	r5, [sp, #4]
 		b	do_mmap2
 #endif
+
+#ifdef CONFIG_OABI_COMPAT
+
+/*
+ * These are syscalls with argument register differences
+ */
+
+sys_oabi_pread64:
+		stmia	sp, {r3, r4}
+		b	sys_pread64
+
+sys_oabi_pwrite64:
+		stmia	sp, {r3, r4}
+		b	sys_pwrite64
+
+sys_oabi_truncate64:
+		mov	r3, r2
+		mov	r2, r1
+		b	sys_truncate64
+
+sys_oabi_ftruncate64:
+		mov	r3, r2
+		mov	r2, r1
+		b	sys_ftruncate64
+
+sys_oabi_readahead:
+		str	r3, [sp]
+		mov	r3, r2
+		mov	r2, r1
+		b	sys_readahead
+
+/*
+ * Let's declare a second syscall table for old ABI binaries
+ * using the compatibility syscall entries.
+ */
+#define ABI(native, compat) compat
+#define OBSOLETE(syscall) syscall
+
+	.type	sys_oabi_call_table, #object
+ENTRY(sys_oabi_call_table)
+#include "calls.S"
+#undef ABI
+#undef OBSOLETE
+
+#endif
+
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index 648cfff..55c99cd 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -19,6 +19,7 @@
 @
 @ Most of the stack format comes from struct pt_regs, but with
 @ the addition of 8 bytes for storing syscall args 5 and 6.
+@ This _must_ remain a multiple of 8 for EABI.
 @
 #define S_OFF		8
 
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 1e985f2..1aca1775 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -251,12 +251,11 @@
  * r10 = procinfo
  *
  * Returns:
- *  r0, r3, r5, r6, r7 corrupted
+ *  r0, r3, r6, r7 corrupted
  *  r4 = physical page table address
  */
 	.type	__create_page_tables, %function
 __create_page_tables:
-	ldr	r5, [r8, #MACHINFO_PHYSRAM]	@ physram
 	pgtbl	r4				@ page table address
 
 	/*
@@ -303,7 +302,7 @@
 	 * Then map first 1MB of ram in case it contains our boot params.
 	 */
 	add	r0, r4, #PAGE_OFFSET >> 18
-	orr	r6, r5, r7
+	orr	r6, r7, #PHYS_OFFSET
 	str	r6, [r0]
 
 #ifdef CONFIG_XIP_KERNEL
@@ -311,7 +310,7 @@
 	 * Map some ram to cover our .data and .bss areas.
 	 * Mapping 3MB should be plenty.
 	 */
-	sub	r3, r4, r5
+	sub	r3, r4, #PHYS_OFFSET
 	mov	r3, r3, lsr #20
 	add	r0, r0, r3, lsl #2
 	add	r6, r6, r3, lsl #20
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index e591f72b..7b6256b 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -766,6 +766,11 @@
 				       (unsigned long __user *) data);
 			break;
 
+		case PTRACE_SET_SYSCALL:
+			ret = 0;
+			child->ptrace_message = data;
+			break;
+
 		default:
 			ret = ptrace_request(child, request, addr, data);
 			break;
@@ -774,14 +779,14 @@
 	return ret;
 }
 
-asmlinkage void syscall_trace(int why, struct pt_regs *regs)
+asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 {
 	unsigned long ip;
 
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+		return scno;
 	if (!(current->ptrace & PT_PTRACED))
-		return;
+		return scno;
 
 	/*
 	 * Save IP.  IP is used to denote syscall entry/exit:
@@ -790,6 +795,8 @@
 	ip = regs->ARM_ip;
 	regs->ARM_ip = why;
 
+	current->ptrace_message = scno;
+
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
@@ -804,4 +811,6 @@
 		current->exit_code = 0;
 	}
 	regs->ARM_ip = ip;
+
+	return current->ptrace_message;
 }
diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c
index 4c31f29..981fe5c 100644
--- a/arch/arm/kernel/semaphore.c
+++ b/arch/arm/kernel/semaphore.c
@@ -177,41 +177,42 @@
  * ip contains the semaphore pointer on entry. Save the C-clobbered
  * registers (r0 to r3 and lr), but not ip, as we use it as a return
  * value in some cases..
+ * To remain AAPCS compliant (64-bit stack align) we save r4 as well.
  */
 asm("	.section .sched.text,\"ax\",%progbits	\n\
 	.align	5				\n\
 	.globl	__down_failed			\n\
 __down_failed:					\n\
-	stmfd	sp!, {r0 - r3, lr}		\n\
+	stmfd	sp!, {r0 - r4, lr}		\n\
 	mov	r0, ip				\n\
 	bl	__down				\n\
-	ldmfd	sp!, {r0 - r3, pc}		\n\
+	ldmfd	sp!, {r0 - r4, pc}		\n\
 						\n\
 	.align	5				\n\
 	.globl	__down_interruptible_failed	\n\
 __down_interruptible_failed:			\n\
-	stmfd	sp!, {r0 - r3, lr}		\n\
+	stmfd	sp!, {r0 - r4, lr}		\n\
 	mov	r0, ip				\n\
 	bl	__down_interruptible		\n\
 	mov	ip, r0				\n\
-	ldmfd	sp!, {r0 - r3, pc}		\n\
+	ldmfd	sp!, {r0 - r4, pc}		\n\
 						\n\
 	.align	5				\n\
 	.globl	__down_trylock_failed		\n\
 __down_trylock_failed:				\n\
-	stmfd	sp!, {r0 - r3, lr}		\n\
+	stmfd	sp!, {r0 - r4, lr}		\n\
 	mov	r0, ip				\n\
 	bl	__down_trylock			\n\
 	mov	ip, r0				\n\
-	ldmfd	sp!, {r0 - r3, pc}		\n\
+	ldmfd	sp!, {r0 - r4, pc}		\n\
 						\n\
 	.align	5				\n\
 	.globl	__up_wakeup			\n\
 __up_wakeup:					\n\
-	stmfd	sp!, {r0 - r3, lr}		\n\
+	stmfd	sp!, {r0 - r4, lr}		\n\
 	mov	r0, ip				\n\
 	bl	__up				\n\
-	ldmfd	sp!, {r0 - r3, pc}		\n\
+	ldmfd	sp!, {r0 - r4, pc}		\n\
 	");
 
 EXPORT_SYMBOL(__down_failed);
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index ea569ba..a491de2 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -147,6 +147,7 @@
 	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -226,6 +227,7 @@
 		return -ENOSYS;
 	}
 }
+#endif
 
 /* Fork a new task - this creates a new program thread.
  * This is called indirectly via a small wrapper
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
new file mode 100644
index 0000000..eafa8e5
--- /dev/null
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -0,0 +1,339 @@
+/*
+ *  arch/arm/kernel/sys_oabi-compat.c
+ *
+ *  Compatibility wrappers for syscalls that are used from
+ *  old ABI user space binaries with an EABI kernel.
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Oct 7, 2005
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+/*
+ * The legacy ABI and the new ARM EABI have different rules making some
+ * syscalls incompatible especially with structure arguments.
+ * Most notably, Eabi says 64-bit members should be 64-bit aligned instead of
+ * simply word aligned.  EABI also pads structures to the size of the largest
+ * member it contains instead of the invariant 32-bit.
+ *
+ * The following syscalls are affected:
+ *
+ * sys_stat64:
+ * sys_lstat64:
+ * sys_fstat64:
+ *
+ *   struct stat64 has different sizes and some members are shifted
+ *   Compatibility wrappers are needed for them and provided below.
+ *
+ * sys_fcntl64:
+ *
+ *   struct flock64 has different sizes and some members are shifted
+ *   A compatibility wrapper is needed and provided below.
+ *
+ * sys_statfs64:
+ * sys_fstatfs64:
+ *
+ *   struct statfs64 has extra padding with EABI growing its size from
+ *   84 to 88.  This struct is now __attribute__((packed,aligned(4)))
+ *   with a small assembly wrapper to force the sz argument to 84 if it is 88
+ *   to avoid copying the extra padding over user space unexpecting it.
+ *
+ * sys_newuname:
+ *
+ *   struct new_utsname has no padding with EABI.  No problem there.
+ *
+ * sys_epoll_ctl:
+ * sys_epoll_wait:
+ *
+ *   struct epoll_event has its second member shifted also affecting the
+ *   structure size. Compatibility wrappers are needed and provided below.
+ *
+ * sys_ipc:
+ * sys_semop:
+ * sys_semtimedop:
+ *
+ *   struct sembuf loses its padding with EABI.  Since arrays of them are
+ *   used they have to be copyed to remove the padding. Compatibility wrappers
+ *   provided below.
+ */
+
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/eventpoll.h>
+#include <linux/sem.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+
+struct oldabi_stat64 {
+	unsigned long long st_dev;
+	unsigned int	__pad1;
+	unsigned long	__st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	unsigned long long st_rdev;
+	unsigned int	__pad2;
+
+	long long	st_size;
+	unsigned long	st_blksize;
+	unsigned long long st_blocks;
+
+	unsigned long	st_atime;
+	unsigned long	st_atime_nsec;
+
+	unsigned long	st_mtime;
+	unsigned long	st_mtime_nsec;
+
+	unsigned long	st_ctime;
+	unsigned long	st_ctime_nsec;
+
+	unsigned long long st_ino;
+} __attribute__ ((packed,aligned(4)));
+
+static long cp_oldabi_stat64(struct kstat *stat,
+			     struct oldabi_stat64 __user *statbuf)
+{
+	struct oldabi_stat64 tmp;
+
+	tmp.st_dev = huge_encode_dev(stat->dev);
+	tmp.__pad1 = 0;
+	tmp.__st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	tmp.st_uid = stat->uid;
+	tmp.st_gid = stat->gid;
+	tmp.st_rdev = huge_encode_dev(stat->rdev);
+	tmp.st_size = stat->size;
+	tmp.st_blocks = stat->blocks;
+	tmp.__pad2 = 0;
+	tmp.st_blksize = stat->blksize;
+	tmp.st_atime = stat->atime.tv_sec;
+	tmp.st_atime_nsec = stat->atime.tv_nsec;
+	tmp.st_mtime = stat->mtime.tv_sec;
+	tmp.st_mtime_nsec = stat->mtime.tv_nsec;
+	tmp.st_ctime = stat->ctime.tv_sec;
+	tmp.st_ctime_nsec = stat->ctime.tv_nsec;
+	tmp.st_ino = stat->ino;
+	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys_oabi_stat64(char __user * filename,
+				struct oldabi_stat64 __user * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
+	if (!error)
+		error = cp_oldabi_stat64(&stat, statbuf);
+	return error;
+}
+
+asmlinkage long sys_oabi_lstat64(char __user * filename,
+				 struct oldabi_stat64 __user * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
+	if (!error)
+		error = cp_oldabi_stat64(&stat, statbuf);
+	return error;
+}
+
+asmlinkage long sys_oabi_fstat64(unsigned long fd,
+				 struct oldabi_stat64 __user * statbuf)
+{
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
+	if (!error)
+		error = cp_oldabi_stat64(&stat, statbuf);
+	return error;
+}
+
+struct oabi_flock64 {
+	short	l_type;
+	short	l_whence;
+	loff_t	l_start;
+	loff_t	l_len;
+	pid_t	l_pid;
+} __attribute__ ((packed,aligned(4)));
+
+asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+				 unsigned long arg)
+{
+	struct oabi_flock64 user;
+	struct flock64 kernel;
+	mm_segment_t fs = USER_DS; /* initialized to kill a warning */
+	unsigned long local_arg = arg;
+	int ret;
+
+	switch (cmd) {
+	case F_GETLK64:
+	case F_SETLK64:
+	case F_SETLKW64:
+		if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+				   sizeof(user)))
+			return -EFAULT;
+		kernel.l_type	= user.l_type;
+		kernel.l_whence	= user.l_whence;
+		kernel.l_start	= user.l_start;
+		kernel.l_len	= user.l_len;
+		kernel.l_pid	= user.l_pid;
+		local_arg = (unsigned long)&kernel;
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+	}
+
+	ret = sys_fcntl64(fd, cmd, local_arg);
+
+	switch (cmd) {
+	case F_GETLK64:
+		if (!ret) {
+			user.l_type	= kernel.l_type;
+			user.l_whence	= kernel.l_whence;
+			user.l_start	= kernel.l_start;
+			user.l_len	= kernel.l_len;
+			user.l_pid	= kernel.l_pid;
+			if (copy_to_user((struct oabi_flock64 __user *)arg,
+					 &user, sizeof(user)))
+				ret = -EFAULT;
+		}
+	case F_SETLK64:
+	case F_SETLKW64:
+		set_fs(fs);
+	}
+
+	return ret;
+}
+
+struct oabi_epoll_event {
+	__u32 events;
+	__u64 data;
+} __attribute__ ((packed,aligned(4)));
+
+asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd,
+				   struct oabi_epoll_event __user *event)
+{
+	struct oabi_epoll_event user;
+	struct epoll_event kernel;
+	mm_segment_t fs;
+	long ret;
+
+	if (op == EPOLL_CTL_DEL)
+		return sys_epoll_ctl(epfd, op, fd, NULL);
+	if (copy_from_user(&user, event, sizeof(user)))
+		return -EFAULT;
+	kernel.events = user.events;
+	kernel.data   = user.data;
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_epoll_ctl(epfd, op, fd, &kernel);
+	set_fs(fs);
+	return ret;
+}
+
+asmlinkage long sys_oabi_epoll_wait(int epfd,
+				    struct oabi_epoll_event __user *events,
+				    int maxevents, int timeout)
+{
+	struct epoll_event *kbuf;
+	mm_segment_t fs;
+	long ret, err, i;
+
+	if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
+		return -EINVAL;
+	kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
+	set_fs(fs);
+	err = 0;
+	for (i = 0; i < ret; i++) {
+		__put_user_error(kbuf[i].events, &events->events, err);
+		__put_user_error(kbuf[i].data,   &events->data,   err);
+		events++;
+	}
+	kfree(kbuf);
+	return err ? -EFAULT : ret;
+}
+
+struct oabi_sembuf {
+	unsigned short	sem_num;
+	short		sem_op;
+	short		sem_flg;
+	unsigned short	__pad;
+};
+
+asmlinkage long sys_oabi_semtimedop(int semid,
+				    struct oabi_sembuf __user *tsops,
+				    unsigned nsops,
+				    const struct timespec __user *timeout)
+{
+	struct sembuf *sops;
+	struct timespec local_timeout;
+	long err;
+	int i;
+
+	if (nsops < 1)
+		return -EINVAL;
+	sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
+	if (!sops)
+		return -ENOMEM;
+	err = 0;
+	for (i = 0; i < nsops; i++) {
+		__get_user_error(sops[i].sem_num, &tsops->sem_num, err);
+		__get_user_error(sops[i].sem_op,  &tsops->sem_op,  err);
+		__get_user_error(sops[i].sem_flg, &tsops->sem_flg, err);
+		tsops++;
+	}
+	if (timeout) {
+		/* copy this as well before changing domain protection */
+		err |= copy_from_user(&local_timeout, timeout, sizeof(*timeout));
+		timeout = &local_timeout;
+	}
+	if (err) {
+		err = -EFAULT;
+	} else {
+		mm_segment_t fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sys_semtimedop(semid, sops, nsops, timeout);
+		set_fs(fs);
+	}
+	kfree(sops);
+	return err;
+}
+
+asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops,
+			       unsigned nsops)
+{
+	return sys_oabi_semtimedop(semid, tsops, nsops, NULL);
+}
+
+extern asmlinkage int sys_ipc(uint call, int first, int second, int third,
+			      void __user *ptr, long fifth);
+
+asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
+			    void __user *ptr, long fifth)
+{
+	switch (call & 0xffff) {
+	case SEMOP:
+		return  sys_oabi_semtimedop(first,
+					    (struct oabi_sembuf __user *)ptr,
+					    second, NULL);
+	case SEMTIMEDOP:
+		return  sys_oabi_semtimedop(first,
+					    (struct oabi_sembuf __user *)ptr,
+					    second,
+					    (const struct timespec __user *)fifth);
+	default:
+		return sys_ipc(call, first, second, third, ptr, fifth);
+	}
+}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 93cfd3f..10235b0 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -404,7 +404,7 @@
 	struct thread_info *thread = current_thread_info();
 	siginfo_t info;
 
-	if ((no >> 16) != 0x9f)
+	if ((no >> 16) != (__ARM_NR_BASE>> 16))
 		return bad_syscall(no, regs);
 
 	switch (no & 0xffff) {
diff --git a/arch/arm/lib/ashldi3.S b/arch/arm/lib/ashldi3.S
index 561e207..55e57a1 100644
--- a/arch/arm/lib/ashldi3.S
+++ b/arch/arm/lib/ashldi3.S
@@ -37,6 +37,7 @@
 #endif
 
 ENTRY(__ashldi3)
+ENTRY(__aeabi_llsl)
 
 	subs	r3, r2, #32
 	rsb	ip, r2, #32
diff --git a/arch/arm/lib/ashrdi3.S b/arch/arm/lib/ashrdi3.S
index 86fb2a9..0b31398 100644
--- a/arch/arm/lib/ashrdi3.S
+++ b/arch/arm/lib/ashrdi3.S
@@ -37,6 +37,7 @@
 #endif
 
 ENTRY(__ashrdi3)
+ENTRY(__aeabi_lasr)
 
 	subs	r3, r2, #32
 	rsb	ip, r2, #32
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index 5902602..4e492f4 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -206,6 +206,7 @@
 
 
 ENTRY(__udivsi3)
+ENTRY(__aeabi_uidiv)
 
 	subs	r2, r1, #1
 	moveq	pc, lr
@@ -246,6 +247,7 @@
 
 
 ENTRY(__divsi3)
+ENTRY(__aeabi_idiv)
 
 	cmp	r1, #0
 	eor	ip, r0, r1			@ save the sign of the result.
@@ -303,12 +305,33 @@
 	rsbmi	r0, r0, #0
 	mov	pc, lr
 
+#ifdef CONFIG_AEABI
+
+ENTRY(__aeabi_uidivmod)
+
+	stmfd	sp!, {r0, r1, ip, lr}
+	bl	__aeabi_uidiv
+	ldmfd	sp!, {r1, r2, ip, lr}
+	mul	r3, r0, r2
+	sub	r1, r1, r3
+	mov	pc, lr
+
+ENTRY(__aeabi_idivmod)
+
+	stmfd	sp!, {r0, r1, ip, lr}
+	bl	__aeabi_idiv
+	ldmfd	sp!, {r1, r2, ip, lr}
+	mul	r3, r0, r2
+	sub	r1, r1, r3
+	mov	pc, lr
+
+#endif
 
 Ldiv0:
 
-	str	lr, [sp, #-4]!
+	str	lr, [sp, #-8]!
 	bl	__div0
 	mov	r0, #0			@ About as wrong as it could be.
-	ldr	pc, [sp], #4
+	ldr	pc, [sp], #8
 
 
diff --git a/arch/arm/lib/lshrdi3.S b/arch/arm/lib/lshrdi3.S
index 46c2ed1..a86dbdd 100644
--- a/arch/arm/lib/lshrdi3.S
+++ b/arch/arm/lib/lshrdi3.S
@@ -37,6 +37,7 @@
 #endif
 
 ENTRY(__lshrdi3)
+ENTRY(__aeabi_llsr)
 
 	subs	r3, r2, #32
 	rsb	ip, r2, #32
diff --git a/arch/arm/lib/muldi3.S b/arch/arm/lib/muldi3.S
index c7fbdf0..72d5941 100644
--- a/arch/arm/lib/muldi3.S
+++ b/arch/arm/lib/muldi3.S
@@ -25,6 +25,7 @@
 #endif
 
 ENTRY(__muldi3)
+ENTRY(__aeabi_lmul)
 
 	mul	xh, yl, xh
 	mla	xh, xl, yh, xh
diff --git a/arch/arm/lib/ucmpdi2.S b/arch/arm/lib/ucmpdi2.S
index 112630f..d847a62 100644
--- a/arch/arm/lib/ucmpdi2.S
+++ b/arch/arm/lib/ucmpdi2.S
@@ -10,6 +10,7 @@
  *  published by the Free Software Foundation.
  */
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 
 #ifdef __ARMEB__
@@ -33,3 +34,16 @@
 	movhi	r0, #2
 	mov	pc, lr
 
+#ifdef CONFIG_AEABI
+
+ENTRY(__aeabi_ulcmp)
+
+	cmp	xh, yh
+	cmpeq	xl, yl
+	movlo	r0, #-1
+	moveq	r0, #0
+	movhi	r0, #1
+	mov	pc, lr
+
+#endif
+
diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c
index f5ef697..dc5fa8e 100644
--- a/arch/arm/mach-aaec2000/aaed2000.c
+++ b/arch/arm/mach-aaec2000/aaed2000.c
@@ -90,7 +90,6 @@
 
 MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
 	/* Maintainer: Nicolas Bellido Y Ortega */
-	.phys_ram	= 0xf0000000,
 	.phys_io	= PIO_BASE,
 	.io_pg_offst	= ((VIO_BASE) >> 18) & 0xfffc,
 	.map_io		= aaed2000_map_io,
diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c
index 4aec834..54022e5 100644
--- a/arch/arm/mach-at91rm9200/board-csb337.c
+++ b/arch/arm/mach-at91rm9200/board-csb337.c
@@ -132,7 +132,6 @@
 
 MACHINE_START(CSB337, "Cogent CSB337")
 	/* Maintainer: Bill Gatliff */
-	.phys_ram	= AT91_SDRAM_BASE,
 	.phys_io	= AT91_BASE_SYS,
 	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c
index 23e4cc2..8195f9d 100644
--- a/arch/arm/mach-at91rm9200/board-csb637.c
+++ b/arch/arm/mach-at91rm9200/board-csb637.c
@@ -105,7 +105,6 @@
 
 MACHINE_START(CSB637, "Cogent CSB637")
 	/* Maintainer: Bill Gatliff */
-	.phys_ram	= AT91_SDRAM_BASE,
 	.phys_io	= AT91_BASE_SYS,
 	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c
index 8c747a3..8a78336 100644
--- a/arch/arm/mach-at91rm9200/board-dk.c
+++ b/arch/arm/mach-at91rm9200/board-dk.c
@@ -127,7 +127,6 @@
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
 	/* Maintainer: SAN People/Atmel */
-	.phys_ram	= AT91_SDRAM_BASE,
 	.phys_io	= AT91_BASE_SYS,
 	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c
index d140645..fd0752e 100644
--- a/arch/arm/mach-at91rm9200/board-ek.c
+++ b/arch/arm/mach-at91rm9200/board-ek.c
@@ -120,7 +120,6 @@
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
 	/* Maintainer: SAN People/Atmel */
-	.phys_ram	= AT91_SDRAM_BASE,
 	.phys_io	= AT91_BASE_SYS,
 	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index 43b9423..c13ca6c 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -64,7 +64,6 @@
 
 MACHINE_START(AUTCPU12, "autronix autcpu12")
 	/* Maintainer: Thomas Gleixner */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0020000,
diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c
index cba7be5..831df00 100644
--- a/arch/arm/mach-clps711x/cdb89712.c
+++ b/arch/arm/mach-clps711x/cdb89712.c
@@ -55,7 +55,6 @@
 
 MACHINE_START(CDB89712, "Cirrus-CDB89712")
 	/* Maintainer: Ray Lehtiniemi */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c
index 35d51a7..e2b2c5a 100644
--- a/arch/arm/mach-clps711x/ceiva.c
+++ b/arch/arm/mach-clps711x/ceiva.c
@@ -56,7 +56,6 @@
 
 MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
 	/* Maintainer: Rob Scott */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-clps711x/clep7312.c b/arch/arm/mach-clps711x/clep7312.c
index c83f3fd..09fb57e 100644
--- a/arch/arm/mach-clps711x/clep7312.c
+++ b/arch/arm/mach-clps711x/clep7312.c
@@ -38,7 +38,6 @@
 
 MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
 	/* Maintainer: Nobody */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-clps711x/edb7211-arch.c b/arch/arm/mach-clps711x/edb7211-arch.c
index 255c98b..dc81cc6 100644
--- a/arch/arm/mach-clps711x/edb7211-arch.c
+++ b/arch/arm/mach-clps711x/edb7211-arch.c
@@ -52,7 +52,6 @@
 
 MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
 	/* Maintainer: Jon McClintock */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0020100,	/* 0xc0000000 - 0xc001ffff can be video RAM */
diff --git a/arch/arm/mach-clps711x/fortunet.c b/arch/arm/mach-clps711x/fortunet.c
index 3d88da0..ff26a85 100644
--- a/arch/arm/mach-clps711x/fortunet.c
+++ b/arch/arm/mach-clps711x/fortunet.c
@@ -78,7 +78,6 @@
 
 MACHINE_START(FORTUNET, "ARM-FortuNet")
 	/* Maintainer: FortuNet Inc. */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000000,
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index a1acb94..9ba45f4 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -90,7 +90,6 @@
 
 MACHINE_START(P720T, "ARM-Prospector720T")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index d869af0..5b12cab 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -384,7 +384,6 @@
 
 MACHINE_START(CLPS7500, "CL-PS7500")
 	/* Maintainer: Philip Blundell */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0x03000000,
 	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.map_io		= clps7500_map_io,
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index ed46149..6d620d8 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -284,7 +284,6 @@
 
 MACHINE_START(EBSA110, "EBSA110")
 	/* Maintainer: Russell King */
-	.phys_ram	= 0x00000000,
 	.phys_io	= 0xe0000000,
 	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000400,
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index 49b898a..5b64d5c 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -85,7 +85,6 @@
 
 MACHINE_START(CATS, "Chalice-CATS")
 	/* Maintainer: Philip Blundell */
-	.phys_ram	= 0x00000000,
 	.phys_io	= DC21285_ARMCSR_BASE,
 	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-footbridge/co285.c b/arch/arm/mach-footbridge/co285.c
index 548a790..4545576 100644
--- a/arch/arm/mach-footbridge/co285.c
+++ b/arch/arm/mach-footbridge/co285.c
@@ -29,7 +29,6 @@
 
 MACHINE_START(CO285, "co-EBSA285")
 	/* Maintainer: Mark van Doesburg */
-	.phys_ram	= 0x00000000,
 	.phys_io	= DC21285_ARMCSR_BASE,
 	.io_pg_offst	= ((0x7cf00000) >> 18) & 0xfffc,
 	.fixup		= fixup_coebsa285,
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index 1c37605..b1d3bf2 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -14,7 +14,6 @@
 
 MACHINE_START(EBSA285, "EBSA285")
 	/* Maintainer: Russell King */
-	.phys_ram	= 0x00000000,
 	.phys_io	= DC21285_ARMCSR_BASE,
 	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 9e563de..229bf05 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -649,7 +649,6 @@
 
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
 	/* Maintainer: Russell King/Rebel.com */
-	.phys_ram	= 0x00000000,
 	.phys_io	= DC21285_ARMCSR_BASE,
 	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-footbridge/personal.c b/arch/arm/mach-footbridge/personal.c
index 0146b8b..c4f843f 100644
--- a/arch/arm/mach-footbridge/personal.c
+++ b/arch/arm/mach-footbridge/personal.c
@@ -14,7 +14,6 @@
 
 MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
 	/* Maintainer: Jamey Hicks / George France */
-	.phys_ram	= 0x00000000,
 	.phys_io	= DC21285_ARMCSR_BASE,
 	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-h720x/h7201-eval.c b/arch/arm/mach-h720x/h7201-eval.c
index fa59e9e..193f968 100644
--- a/arch/arm/mach-h720x/h7201-eval.c
+++ b/arch/arm/mach-h720x/h7201-eval.c
@@ -31,7 +31,6 @@
 
 MACHINE_START(H7201, "Hynix GMS30C7201")
 	/* Maintainer: Robert Schwebel, Pengutronix */
-	.phys_ram	= 0x40000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0001000,
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c
index d75c822..3626689 100644
--- a/arch/arm/mach-h720x/h7202-eval.c
+++ b/arch/arm/mach-h720x/h7202-eval.c
@@ -72,7 +72,6 @@
 
 MACHINE_START(H7202, "Hynix HMS30C7202")
 	/* Maintainer: Robert Schwebel, Pengutronix */
-	.phys_ram	= 0x40000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x40000100,
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
index c9e0cd8..dc31e3f 100644
--- a/arch/arm/mach-imx/mx1ads.c
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -69,7 +69,6 @@
 
 MACHINE_START(MX1ADS, "Motorola MX1ADS")
 	/* Maintainer: Sascha Hauer, Pengutronix */
-	.phys_ram	= 0x08000000,
 	.phys_io	= 0x00200000,
 	.io_pg_offst	= ((0xe0200000) >> 18) & 0xfffc,
 	.boot_params	= 0x08000100,
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 3afedeb..d8d3c2a 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -347,7 +347,6 @@
 
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0x00000000,
 	.phys_io	= 0x16000000,
 	.io_pg_offst	= ((0xf1600000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 16cf248..3182017 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -578,7 +578,6 @@
 
 MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0x00000000,
 	.phys_io	= 0x16000000,
 	.io_pg_offst	= ((0xf1600000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-integrator/lm.c b/arch/arm/mach-integrator/lm.c
index 5b41e3a..622cdc4 100644
--- a/arch/arm/mach-integrator/lm.c
+++ b/arch/arm/mach-integrator/lm.c
@@ -22,20 +22,6 @@
 	return 1;
 }
 
-static struct bus_type lm_bustype = {
-	.name		= "logicmodule",
-	.match		= lm_match,
-//	.suspend	= lm_suspend,
-//	.resume		= lm_resume,
-};
-
-static int __init lm_init(void)
-{
-	return bus_register(&lm_bustype);
-}
-
-postcore_initcall(lm_init);
-
 static int lm_bus_probe(struct device *dev)
 {
 	struct lm_device *lmdev = to_lm_device(dev);
@@ -49,16 +35,30 @@
 	struct lm_device *lmdev = to_lm_device(dev);
 	struct lm_driver *lmdrv = to_lm_driver(dev->driver);
 
-	lmdrv->remove(lmdev);
+	if (lmdrv->remove)
+		lmdrv->remove(lmdev);
 	return 0;
 }
 
+static struct bus_type lm_bustype = {
+	.name		= "logicmodule",
+	.match		= lm_match,
+	.probe		= lm_bus_probe,
+	.remove		= lm_bus_remove,
+//	.suspend	= lm_bus_suspend,
+//	.resume		= lm_bus_resume,
+};
+
+static int __init lm_init(void)
+{
+	return bus_register(&lm_bustype);
+}
+
+postcore_initcall(lm_init);
+
 int lm_driver_register(struct lm_driver *drv)
 {
 	drv->drv.bus = &lm_bustype;
-	drv->drv.probe = lm_bus_probe;
-	drv->drv.remove = lm_bus_remove;
-
 	return driver_register(&drv->drv);
 }
 
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
index 8077023..e4f4c52 100644
--- a/arch/arm/mach-iop3xx/iop321-setup.c
+++ b/arch/arm/mach-iop3xx/iop321-setup.c
@@ -151,7 +151,6 @@
 #if defined(CONFIG_ARCH_IQ80321)
 MACHINE_START(IQ80321, "Intel IQ80321")
 	/* Maintainer: Intel Corporation */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IQ80321_UART,
 	.io_pg_offst	= ((IQ80321_UART) >> 18) & 0xfffc,
 	.map_io		= iq80321_map_io,
@@ -163,7 +162,6 @@
 #elif defined(CONFIG_ARCH_IQ31244)
 MACHINE_START(IQ31244, "Intel IQ31244")
 	/* Maintainer: Intel Corp. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IQ31244_UART,
 	.io_pg_offst	= ((IQ31244_UART) >> 18) & 0xfffc,
 	.map_io		= iq31244_map_io,
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
index e6ea1cb..6358548 100644
--- a/arch/arm/mach-iop3xx/iop331-setup.c
+++ b/arch/arm/mach-iop3xx/iop331-setup.c
@@ -195,7 +195,6 @@
 #if defined(CONFIG_ARCH_IQ80331)
 MACHINE_START(IQ80331, "Intel IQ80331")
 	/* Maintainer: Intel Corp. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= 0xfefff000,
 	.io_pg_offst	= ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
 	.map_io		= iq80331_map_io,
@@ -208,7 +207,6 @@
 #elif defined(CONFIG_MACH_IQ80332)
 MACHINE_START(IQ80332, "Intel IQ80332")
 	/* Maintainer: Intel Corp. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= 0xfefff000,
 	.io_pg_offst	= ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
 	.map_io		= iq80332_map_io,
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 6851aba..cfd5bef 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -106,6 +106,16 @@
 		.length		= IXP2000_MSF_SIZE,
 		.type		= MT_IXP2000_DEVICE,
 	}, {
+		.virtual	= IXP2000_SCRATCH_RING_VIRT_BASE,
+		.pfn		= __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
+		.length		= IXP2000_SCRATCH_RING_SIZE,
+		.type		= MT_IXP2000_DEVICE,
+	}, {
+		.virtual	= IXP2000_SRAM0_VIRT_BASE,
+		.pfn		= __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
+		.length		= IXP2000_SRAM0_SIZE,
+		.type		= MT_IXP2000_DEVICE,
+	}, {
 		.virtual	= IXP2000_PCI_IO_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
 		.length		= IXP2000_PCI_IO_SIZE,
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index 61f6006..9e5a13b 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -254,7 +254,6 @@
 
 MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_ram	= 0x00000000,
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index fd280a9..7c78240 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -169,7 +169,6 @@
 
 MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= 0x00000000,
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index f9073aa..076e3f8 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -285,7 +285,6 @@
 
 MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= 0x00000000,
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index e6a882f..10f0660 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -376,7 +376,6 @@
 #ifdef CONFIG_ARCH_IXDP2401
 MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= 0x00000000,
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
@@ -390,7 +389,6 @@
 #ifdef CONFIG_ARCH_IXDP2801
 MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= 0x00000000,
 	.phys_io	= IXP2000_UART_PHYS_BASE,
 	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 679594a..13f8a7a 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -101,7 +101,6 @@
 #ifdef CONFIG_ARCH_ADI_COYOTE
 MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
@@ -119,7 +118,6 @@
 #ifdef CONFIG_MACH_IXDPG425
 MACHINE_START(IXDPG425, "Intel IXDPG425")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index 0386704..654e2ee 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -142,7 +142,6 @@
 
 MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
 	/* Maintainer: George Joseph */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_UART2_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index c2e105c..da72383 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -121,7 +121,6 @@
 #ifdef CONFIG_ARCH_IXDP425
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
@@ -135,7 +134,6 @@
 #ifdef CONFIG_MACH_IXDP465
 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
@@ -149,7 +147,6 @@
 #ifdef CONFIG_ARCH_PRPMC1100
 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
@@ -169,7 +166,6 @@
 #ifdef CONFIG_ARCH_AVILA
 MACHINE_START(AVILA, "Gateworks Avila Network Platform")
 	/* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 49998a8..856d56f 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -124,7 +124,6 @@
 
 MACHINE_START(NAS100D, "Iomega NAS 100d")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index 289e94c..da9340a 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -123,7 +123,6 @@
 
 MACHINE_START(NSLU2, "Linksys NSLU2")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_ram	= PHYS_OFFSET,
 	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
 	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c
index 03ed742..ac62643 100644
--- a/arch/arm/mach-l7200/core.c
+++ b/arch/arm/mach-l7200/core.c
@@ -91,7 +91,6 @@
 
 MACHINE_START(L7200, "LinkUp Systems L7200")
 	/* Maintainer: Steve Hill / Scott McConnell */
-	.phys_ram	= 0xf0000000,
 	.phys_io	= 0x80040000,
 	.io_pg_offst	= ((0xd0000000) >> 18) & 0xfffc,
 	.map_io		= l7200_map_io,
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index 19f2fa2..2cccc27 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -112,7 +112,6 @@
 
 MACHINE_START (KEV7A400, "Sharp KEV7a400")
 	/* Maintainer: Marc Singer */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index 4eb962f..12e2327 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -317,7 +317,6 @@
 
 MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
 	/* Maintainer: Marc Singer */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
@@ -333,7 +332,6 @@
 
 MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
 	/* Maintainer: Marc Singer */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 4b292e9..bdc20b5 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -109,7 +109,6 @@
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
 	/* Maintainer: Tony Lindgren <tony@atomide.com> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index a07e2c9..9533c36 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -199,7 +199,6 @@
 
 MACHINE_START(OMAP_H2, "TI-H2")
 	/* Maintainer: Imre Deak <imre.deak@nokia.com> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 668e278..d665efc 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -215,7 +215,6 @@
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
 	/* Maintainer: Texas Instruments, Inc. */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 95f1ff3..652f37c 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -303,7 +303,6 @@
 
 MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index 0448fa7..58f7839 100644
--- a/arch/arm/mach-omap1/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -149,7 +149,6 @@
 
 MACHINE_START(NETSTAR, "NetStar OMAP5910")
 	/* Maintainer: Ladislav Michl <michl@2n.cz> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index e990e1b..e5d126e 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -274,7 +274,6 @@
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
 	/* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 5c975eb..67fada2 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -76,7 +76,6 @@
 }
 
 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 92ff5dc..88708a0 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -199,7 +199,6 @@
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
 	/* Maintainer: Kevin Hilman <kjh@hilman.org> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 6f9a622..959b4b8 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -281,7 +281,6 @@
 
 MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
 	/* Maintainer: Ladislav Michl <michl@2n.cz> */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0xfff00000,
 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index c602e7a..b937123 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -69,7 +69,6 @@
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
 	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-	.phys_ram	= 0x80000000,
 	.phys_io	= 0x48000000,
 	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index f255446..c3c35d4 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -186,7 +186,6 @@
 
 MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
 	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-	.phys_ram	= 0x80000000,
 	.phys_io	= 0x48000000,
 	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 5a7b873..7ffd2de 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -342,7 +342,6 @@
 
 #ifdef CONFIG_MACH_CORGI
 MACHINE_START(CORGI, "SHARP Corgi")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
@@ -355,7 +354,6 @@
 
 #ifdef CONFIG_MACH_SHEPHERD
 MACHINE_START(SHEPHERD, "SHARP Shepherd")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
@@ -368,7 +366,6 @@
 
 #ifdef CONFIG_MACH_HUSKY
 MACHINE_START(HUSKY, "SHARP Husky")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 7de159e..347b9de 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -183,7 +183,6 @@
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
 	/* Maintainer: Vibren Technologies */
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= idp_map_io,
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index b464bc8..3e26d7c 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -437,7 +437,6 @@
 
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
 	/* Maintainer: MontaVista Software Inc. */
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= lubbock_map_io,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 8da9d3e..d5bda60 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -489,7 +489,6 @@
 
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
 	/* Maintainer: MontaVista Software Inc. */
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= mainstone_map_io,
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 663c950..911e6ff 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -311,7 +311,6 @@
 }
 
 MACHINE_START(POODLE, "SHARP Poodle")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_poodle,
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index a9eacc0..c094d99 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -497,7 +497,6 @@
 
 #ifdef CONFIG_MACH_SPITZ
 MACHINE_START(SPITZ, "SHARP Spitz")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_spitz,
@@ -510,7 +509,6 @@
 
 #ifdef CONFIG_MACH_BORZOI
 MACHINE_START(BORZOI, "SHARP Borzoi")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_spitz,
@@ -523,7 +521,6 @@
 
 #ifdef CONFIG_MACH_AKITA
 MACHINE_START(AKITA, "SHARP Akita")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_spitz,
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index e4f92ef..d168286 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -295,7 +295,6 @@
 }
 
 MACHINE_START(TOSA, "SHARP Tosa")
-	.phys_ram	= 0xa0000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup          = fixup_tosa,
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 1299768..17f5f44 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -3,7 +3,6 @@
 
 config MACH_REALVIEW_EB
 	bool "Support RealView/EB platform"
-	default n
 	select ARM_GIC
 	help
 	  Include support for the ARM(R) RealView Emulation Baseboard platform.
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 112f759..d4a586e 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -166,7 +166,6 @@
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0x00000000,
 	.phys_io	= REALVIEW_UART0_BASE,
 	.io_pg_offst	= (IO_ADDRESS(REALVIEW_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 5c4ac1c..208a2b5 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -177,7 +177,6 @@
 
 MACHINE_START(RISCPC, "Acorn-RiscPC")
 	/* Maintainer: Russell King */
-	.phys_ram	= 0x10000000,
 	.phys_io	= 0x03000000,
 	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
index 0f81fc0..3e327b8 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -294,7 +294,6 @@
 
 MACHINE_START(ANUBIS, "Simtec-Anubis")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 4d96271..995bb8a 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -527,7 +527,6 @@
 
 MACHINE_START(BAST, "Simtec-BAST")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 0aa8760..1c316f1 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -171,7 +171,6 @@
 
 MACHINE_START(H1940, "IPAQ-H1940")
 	/* Maintainer: Ben Dooks <ben@fluff.org> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 378d640..116ac31 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -128,7 +128,6 @@
 	/* Maintainer: Christer Weinigel <christer@weinigel.se>,
 				Ben Dooks <ben-linux@fluff.org>
 	*/
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c
index 42b0eef..07d0950 100644
--- a/arch/arm/mach-s3c2410/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2410/mach-nexcoder.c
@@ -148,7 +148,6 @@
 
 MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index a2eb9ed..b39daed 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -116,7 +116,6 @@
 
 MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
index f8d86d1..0260ed5 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -205,7 +205,6 @@
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
 	/* Maintainer: Ben Dooks <ben@fluff.org> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 2c91965..1e76e1f 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -115,7 +115,6 @@
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
 				    * to SMDK2410 */
 	/* Maintainer: Jonas Dietsche */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index 4e31118..f431572 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -216,7 +216,6 @@
 
 MACHINE_START(S3C2440, "SMDK2440")
 	/* Maintainer: Ben Dooks <ben@fluff.org> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index ae7e099..785fc9c 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -395,7 +395,6 @@
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_ram	= S3C2410_SDRAM_PA,
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index a66ac61..a599bb0 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -447,7 +447,6 @@
 
 
 MACHINE_START(ASSABET, "Intel-Assabet")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index edccd5e..f60b7a6 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -297,7 +297,6 @@
 }
 
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 5085937..8269a9e 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -135,7 +135,6 @@
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
 	/* Maintainer: support@intrinsyc.com */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= cerf_map_io,
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 522abc0..6888816 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -191,7 +191,6 @@
 }
 
 MACHINE_START(COLLIE, "Sharp-Collie")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= collie_map_io,
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index e8352b7..b04d922 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -392,7 +392,6 @@
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
@@ -510,7 +509,6 @@
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
@@ -897,7 +895,6 @@
 }
 
 MACHINE_START(H3800, "Compaq iPAQ H3800")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index c922e04..046b213 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -195,7 +195,6 @@
  */
 
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 2f671cc..17f5a43 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -173,7 +173,6 @@
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
 	/* Maintainer: Michael Gernoth <michael@gernoth.net> */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index 8c9e3dd..07d3a69 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -60,7 +60,6 @@
 }
 
 MACHINE_START(LART, "LART")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 58c18f9..0709ebab 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -146,7 +146,6 @@
 }
 
 MACHINE_START(PLEB, "PLEB")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= pleb_map_io,
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index 7482288..5aafe0b5 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -83,7 +83,6 @@
 }
 
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 439ddc9..d2c23b2 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -229,7 +229,6 @@
 
 MACHINE_START(SIMPAD, "Simpad")
 	/* Maintainer: Holger Freyther */
-	.phys_ram	= 0xc0000000,
 	.phys_io	= 0x80000000,
 	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 2d428b6..877600e 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -111,7 +111,6 @@
 
 MACHINE_START(SHARK, "Shark")
 	/* Maintainer: Alexander Schulz */
-	.phys_ram	= 0x08000000,
 	.phys_io	= 0x40000000,
 	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x08003000,
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
index 8d787f4..95096af 100644
--- a/arch/arm/mach-versatile/Kconfig
+++ b/arch/arm/mach-versatile/Kconfig
@@ -9,7 +9,6 @@
 
 config MACH_VERSATILE_AB
 	bool "Support Versatile/AB platform"
-	default n
 	help
 	  Include support for the ARM(R) Versatile/AP platform.
 
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 9002374..9ebbe80 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -35,6 +35,7 @@
 #include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst307.h>
+#include <asm/hardware/vic.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -56,24 +57,6 @@
 #define VA_VIC_BASE		__io_address(VERSATILE_VIC_BASE)
 #define VA_SIC_BASE		__io_address(VERSATILE_SIC_BASE)
 
-static void vic_mask_irq(unsigned int irq)
-{
-	irq -= IRQ_VIC_START;
-	writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR);
-}
-
-static void vic_unmask_irq(unsigned int irq)
-{
-	irq -= IRQ_VIC_START;
-	writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE);
-}
-
-static struct irqchip vic_chip = {
-	.ack	= vic_mask_irq,
-	.mask	= vic_mask_irq,
-	.unmask	= vic_unmask_irq,
-};
-
 static void sic_mask_irq(unsigned int irq)
 {
 	irq -= IRQ_SIC_START;
@@ -127,43 +110,12 @@
 
 void __init versatile_init_irq(void)
 {
-	unsigned int i, value;
+	unsigned int i;
 
-	/* Disable all interrupts initially. */
-
-	writel(0, VA_VIC_BASE + VIC_INT_SELECT);
-	writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE);
-	writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR);
-	writel(0, VA_VIC_BASE + VIC_IRQ_STATUS);
-	writel(0, VA_VIC_BASE + VIC_ITCR);
-	writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR);
-
-	/*
-	 * Make sure we clear all existing interrupts
-	 */
-	writel(0, VA_VIC_BASE + VIC_VECT_ADDR);
-	for (i = 0; i < 19; i++) {
-		value = readl(VA_VIC_BASE + VIC_VECT_ADDR);
-		writel(value, VA_VIC_BASE + VIC_VECT_ADDR);
-	}
-
-	for (i = 0; i < 16; i++) {
-		value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4));
-		writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4));
-	}
-
-	writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR);
-
-	for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) {
-		if (i != IRQ_VICSOURCE31) {
-			set_irq_chip(i, &vic_chip);
-			set_irq_handler(i, do_level_IRQ);
-			set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-		}
-	}
+	vic_init(VA_VIC_BASE, ~(1 << 31));
 
 	set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq);
-	vic_unmask_irq(IRQ_VICSOURCE31);
+	enable_irq(IRQ_VICSOURCE31);
 
 	/* Do second interrupt controller */
 	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
@@ -877,7 +829,7 @@
 	ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
 	do {
 		ticks1 = ticks2;
-		status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
+		status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS);
 		ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
 	} while (ticks2 > ticks1);
 
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
index e74c8a2..1eb5967 100644
--- a/arch/arm/mach-versatile/versatile_ab.c
+++ b/arch/arm/mach-versatile/versatile_ab.c
@@ -36,7 +36,6 @@
 
 MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0x00000000,
 	.phys_io	= 0x101f1000,
 	.io_pg_offst	= ((0xf11f1000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index 22d5ca0..f17ab4f 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -100,7 +100,6 @@
 
 MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_ram	= 0x00000000,
 	.phys_io	= 0x101f1000,
 	.io_pg_offst	= ((0xf11f1000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
diff --git a/arch/arm/nwfpe/fpa11.h b/arch/arm/nwfpe/fpa11.h
index da4c616..28cd79a 100644
--- a/arch/arm/nwfpe/fpa11.h
+++ b/arch/arm/nwfpe/fpa11.h
@@ -62,7 +62,7 @@
 #else
 	u32 padding[3];
 #endif
-} FPREG;
+} __attribute__ ((packed,aligned(4))) FPREG;
 
 /*
  * FPA11 device model.
@@ -89,7 +89,7 @@
 				   so we can use it to detect whether this
 				   instance of the emulator needs to be
 				   initialised. */
-} FPA11;
+} __attribute__ ((packed,aligned(4))) FPA11;
 
 extern int8 SetRoundingMode(const unsigned int);
 extern int8 SetRoundingPrecision(const unsigned int);
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 9693e9b..0887bb2 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -22,7 +22,6 @@
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
 	depends on ARCH_OMAP
-	default n
 	help
 	  Say Y if you want to reset unused clocks during boot.
 	  This option saves power, but assumes all drivers are
@@ -44,7 +43,6 @@
 config OMAP_MUX_DEBUG
 	bool "Multiplexing debug output"
         depends on OMAP_MUX
-        default n
         help
           Makes the multiplexing functions print out a lot of debug info.
           This is useful if you want to find out the correct values of the
@@ -93,7 +91,6 @@
 
 config OMAP_DM_TIMER
 	bool "Use dual-mode timer"
-	default n
 	depends on ARCH_OMAP16XX
 	help
 	 Select this option if you want to use OMAP Dual-Mode timers.
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index d5d0df7..cbde675 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -702,6 +702,15 @@
 
 	  Don't change this unless you know what you are doing.
 
+config HOTPLUG_CPU
+	bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+	depends on SMP && HOTPLUG && EXPERIMENTAL
+	---help---
+	  Say Y here to experiment with turning CPUs off and on.  CPUs
+	  can be controlled through /sys/devices/system/cpu.
+
+	  Say N.
+
 endmenu
 
 
@@ -988,15 +997,6 @@
 	  This support is also available as a module.  If compiled as a
 	  module, it will be called scx200.
 
-config HOTPLUG_CPU
-	bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
-	depends on SMP && HOTPLUG && EXPERIMENTAL
-	---help---
-	  Say Y here to experiment with turning CPUs off and on.  CPUs
-	  can be controlled through /sys/devices/system/cpu.
-
-	  Say N.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index d3c0409..bd2d53a 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -42,9 +42,9 @@
 cflags-$(CONFIG_REGPARM) += $(shell if [ $(call cc-version) -ge 0300 ] ; then \
                             echo "-mregparm=3"; fi ;)
 
-# Disable unit-at-a-time mode, it makes gcc use a lot more stack
-# due to the lack of sharing of stacklots.
-CFLAGS += $(call cc-option,-fno-unit-at-a-time)
+# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
+# a lot more stack due to the lack of sharing of stacklots:
+CFLAGS				+= $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-option,-fno-unit-at-a-time); fi ;)
 
 CFLAGS += $(cflags-y)
 
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index b9f0030..0aaebf3 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -112,33 +112,38 @@
 		p < (void *)tinfo + THREAD_SIZE - 3;
 }
 
+static void print_addr_and_symbol(unsigned long addr, char *log_lvl)
+{
+	printk(log_lvl);
+	printk(" [<%08lx>] ", addr);
+	print_symbol("%s", addr);
+	printk("\n");
+}
+
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
-				unsigned long *stack, unsigned long ebp)
+				unsigned long *stack, unsigned long ebp,
+				char *log_lvl)
 {
 	unsigned long addr;
 
 #ifdef	CONFIG_FRAME_POINTER
 	while (valid_stack_ptr(tinfo, (void *)ebp)) {
 		addr = *(unsigned long *)(ebp + 4);
-		printk(KERN_EMERG " [<%08lx>] ", addr);
-		print_symbol("%s", addr);
-		printk("\n");
+		print_addr_and_symbol(addr, log_lvl);
 		ebp = *(unsigned long *)ebp;
 	}
 #else
 	while (valid_stack_ptr(tinfo, stack)) {
 		addr = *stack++;
-		if (__kernel_text_address(addr)) {
-			printk(KERN_EMERG " [<%08lx>]", addr);
-			print_symbol(" %s", addr);
-			printk("\n");
-		}
+		if (__kernel_text_address(addr))
+			print_addr_and_symbol(addr, log_lvl);
 	}
 #endif
 	return ebp;
 }
 
-void show_trace(struct task_struct *task, unsigned long * stack)
+static void show_trace_log_lvl(struct task_struct *task,
+			       unsigned long *stack, char *log_lvl)
 {
 	unsigned long ebp;
 
@@ -157,7 +162,7 @@
 		struct thread_info *context;
 		context = (struct thread_info *)
 			((unsigned long)stack & (~(THREAD_SIZE - 1)));
-		ebp = print_context_stack(context, stack, ebp);
+		ebp = print_context_stack(context, stack, ebp, log_lvl);
 		stack = (unsigned long*)context->previous_esp;
 		if (!stack)
 			break;
@@ -165,7 +170,13 @@
 	}
 }
 
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_trace(struct task_struct *task, unsigned long * stack)
+{
+	show_trace_log_lvl(task, stack, "");
+}
+
+static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp,
+			       char *log_lvl)
 {
 	unsigned long *stack;
 	int i;
@@ -178,16 +189,26 @@
 	}
 
 	stack = esp;
-	printk(KERN_EMERG);
+	printk(log_lvl);
 	for(i = 0; i < kstack_depth_to_print; i++) {
 		if (kstack_end(stack))
 			break;
-		if (i && ((i % 8) == 0))
-			printk("\n" KERN_EMERG "       ");
+		if (i && ((i % 8) == 0)) {
+			printk("\n");
+			printk(log_lvl);
+			printk("       ");
+		}
 		printk("%08lx ", *stack++);
 	}
-	printk("\n" KERN_EMERG "Call Trace:\n");
-	show_trace(task, esp);
+	printk("\n");
+	printk(log_lvl);
+	printk("Call Trace:\n");
+	show_trace_log_lvl(task, esp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+	show_stack_log_lvl(task, esp, "");
 }
 
 /*
@@ -238,7 +259,7 @@
 		u8 __user *eip;
 
 		printk("\n" KERN_EMERG "Stack: ");
-		show_stack(NULL, (unsigned long*)esp);
+		show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG);
 
 		printk(KERN_EMERG "Code: ");
 
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index 65f6707..83c3645 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -449,3 +449,19 @@
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032,
 			 pci_post_fixup_toshiba_ohci1394);
+
+
+/*
+ * Prevent the BIOS trapping accesses to the Cyrix CS5530A video device
+ * configuration space.
+ */
+static void __devinit pci_early_fixup_cyrix_5530(struct pci_dev *dev)
+{
+	u8 r;
+	/* clear 'F4 Video Configuration Trap' bit */
+	pci_read_config_byte(dev, 0x42, &r);
+	r &= 0xfd;
+	pci_write_config_byte(dev, 0x42, r);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
+			pci_early_fixup_cyrix_5530);
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig
index 80f8663..1d07d80 100644
--- a/arch/ia64/configs/gensparse_defconfig
+++ b/arch/ia64/configs/gensparse_defconfig
@@ -701,6 +701,7 @@
 CONFIG_SERIAL_SGI_L1_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_IOC3=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1046,6 +1047,7 @@
 # SN Devices
 #
 CONFIG_SGI_IOC4=y
+CONFIG_SGI_IOC3=y
 
 #
 # File systems
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index ff8bb37..3cb503b 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -659,6 +659,7 @@
 CONFIG_SERIAL_SGI_L1_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_IOC3=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -899,6 +900,7 @@
 # SN Devices
 #
 CONFIG_SGI_IOC4=y
+CONFIG_SGI_IOC3=y
 
 #
 # File systems
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index a346e18..626cdc8 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -108,7 +108,6 @@
 static struct console *console;
 
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 extern struct console *console_drivers; /* from kernel/printk.c */
 
@@ -167,15 +166,9 @@
 			}
 		}
 		seen_esc = 0;
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
 
-		*tty->flip.char_buf_ptr = ch;
-
-		*tty->flip.flag_buf_ptr = 0;
-
-		tty->flip.flag_buf_ptr++;
-		tty->flip.char_buf_ptr++;
-		tty->flip.count++;
+		if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+			break;
 	}
 	tty_flip_buffer_push(tty);
 }
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 2ddbac6..ce42391 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -903,5 +903,6 @@
 	data8 0
 	data8 0
 	data8 0
+	data8 0							// 1280
 
 	.org fsyscall_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls
diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S
index 2323377..5cd6226f 100644
--- a/arch/ia64/kernel/jprobes.S
+++ b/arch/ia64/kernel/jprobes.S
@@ -60,3 +60,30 @@
 GLOBAL_ENTRY(jprobe_inst_return)
 	br.call.sptk.many b0=jprobe_break
 END(jprobe_inst_return)
+
+GLOBAL_ENTRY(invalidate_stacked_regs)
+	movl r16=invalidate_restore_cfm
+	;;
+	mov b6=r16
+	;;
+	br.ret.sptk.many b6
+	;;
+invalidate_restore_cfm:
+	mov r16=ar.rsc
+	;;
+	mov ar.rsc=r0
+	;;
+	loadrs
+	;;
+	mov ar.rsc=r16
+	;;
+	br.cond.sptk.many rp
+END(invalidate_stacked_regs)
+
+GLOBAL_ENTRY(flush_register_stack)
+	// flush dirty regs to backing store (must be first in insn group)
+	flushrs
+	;;
+	br.ret.sptk.many rp
+END(flush_register_stack)
+
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 346fedf..50ae8c7 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -766,11 +766,56 @@
 	return ret;
 }
 
+struct param_bsp_cfm {
+	unsigned long ip;
+	unsigned long *bsp;
+	unsigned long cfm;
+};
+
+static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg)
+{
+	unsigned long ip;
+	struct param_bsp_cfm *lp = arg;
+
+	do {
+		unw_get_ip(info, &ip);
+		if (ip == 0)
+			break;
+		if (ip == lp->ip) {
+			unw_get_bsp(info, (unsigned long*)&lp->bsp);
+			unw_get_cfm(info, (unsigned long*)&lp->cfm);
+			return;
+		}
+	} while (unw_unwind(info) >= 0);
+	lp->bsp = 0;
+	lp->cfm = 0;
+	return;
+}
+
 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
 	struct jprobe *jp = container_of(p, struct jprobe, kp);
 	unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	struct param_bsp_cfm pa;
+	int bytes;
+
+	/*
+	 * Callee owns the argument space and could overwrite it, eg
+	 * tail call optimization. So to be absolutely safe
+	 * we save the argument space before transfering the control
+	 * to instrumented jprobe function which runs in
+	 * the process context
+	 */
+	pa.ip = regs->cr_iip;
+	unw_init_running(ia64_get_bsp_cfm, &pa);
+	bytes = (char *)ia64_rse_skip_regs(pa.bsp, pa.cfm & 0x3f)
+				- (char *)pa.bsp;
+	memcpy( kcb->jprobes_saved_stacked_regs,
+		pa.bsp,
+		bytes );
+	kcb->bsp = pa.bsp;
+	kcb->cfm = pa.cfm;
 
 	/* save architectural state */
 	kcb->jprobe_saved_regs = *regs;
@@ -792,8 +837,20 @@
 int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	int bytes;
 
+	/* restoring architectural state */
 	*regs = kcb->jprobe_saved_regs;
+
+	/* restoring the original argument space */
+	flush_register_stack();
+	bytes = (char *)ia64_rse_skip_regs(kcb->bsp, kcb->cfm & 0x3f)
+				- (char *)kcb->bsp;
+	memcpy( kcb->bsp,
+		kcb->jprobes_saved_stacked_regs,
+		bytes );
+	invalidate_stacked_regs();
+
 	preempt_enable_no_resched();
 	return 1;
 }
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index db32fc1..403a80a 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -847,7 +847,7 @@
 	;;
 	mov cr.iim=temp3
 	mov cr.iha=temp4
-	dep r22=0,r22,62,2	// pal_min_state, physical, uncached
+	dep r22=0,r22,62,1	// pal_min_state, physical, uncached
 	mov IA64_KR(CURRENT)=r21
 	ld8 r8=[temp1]		// os_status
 	ld8 r10=[temp2]		// context
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index a87a162..9d5a823 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -3,7 +3,7 @@
  *
  * Creates entries in /proc/sal for various system features.
  *
- * Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2003, 2006 Silicon Graphics, Inc.  All rights reserved.
  * Copyright (c) 2003 Hewlett-Packard Co
  *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  *
@@ -27,9 +27,17 @@
  *   mca.c may not pass a buffer, a NULL buffer just indicates that a new
  *   record is available in SAL.
  *   Replace some NR_CPUS by cpus_online, for hotplug cpu.
+ *
+ * Jan  5 2006        kaos@sgi.com
+ *   Handle hotplug cpus coming online.
+ *   Handle hotplug cpus going offline while they still have outstanding records.
+ *   Use the cpu_* macros consistently.
+ *   Replace the counting semaphore with a mutex and a test if the cpumask is non-empty.
+ *   Modify the locking to make the test for "work to do" an atomic operation.
  */
 
 #include <linux/capability.h>
+#include <linux/cpu.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
@@ -132,8 +140,8 @@
 };
 
 struct salinfo_data {
-	volatile cpumask_t	cpu_event;	/* which cpus have outstanding events */
-	struct semaphore	sem;		/* count of cpus with outstanding events (bits set in cpu_event) */
+	cpumask_t		cpu_event;	/* which cpus have outstanding events */
+	struct semaphore	mutex;
 	u8			*log_buffer;
 	u64			log_size;
 	u8			*oemdata;	/* decoded oem data */
@@ -174,6 +182,21 @@
 	int ret;
 };
 
+/* Kick the mutex that tells user space that there is work to do.  Instead of
+ * trying to track the state of the mutex across multiple cpus, in user
+ * context, interrupt context, non-maskable interrupt context and hotplug cpu,
+ * it is far easier just to grab the mutex if it is free then release it.
+ *
+ * This routine must be called with data_saved_lock held, to make the down/up
+ * operation atomic.
+ */
+static void
+salinfo_work_to_do(struct salinfo_data *data)
+{
+	down_trylock(&data->mutex);
+	up(&data->mutex);
+}
+
 static void
 salinfo_platform_oemdata_cpu(void *context)
 {
@@ -212,9 +235,9 @@
 
 	BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
 
+	if (irqsafe)
+		spin_lock_irqsave(&data_saved_lock, flags);
 	if (buffer) {
-		if (irqsafe)
-			spin_lock_irqsave(&data_saved_lock, flags);
 		for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
 			if (!data_saved->buffer)
 				break;
@@ -232,13 +255,11 @@
 			data_saved->size = size;
 			data_saved->buffer = buffer;
 		}
-		if (irqsafe)
-			spin_unlock_irqrestore(&data_saved_lock, flags);
 	}
-
-	if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) {
-		if (irqsafe)
-			up(&data->sem);
+	cpu_set(smp_processor_id(), data->cpu_event);
+	if (irqsafe) {
+		salinfo_work_to_do(data);
+		spin_unlock_irqrestore(&data_saved_lock, flags);
 	}
 }
 
@@ -249,20 +270,17 @@
 static void
 salinfo_timeout_check(struct salinfo_data *data)
 {
-	int i;
+	unsigned long flags;
 	if (!data->open)
 		return;
-	for_each_online_cpu(i) {
-		if (test_bit(i, &data->cpu_event)) {
-			/* double up() is not a problem, user space will see no
-			 * records for the additional "events".
-			 */
-			up(&data->sem);
-		}
+	if (!cpus_empty(data->cpu_event)) {
+		spin_lock_irqsave(&data_saved_lock, flags);
+		salinfo_work_to_do(data);
+		spin_unlock_irqrestore(&data_saved_lock, flags);
 	}
 }
 
-static void 
+static void
 salinfo_timeout (unsigned long arg)
 {
 	salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
@@ -290,16 +308,20 @@
 	int i, n, cpu = -1;
 
 retry:
-	if (down_trylock(&data->sem)) {
+	if (cpus_empty(data->cpu_event) && down_trylock(&data->mutex)) {
 		if (file->f_flags & O_NONBLOCK)
 			return -EAGAIN;
-		if (down_interruptible(&data->sem))
+		if (down_interruptible(&data->mutex))
 			return -EINTR;
 	}
 
 	n = data->cpu_check;
 	for (i = 0; i < NR_CPUS; i++) {
-		if (test_bit(n, &data->cpu_event) && cpu_online(n)) {
+		if (cpu_isset(n, data->cpu_event)) {
+			if (!cpu_online(n)) {
+				cpu_clear(n, data->cpu_event);
+				continue;
+			}
 			cpu = n;
 			break;
 		}
@@ -310,9 +332,6 @@
 	if (cpu == -1)
 		goto retry;
 
-	/* events are sticky until the user says "clear" */
-	up(&data->sem);
-
 	/* for next read, start checking at next CPU */
 	data->cpu_check = cpu;
 	if (++data->cpu_check == NR_CPUS)
@@ -381,10 +400,8 @@
 static void
 call_on_cpu(int cpu, void (*fn)(void *), void *arg)
 {
-	cpumask_t save_cpus_allowed, new_cpus_allowed;
-	memcpy(&save_cpus_allowed, &current->cpus_allowed, sizeof(save_cpus_allowed));
-	memset(&new_cpus_allowed, 0, sizeof(new_cpus_allowed));
-	set_bit(cpu, &new_cpus_allowed);
+	cpumask_t save_cpus_allowed = current->cpus_allowed;
+	cpumask_t new_cpus_allowed = cpumask_of_cpu(cpu);
 	set_cpus_allowed(current, new_cpus_allowed);
 	(*fn)(arg);
 	set_cpus_allowed(current, save_cpus_allowed);
@@ -433,10 +450,10 @@
 	if (!data->saved_num)
 		call_on_cpu(cpu, salinfo_log_read_cpu, data);
 	if (!data->log_size) {
-	        data->state = STATE_NO_DATA;
-	        clear_bit(cpu, &data->cpu_event);
+		data->state = STATE_NO_DATA;
+		cpu_clear(cpu, data->cpu_event);
 	} else {
-	        data->state = STATE_LOG_RECORD;
+		data->state = STATE_LOG_RECORD;
 	}
 }
 
@@ -473,27 +490,31 @@
 salinfo_log_clear(struct salinfo_data *data, int cpu)
 {
 	sal_log_record_header_t *rh;
+	unsigned long flags;
+	spin_lock_irqsave(&data_saved_lock, flags);
 	data->state = STATE_NO_DATA;
-	if (!test_bit(cpu, &data->cpu_event))
-		return 0;
-	down(&data->sem);
-	clear_bit(cpu, &data->cpu_event);
-	if (data->saved_num) {
-		unsigned long flags;
-		spin_lock_irqsave(&data_saved_lock, flags);
-		shift1_data_saved(data, data->saved_num - 1 );
-		data->saved_num = 0;
+	if (!cpu_isset(cpu, data->cpu_event)) {
 		spin_unlock_irqrestore(&data_saved_lock, flags);
+		return 0;
 	}
+	cpu_clear(cpu, data->cpu_event);
+	if (data->saved_num) {
+		shift1_data_saved(data, data->saved_num - 1);
+		data->saved_num = 0;
+	}
+	spin_unlock_irqrestore(&data_saved_lock, flags);
 	rh = (sal_log_record_header_t *)(data->log_buffer);
 	/* Corrected errors have already been cleared from SAL */
 	if (rh->severity != sal_log_severity_corrected)
 		call_on_cpu(cpu, salinfo_log_clear_cpu, data);
 	/* clearing a record may make a new record visible */
 	salinfo_log_new_read(cpu, data);
-	if (data->state == STATE_LOG_RECORD &&
-	    !test_and_set_bit(cpu,  &data->cpu_event))
-		up(&data->sem);
+	if (data->state == STATE_LOG_RECORD) {
+		spin_lock_irqsave(&data_saved_lock, flags);
+		cpu_set(cpu, data->cpu_event);
+		salinfo_work_to_do(data);
+		spin_unlock_irqrestore(&data_saved_lock, flags);
+	}
 	return 0;
 }
 
@@ -550,6 +571,53 @@
 	.write   = salinfo_log_write,
 };
 
+#ifdef	CONFIG_HOTPLUG_CPU
+static int __devinit
+salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+	unsigned int i, cpu = (unsigned long)hcpu;
+	unsigned long flags;
+	struct salinfo_data *data;
+	switch (action) {
+	case CPU_ONLINE:
+		spin_lock_irqsave(&data_saved_lock, flags);
+		for (i = 0, data = salinfo_data;
+		     i < ARRAY_SIZE(salinfo_data);
+		     ++i, ++data) {
+			cpu_set(cpu, data->cpu_event);
+			salinfo_work_to_do(data);
+		}
+		spin_unlock_irqrestore(&data_saved_lock, flags);
+		break;
+	case CPU_DEAD:
+		spin_lock_irqsave(&data_saved_lock, flags);
+		for (i = 0, data = salinfo_data;
+		     i < ARRAY_SIZE(salinfo_data);
+		     ++i, ++data) {
+			struct salinfo_data_saved *data_saved;
+			int j;
+			for (j = ARRAY_SIZE(data->data_saved) - 1, data_saved = data->data_saved + j;
+			     j >= 0;
+			     --j, --data_saved) {
+				if (data_saved->buffer && data_saved->cpu == cpu) {
+					shift1_data_saved(data, j);
+				}
+			}
+			cpu_clear(cpu, data->cpu_event);
+		}
+		spin_unlock_irqrestore(&data_saved_lock, flags);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block salinfo_cpu_notifier =
+{
+	.notifier_call = salinfo_cpu_callback,
+	.priority = 0,
+};
+#endif	/* CONFIG_HOTPLUG_CPU */
+
 static int __init
 salinfo_init(void)
 {
@@ -557,7 +625,7 @@
 	struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */
 	struct proc_dir_entry *dir, *entry;
 	struct salinfo_data *data;
-	int i, j, online;
+	int i, j;
 
 	salinfo_dir = proc_mkdir("sal", NULL);
 	if (!salinfo_dir)
@@ -572,7 +640,7 @@
 	for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
 		data = salinfo_data + i;
 		data->type = i;
-		sema_init(&data->sem, 0);
+		init_MUTEX(&data->mutex);
 		dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
 		if (!dir)
 			continue;
@@ -592,12 +660,8 @@
 		*sdir++ = entry;
 
 		/* we missed any events before now */
-		online = 0;
-		for_each_online_cpu(j) {
-			set_bit(j, &data->cpu_event);
-			++online;
-		}
-		sema_init(&data->sem, online);
+		for_each_online_cpu(j)
+			cpu_set(j, data->cpu_event);
 
 		*sdir++ = dir;
 	}
@@ -609,6 +673,10 @@
 	salinfo_timer.function = &salinfo_timeout;
 	add_timer(&salinfo_timer);
 
+#ifdef	CONFIG_HOTPLUG_CPU
+	register_cpu_notifier(&salinfo_cpu_notifier);
+#endif
+
 	return 0;
 }
 
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index d3e0ecb..5539190 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -530,12 +530,15 @@
 		if (fsys_mode(current, &regs)) {
 			extern char __kernel_syscall_via_break[];
 			/*
-			 * Got a trap in fsys-mode: Taken Branch Trap and Single Step trap
-			 * need special handling; Debug trap is not supposed to happen.
+			 * Got a trap in fsys-mode: Taken Branch Trap
+			 * and Single Step trap need special handling;
+			 * Debug trap is ignored (we disable it here
+			 * and re-enable it in the lower-privilege trap).
 			 */
 			if (unlikely(vector == 29)) {
-				die("Got debug trap in fsys-mode---not supposed to happen!",
-				    &regs, 0);
+				set_thread_flag(TIF_DB_DISABLED);
+				ia64_psr(&regs)->db = 0;
+				ia64_psr(&regs)->lp = 1;
 				return;
 			}
 			/* re-do the system call via break 0x100000: */
@@ -589,10 +592,19 @@
 	      case 34:
 		if (isr & 0x2) {
 			/* Lower-Privilege Transfer Trap */
+
+			/* If we disabled debug traps during an fsyscall,
+			 * re-enable them here.
+			 */
+			if (test_thread_flag(TIF_DB_DISABLED)) {
+				clear_thread_flag(TIF_DB_DISABLED);
+				ia64_psr(&regs)->db = 1;
+			}
+
 			/*
-			 * Just clear PSR.lp and then return immediately: all the
-			 * interesting work (e.g., signal delivery is done in the kernel
-			 * exit path).
+			 * Just clear PSR.lp and then return immediately:
+			 * all the interesting work (e.g., signal delivery)
+			 * is done in the kernel exit path.
 			 */
 			ia64_psr(&regs)->lp = 0;
 			return;
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index 41105d4..6a4eec9 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -90,7 +90,7 @@
 {
 	static DEFINE_SPINLOCK(ptcg_lock);
 
-	if (mm != current->active_mm) {
+	if (mm != current->active_mm || !current->mm) {
 		flush_tlb_all();
 		return;
 	}
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
index 71c2b27..4d417c3 100644
--- a/arch/ia64/sn/include/xtalk/hubdev.h
+++ b/arch/ia64/sn/include/xtalk/hubdev.h
@@ -26,11 +26,14 @@
 #define IIO_NUM_ITTES   7
 #define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
 
-struct sn_flush_device_list {
+/* This struct is shared between the PROM and the kernel.
+ * Changes to this struct will require corresponding changes to the kernel.
+ */
+struct sn_flush_device_common {
 	int sfdl_bus;
 	int sfdl_slot;
 	int sfdl_pin;
-	struct bar_list {
+	struct common_bar_list {
 		unsigned long start;
 		unsigned long end;
 	} sfdl_bar_list[6];
@@ -40,14 +43,19 @@
 	uint32_t sfdl_persistent_busnum;
 	uint32_t sfdl_persistent_segment;
 	struct pcibus_info *sfdl_pcibus_info;
+};
+
+/* This struct is kernel only and is not used by the PROM */
+struct sn_flush_device_kernel {
 	spinlock_t sfdl_flush_lock;
+	struct sn_flush_device_common *common;
 };
 
 /*
- * **widget_p - Used as an array[wid_num][device] of sn_flush_device_list.
+ * **widget_p - Used as an array[wid_num][device] of sn_flush_device_kernel.
  */
 struct sn_flush_nasid_entry  {
-	struct sn_flush_device_list **widget_p; /* Used as a array of wid_num */
+	struct sn_flush_device_kernel **widget_p; // Used as an array of wid_num
 	uint64_t iio_itte[8];
 };
 
diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c
index fcbc748..f1ec137 100644
--- a/arch/ia64/sn/kernel/bte_error.c
+++ b/arch/ia64/sn/kernel/bte_error.c
@@ -33,7 +33,7 @@
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-void shub1_bte_error_handler(unsigned long _nodepda)
+int shub1_bte_error_handler(unsigned long _nodepda)
 {
 	struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
 	struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
@@ -53,7 +53,7 @@
 	    (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
 		BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
 			    smp_processor_id()));
-		return;
+		return 1;
 	}
 
 	/* Determine information about our hub */
@@ -81,7 +81,7 @@
 		mod_timer(recovery_timer, HZ * 5);
 		BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
 			    smp_processor_id()));
-		return;
+		return 1;
 	}
 	if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
 
@@ -99,7 +99,7 @@
 				BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
 					    err_nodepda, smp_processor_id(),
 					    i));
-				return;
+				return 1;
 			}
 		}
 	}
@@ -124,6 +124,42 @@
 	REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
 
 	del_timer(recovery_timer);
+	return 0;
+}
+
+/*
+ * Wait until all BTE related CRBs are completed
+ * and then reset the interfaces.
+ */
+int shub2_bte_error_handler(unsigned long _nodepda)
+{
+	struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
+	struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
+	struct bteinfo_s *bte;
+	nasid_t nasid;
+	u64 status;
+	int i;
+
+	nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
+
+	/*
+	 * Verify that all the BTEs are complete
+	 */
+	for (i = 0; i < BTES_PER_NODE; i++) {
+		bte = &err_nodepda->bte_if[i];
+		status = BTE_LNSTAT_LOAD(bte);
+		if ((status & IBLS_ERROR) || !(status & IBLS_BUSY))
+			continue;
+		mod_timer(recovery_timer, HZ * 5);
+		BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
+			    smp_processor_id()));
+		return 1;
+	}
+	if (ia64_sn_bte_recovery(nasid))
+		panic("bte_error_handler(): Fatal BTE Error");
+
+	del_timer(recovery_timer);
+	return 0;
 }
 
 /*
@@ -135,7 +171,6 @@
 	struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
 	spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
 	int i;
-	nasid_t nasid;
 	unsigned long irq_flags;
 	volatile u64 *notify;
 	bte_result_t bh_error;
@@ -160,12 +195,15 @@
 	}
 
 	if (is_shub1()) {
-		shub1_bte_error_handler(_nodepda);
+		if (shub1_bte_error_handler(_nodepda)) {
+			spin_unlock_irqrestore(recovery_lock, irq_flags);
+			return;
+		}
 	} else {
-		nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
-
-		if (ia64_sn_bte_recovery(nasid))
-			panic("bte_error_handler(): Fatal BTE Error");
+		if (shub2_bte_error_handler(_nodepda)) {
+			spin_unlock_irqrestore(recovery_lock, irq_flags);
+			return;
+		}
 	}
 
 	for (i = 0; i < BTES_PER_NODE; i++) {
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index 5c5eb01..56ab6ba 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -32,13 +32,14 @@
 	ret_stuff.v0 = 0;
 	hubdev_info = (struct hubdev_info *)arg;
 	nasid = hubdev_info->hdi_nasid;
-	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
-			(u64) nasid, 0, 0, 0, 0, 0, 0);
-
-	if ((int)ret_stuff.v0)
-		panic("hubii_eint_handler(): Fatal TIO Error");
 
 	if (is_shub1()) {
+		SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+			(u64) nasid, 0, 0, 0, 0, 0, 0);
+
+		if ((int)ret_stuff.v0)
+			panic("hubii_eint_handler(): Fatal TIO Error");
+
 		if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
 			(void)hubiio_crb_error_handler(hubdev_info);
 	} else 
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 318087e..258d9d7 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -76,11 +76,12 @@
 };
 
 /*
- * Retrieve the DMA Flush List given nasid.  This list is needed 
- * to implement the WAR - Flush DMA data on PIO Reads.
+ * Retrieve the DMA Flush List given nasid, widget, and device.
+ * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
  */
-static inline uint64_t
-sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
+static inline u64
+sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
+			     u64 address)
 {
 
 	struct ia64_sal_retval ret_stuff;
@@ -88,17 +89,17 @@
 	ret_stuff.v0 = 0;
 
 	SAL_CALL_NOLOCK(ret_stuff,
-			(u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
-			(u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0,
-			0);
-	return ret_stuff.v0;
+			(u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
+			(u64) nasid, (u64) widget_num,
+			(u64) device_num, (u64) address, 0, 0, 0);
+	return ret_stuff.status;
 
 }
 
 /*
  * Retrieve the hub device info structure for the given nasid.
  */
-static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
+static inline u64 sal_get_hubdev_info(u64 handle, u64 address)
 {
 
 	struct ia64_sal_retval ret_stuff;
@@ -114,7 +115,7 @@
 /*
  * Retrieve the pci bus information given the bus number.
  */
-static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
+static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 {
 
 	struct ia64_sal_retval ret_stuff;
@@ -130,7 +131,7 @@
 /*
  * Retrieve the pci device information given the bus and device|function number.
  */
-static inline uint64_t
+static inline u64
 sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 
 			u64 sn_irq_info)
 {
@@ -170,12 +171,12 @@
  */
 static void sn_fixup_ionodes(void)
 {
-
-	struct sn_flush_device_list *sn_flush_device_list;
+	struct sn_flush_device_kernel *sn_flush_device_kernel;
+	struct sn_flush_device_kernel *dev_entry;
 	struct hubdev_info *hubdev;
-	uint64_t status;
-	uint64_t nasid;
-	int i, widget;
+	u64 status;
+	u64 nasid;
+	int i, widget, device;
 
 	/*
 	 * Get SGI Specific HUB chipset information.
@@ -186,7 +187,7 @@
 		nasid = cnodeid_to_nasid(i);
 		hubdev->max_segment_number = 0xffffffff;
 		hubdev->max_pcibus_number = 0xff;
-		status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
+		status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev));
 		if (status)
 			continue;
 
@@ -213,38 +214,49 @@
 
 		hubdev->hdi_flush_nasid_list.widget_p =
 		    kmalloc((HUB_WIDGET_ID_MAX + 1) *
-			    sizeof(struct sn_flush_device_list *), GFP_KERNEL);
-
+			    sizeof(struct sn_flush_device_kernel *),
+			    GFP_KERNEL);
 		memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
 		       (HUB_WIDGET_ID_MAX + 1) *
-		       sizeof(struct sn_flush_device_list *));
+		       sizeof(struct sn_flush_device_kernel *));
 
 		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
-			sn_flush_device_list = kmalloc(DEV_PER_WIDGET *
-						       sizeof(struct
-							      sn_flush_device_list),
-						       GFP_KERNEL);
-			memset(sn_flush_device_list, 0x0,
+			sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET *
+						         sizeof(struct
+						        sn_flush_device_kernel),
+						        GFP_KERNEL);
+			if (!sn_flush_device_kernel)
+				BUG();
+			memset(sn_flush_device_kernel, 0x0,
 			       DEV_PER_WIDGET *
-			       sizeof(struct sn_flush_device_list));
+			       sizeof(struct sn_flush_device_kernel));
 
-			status =
-			    sal_get_widget_dmaflush_list(nasid, widget,
-							 (uint64_t)
-							 __pa
-							 (sn_flush_device_list));
-			if (status) {
-				kfree(sn_flush_device_list);
-				continue;
+			dev_entry = sn_flush_device_kernel;
+			for (device = 0; device < DEV_PER_WIDGET;
+			     device++,dev_entry++) {
+				dev_entry->common = kmalloc(sizeof(struct
+					      	        sn_flush_device_common),
+					                    GFP_KERNEL);
+				if (!dev_entry->common)
+					BUG();
+				memset(dev_entry->common, 0x0, sizeof(struct
+					     	       sn_flush_device_common));
+
+				status = sal_get_device_dmaflush_list(nasid,
+									widget,
+								       	device,
+						      (u64)(dev_entry->common));
+				if (status)
+					BUG();
+
+				spin_lock_init(&dev_entry->sfdl_flush_lock);
 			}
 
-			spin_lock_init(&sn_flush_device_list->sfdl_flush_lock);
-			hubdev->hdi_flush_nasid_list.widget_p[widget] =
-			    sn_flush_device_list;
-		}
-
+			if (sn_flush_device_kernel)
+				hubdev->hdi_flush_nasid_list.widget_p[widget] =
+						       sn_flush_device_kernel;
+	        }
 	}
-
 }
 
 /*
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 493fb3f..6a7939b 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -77,12 +77,6 @@
 	kfree(to_cx_dev(dev));
 }
 
-struct bus_type tiocx_bus_type = {
-	.name = "tiocx",
-	.match = tiocx_match,
-	.uevent = tiocx_uevent,
-};
-
 /**
  * cx_device_match - Find cx_device in the id table.
  * @ids: id table from driver
@@ -149,6 +143,14 @@
 	return 0;
 }
 
+struct bus_type tiocx_bus_type = {
+	.name = "tiocx",
+	.match = tiocx_match,
+	.uevent = tiocx_uevent,
+	.probe = cx_device_probe,
+	.remove = cx_driver_remove,
+};
+
 /**
  * cx_driver_register - Register the driver.
  * @cx_driver: driver table (cx_drv struct) from driver
@@ -162,8 +164,6 @@
 {
 	cx_driver->driver.name = cx_driver->name;
 	cx_driver->driver.bus = &tiocx_bus_type;
-	cx_driver->driver.probe = cx_device_probe;
-	cx_driver->driver.remove = cx_driver_remove;
 
 	return driver_register(&cx_driver->driver);
 }
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c
index abf4fc2..0c0a689 100644
--- a/arch/ia64/sn/kernel/xpc_channel.c
+++ b/arch/ia64/sn/kernel/xpc_channel.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -24,7 +24,7 @@
 #include <linux/slab.h>
 #include <asm/sn/bte.h>
 #include <asm/sn/sn_sal.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /*
@@ -779,6 +779,12 @@
 
 	/* both sides are disconnected now */
 
+	if (ch->flags & XPC_C_CONNECTCALLOUT) {
+		spin_unlock_irqrestore(&ch->lock, *irq_flags);
+		xpc_disconnect_callout(ch, xpcDisconnected);
+		spin_lock_irqsave(&ch->lock, *irq_flags);
+	}
+
 	/* it's now safe to free the channel's message queues */
 	xpc_free_msgqueues(ch);
 
@@ -1645,7 +1651,7 @@
 
 
 void
-xpc_disconnecting_callout(struct xpc_channel *ch)
+xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason)
 {
 	/*
 	 * Let the channel's registerer know that the channel is being
@@ -1654,15 +1660,13 @@
 	 */
 
 	if (ch->func != NULL) {
-		dev_dbg(xpc_chan, "ch->func() called, reason=xpcDisconnecting,"
-			" partid=%d, channel=%d\n", ch->partid, ch->number);
+		dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, "
+			"channel=%d\n", reason, ch->partid, ch->number);
 
-		ch->func(xpcDisconnecting, ch->partid, ch->number, NULL,
-								ch->key);
+		ch->func(reason, ch->partid, ch->number, NULL, ch->key);
 
-		dev_dbg(xpc_chan, "ch->func() returned, reason="
-			"xpcDisconnecting, partid=%d, channel=%d\n",
-			ch->partid, ch->number);
+		dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, "
+			"channel=%d\n", reason, ch->partid, ch->number);
 	}
 }
 
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index b617236..8930586e 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -59,7 +59,7 @@
 #include <asm/sn/sn_sal.h>
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /* define two XPC debug device structures to be used with dev_dbg() et al */
@@ -82,6 +82,9 @@
 struct device *xpc_chan = &xpc_chan_dbg_subname;
 
 
+static int xpc_kdebug_ignore;
+
+
 /* systune related variables for /proc/sys directories */
 
 static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
@@ -162,6 +165,8 @@
 };
 static struct ctl_table_header *xpc_sysctl;
 
+/* non-zero if any remote partition disengage request was timed out */
+int xpc_disengage_request_timedout;
 
 /* #of IRQs received */
 static atomic_t xpc_act_IRQ_rcvd;
@@ -773,7 +778,7 @@
 			ch->flags |= XPC_C_DISCONNECTCALLOUT;
 			spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-			xpc_disconnecting_callout(ch);
+			xpc_disconnect_callout(ch, xpcDisconnecting);
 		} else {
 			spin_unlock_irqrestore(&ch->lock, irq_flags);
 		}
@@ -921,9 +926,9 @@
 xpc_do_exit(enum xpc_retval reason)
 {
 	partid_t partid;
-	int active_part_count;
+	int active_part_count, printed_waiting_msg = 0;
 	struct xpc_partition *part;
-	unsigned long printmsg_time;
+	unsigned long printmsg_time, disengage_request_timeout = 0;
 
 
 	/* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
@@ -953,7 +958,8 @@
 
 	/* wait for all partitions to become inactive */
 
-	printmsg_time = jiffies;
+	printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+	xpc_disengage_request_timedout = 0;
 
 	do {
 		active_part_count = 0;
@@ -969,20 +975,39 @@
 			active_part_count++;
 
 			XPC_DEACTIVATE_PARTITION(part, reason);
+
+			if (part->disengage_request_timeout >
+						disengage_request_timeout) {
+				disengage_request_timeout =
+						part->disengage_request_timeout;
+			}
 		}
 
-		if (active_part_count == 0) {
-			break;
-		}
-
-		if (jiffies >= printmsg_time) {
-			dev_info(xpc_part, "waiting for partitions to "
-				"deactivate/disengage, active count=%d, remote "
-				"engaged=0x%lx\n", active_part_count,
-				xpc_partition_engaged(1UL << partid));
-
-			printmsg_time = jiffies +
+		if (xpc_partition_engaged(-1UL)) {
+			if (time_after(jiffies, printmsg_time)) {
+				dev_info(xpc_part, "waiting for remote "
+					"partitions to disengage, timeout in "
+					"%ld seconds\n",
+					(disengage_request_timeout - jiffies)
+									/ HZ);
+				printmsg_time = jiffies +
 					(XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+				printed_waiting_msg = 1;
+			}
+
+		} else if (active_part_count > 0) {
+			if (printed_waiting_msg) {
+				dev_info(xpc_part, "waiting for local partition"
+					" to disengage\n");
+				printed_waiting_msg = 0;
+			}
+
+		} else {
+			if (!xpc_disengage_request_timedout) {
+				dev_info(xpc_part, "all partitions have "
+					"disengaged\n");
+			}
+			break;
 		}
 
 		/* sleep for a 1/3 of a second or so */
@@ -1000,11 +1025,13 @@
 	del_timer_sync(&xpc_hb_timer);
 	DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
 
-	/* take ourselves off of the reboot_notifier_list */
-	(void) unregister_reboot_notifier(&xpc_reboot_notifier);
+	if (reason == xpcUnloading) {
+		/* take ourselves off of the reboot_notifier_list */
+		(void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
-	/* take ourselves off of the die_notifier list */
-	(void) unregister_die_notifier(&xpc_die_notifier);
+		/* take ourselves off of the die_notifier list */
+		(void) unregister_die_notifier(&xpc_die_notifier);
+	}
 
 	/* close down protections for IPI operations */
 	xpc_restrict_IPI_ops();
@@ -1020,63 +1047,6 @@
 
 
 /*
- * Called when the system is about to be either restarted or halted.
- */
-static void
-xpc_die_disengage(void)
-{
-	struct xpc_partition *part;
-	partid_t partid;
-	unsigned long engaged;
-	long time, print_time, disengage_request_timeout;
-
-
-	/* keep xpc_hb_checker thread from doing anything (just in case) */
-	xpc_exiting = 1;
-
-	xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */
-
-	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
-		part = &xpc_partitions[partid];
-
-		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
-							remote_vars_version)) {
-
-			/* just in case it was left set by an earlier XPC */
-			xpc_clear_partition_engaged(1UL << partid);
-			continue;
-		}
-
-		if (xpc_partition_engaged(1UL << partid) ||
-					part->act_state != XPC_P_INACTIVE) {
-			xpc_request_partition_disengage(part);
-			xpc_mark_partition_disengaged(part);
-			xpc_IPI_send_disengage(part);
-		}
-	}
-
-	print_time = rtc_time();
-	disengage_request_timeout = print_time +
-		(xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
-
-	/* wait for all other partitions to disengage from us */
-
-	while ((engaged = xpc_partition_engaged(-1UL)) &&
-			(time = rtc_time()) < disengage_request_timeout) {
-
-		if (time >= print_time) {
-			dev_info(xpc_part, "waiting for remote partitions to "
-				"disengage, engaged=0x%lx\n", engaged);
-			print_time = time + (XPC_DISENGAGE_PRINTMSG_INTERVAL *
-						sn_rtc_cycles_per_second);
-		}
-	}
-	dev_info(xpc_part, "finished waiting for remote partitions to "
-				"disengage, engaged=0x%lx\n", engaged);
-}
-
-
-/*
  * This function is called when the system is being rebooted.
  */
 static int
@@ -1105,7 +1075,88 @@
 
 
 /*
- * This function is called when the system is being rebooted.
+ * Notify other partitions to disengage from all references to our memory.
+ */
+static void
+xpc_die_disengage(void)
+{
+	struct xpc_partition *part;
+	partid_t partid;
+	unsigned long engaged;
+	long time, printmsg_time, disengage_request_timeout;
+
+
+	/* keep xpc_hb_checker thread from doing anything (just in case) */
+	xpc_exiting = 1;
+
+	xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */
+
+	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+		part = &xpc_partitions[partid];
+
+		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
+							remote_vars_version)) {
+
+			/* just in case it was left set by an earlier XPC */
+			xpc_clear_partition_engaged(1UL << partid);
+			continue;
+		}
+
+		if (xpc_partition_engaged(1UL << partid) ||
+					part->act_state != XPC_P_INACTIVE) {
+			xpc_request_partition_disengage(part);
+			xpc_mark_partition_disengaged(part);
+			xpc_IPI_send_disengage(part);
+		}
+	}
+
+	time = rtc_time();
+	printmsg_time = time +
+		(XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);
+	disengage_request_timeout = time +
+		(xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
+
+	/* wait for all other partitions to disengage from us */
+
+	while (1) {
+		engaged = xpc_partition_engaged(-1UL);
+		if (!engaged) {
+			dev_info(xpc_part, "all partitions have disengaged\n");
+			break;
+		}
+
+		time = rtc_time();
+		if (time >= disengage_request_timeout) {
+			for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+				if (engaged & (1UL << partid)) {
+					dev_info(xpc_part, "disengage from "
+						"remote partition %d timed "
+						"out\n", partid);
+				}
+			}
+			break;
+		}
+
+		if (time >= printmsg_time) {
+			dev_info(xpc_part, "waiting for remote partitions to "
+				"disengage, timeout in %ld seconds\n",
+				(disengage_request_timeout - time) /
+						sn_rtc_cycles_per_second);
+			printmsg_time = time +
+					(XPC_DISENGAGE_PRINTMSG_INTERVAL *
+						sn_rtc_cycles_per_second);
+		}
+	}
+}
+
+
+/*
+ * This function is called when the system is being restarted or halted due
+ * to some sort of system failure. If this is the case we need to notify the
+ * other partitions to disengage from all references to our memory.
+ * This function can also be called when our heartbeater could be offlined
+ * for a time. In this case we need to notify other partitions to not worry
+ * about the lack of a heartbeat.
  */
 static int
 xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
@@ -1115,11 +1166,25 @@
 	case DIE_MACHINE_HALT:
 		xpc_die_disengage();
 		break;
+
+	case DIE_KDEBUG_ENTER:
+		/* Should lack of heartbeat be ignored by other partitions? */
+		if (!xpc_kdebug_ignore) {
+			break;
+		}
+		/* fall through */
 	case DIE_MCA_MONARCH_ENTER:
 	case DIE_INIT_MONARCH_ENTER:
 		xpc_vars->heartbeat++;
 		xpc_vars->heartbeat_offline = 1;
 		break;
+
+	case DIE_KDEBUG_LEAVE:
+		/* Is lack of heartbeat being ignored by other partitions? */
+		if (!xpc_kdebug_ignore) {
+			break;
+		}
+		/* fall through */
 	case DIE_MCA_MONARCH_LEAVE:
 	case DIE_INIT_MONARCH_LEAVE:
 		xpc_vars->heartbeat++;
@@ -1344,3 +1409,7 @@
 MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait "
 		"for disengage request to complete.");
 
+module_param(xpc_kdebug_ignore, int, 0);
+MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
+		"other partitions when dropping into kdebug.");
+
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c
index cdd6431..88a730e 100644
--- a/arch/ia64/sn/kernel/xpc_partition.c
+++ b/arch/ia64/sn/kernel/xpc_partition.c
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -28,7 +28,7 @@
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/addrs.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /* XPC is exiting flag */
@@ -771,7 +771,8 @@
 		}
 	}
 
-	if (!xpc_partition_disengaged(part)) {
+	if (part->disengage_request_timeout > 0 &&
+					!xpc_partition_disengaged(part)) {
 		/* still waiting on other side to disengage from us */
 		return;
 	}
@@ -873,6 +874,9 @@
 			 * request in a timely fashion, so assume it's dead.
 			 */
 
+			dev_info(xpc_part, "disengage from remote partition %d "
+				"timed out\n", partid);
+			xpc_disengage_request_timedout = 1;
 			xpc_clear_partition_engaged(1UL << partid);
 			disengaged = 1;
 		}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index 3409347..e68332d 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -218,7 +218,9 @@
 	uint64_t flags;
 	uint64_t itte;
 	struct hubdev_info *hubinfo;
-	volatile struct sn_flush_device_list *p;
+	volatile struct sn_flush_device_kernel *p;
+	volatile struct sn_flush_device_common *common;
+
 	struct sn_flush_nasid_entry *flush_nasid_list;
 
 	if (!sn_ioif_inited)
@@ -268,17 +270,17 @@
 	p = &flush_nasid_list->widget_p[wid_num][0];
 
 	/* find a matching BAR */
-	for (i = 0; i < DEV_PER_WIDGET; i++) {
+	for (i = 0; i < DEV_PER_WIDGET; i++,p++) {
+		common = p->common;
 		for (j = 0; j < PCI_ROM_RESOURCE; j++) {
-			if (p->sfdl_bar_list[j].start == 0)
+			if (common->sfdl_bar_list[j].start == 0)
 				break;
-			if (addr >= p->sfdl_bar_list[j].start
-			    && addr <= p->sfdl_bar_list[j].end)
+			if (addr >= common->sfdl_bar_list[j].start
+			    && addr <= common->sfdl_bar_list[j].end)
 				break;
 		}
-		if (j < PCI_ROM_RESOURCE && p->sfdl_bar_list[j].start != 0)
+		if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0)
 			break;
-		p++;
 	}
 
 	/* if no matching BAR, return without doing anything. */
@@ -304,24 +306,24 @@
 		if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) {
 			return;
 		} else {
-			pcireg_wrb_flush_get(p->sfdl_pcibus_info,
-					     (p->sfdl_slot - 1));
+			pcireg_wrb_flush_get(common->sfdl_pcibus_info,
+					     (common->sfdl_slot - 1));
 		}
 	} else {
-		spin_lock_irqsave(&((struct sn_flush_device_list *)p)->
-				  sfdl_flush_lock, flags);
-
-		*p->sfdl_flush_addr = 0;
+		spin_lock_irqsave((spinlock_t *)&p->sfdl_flush_lock,
+				  flags);
+		*common->sfdl_flush_addr = 0;
 
 		/* force an interrupt. */
-		*(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
+		*(volatile uint32_t *)(common->sfdl_force_int_addr) = 1;
 
 		/* wait for the interrupt to come back. */
-		while (*(p->sfdl_flush_addr) != 0x10f)
+		while (*(common->sfdl_flush_addr) != 0x10f)
 			cpu_relax();
 
 		/* okay, everything is synched up. */
-		spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
+		spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock,
+				       flags);
 	}
 	return;
 }
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 1f500c8..e328e94 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -92,7 +92,8 @@
 	cnodeid_t near_cnode;
 	struct hubdev_info *hubdev_info;
 	struct pcibus_info *soft;
-	struct sn_flush_device_list *sn_flush_device_list;
+	struct sn_flush_device_kernel *sn_flush_device_kernel;
+	struct sn_flush_device_common *common;
 
 	if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {
 		return NULL;
@@ -137,20 +138,19 @@
 	hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
 
 	if (hubdev_info->hdi_flush_nasid_list.widget_p) {
-		sn_flush_device_list = hubdev_info->hdi_flush_nasid_list.
+		sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list.
 		    widget_p[(int)soft->pbi_buscommon.bs_xid];
-		if (sn_flush_device_list) {
+		if (sn_flush_device_kernel) {
 			for (j = 0; j < DEV_PER_WIDGET;
-			     j++, sn_flush_device_list++) {
-				if (sn_flush_device_list->sfdl_slot == -1)
+			     j++, sn_flush_device_kernel++) {
+				common = sn_flush_device_kernel->common;
+				if (common->sfdl_slot == -1)
 					continue;
-				if ((sn_flush_device_list->
-				     sfdl_persistent_segment ==
+				if ((common->sfdl_persistent_segment ==
 				     soft->pbi_buscommon.bs_persist_segment) &&
-				     (sn_flush_device_list->
-				     sfdl_persistent_busnum ==
+				     (common->sfdl_persistent_busnum ==
 				     soft->pbi_buscommon.bs_persist_busnum))
-					sn_flush_device_list->sfdl_pcibus_info =
+					common->sfdl_pcibus_info =
 					    soft;
 			}
 		}
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 1eaa0d3..2d804e2 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -173,8 +173,6 @@
 	WARN_ON(driver->drv.probe != NULL);
 	WARN_ON(driver->drv.remove != NULL);
 
-	driver->drv.probe = parisc_driver_probe;
-	driver->drv.remove = parisc_driver_remove;
 	driver->drv.name = driver->name;
 
 	return driver_register(&driver->drv);
@@ -575,6 +573,8 @@
 	.name = "parisc",
 	.match = parisc_generic_match,
 	.dev_attrs = parisc_device_attrs,
+	.probe = parisc_driver_probe,
+	.remove = parisc_driver_remove,
 };
 
 /**
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index d3654a2..44dd82b 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -139,17 +139,14 @@
 
 drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
 
-defaultimage-$(CONFIG_PPC32)	:= zImage
+# Default to zImage, override when needed
+defaultimage-y			:= zImage
 defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux
-defaultimage-$(CONFIG_PPC_PSERIES) := zImage
 KBUILD_IMAGE := $(defaultimage-y)
 all: $(KBUILD_IMAGE)
 
 CPPFLAGS_vmlinux.lds	:= -Upowerpc
 
-# All the instructions talk about "make bzImage".
-bzImage: zImage
-
 BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
 
 .PHONY: $(BOOT_TARGETS)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index b53d677..788dec4 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -25,8 +25,8 @@
 BOOTCFLAGS	:= $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
 		   $(shell $(CROSS32CC) -print-file-name=include) -fPIC
 BOOTAFLAGS	:= -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
-BOOTLFLAGS	:= -T $(srctree)/$(src)/zImage.lds
 OBJCOPYFLAGS    := contents,alloc,load,readonly,data
+OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
 
 zlib       := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
 zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
@@ -35,7 +35,7 @@
 $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
 
-src-boot := string.S prom.c main.c div64.S crt0.S
+src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
 src-boot += $(zlib)
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -70,7 +70,7 @@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootld = BOOTLD  $@
-      cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
+      cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
 
 $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
 	$(call if_changed_dep,bootcc)
@@ -87,12 +87,14 @@
 src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
 gz-sec  = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
 
-hostprogs-y		:= addnote addRamDisk
-targets 		+= zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
-			   $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
-			   $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
-			   $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
-			   vmlinux.initrd
+hostprogs-y		:= addnote addRamDisk hack-coff
+
+targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
+	   zImage.coff zImage.initrd.coff \
+	   $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
+	   $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
+	   $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
+	   vmlinux.initrd
 extra-y			:= initrd.o
 
 quiet_cmd_ramdisk = RAMDISK $@
@@ -114,6 +116,10 @@
 quiet_cmd_addnote = ADDNOTE $@
       cmd_addnote = $(obj)/addnote $@
 
+quiet_cmd_gencoff = COFF    $@
+      cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
+		    $(obj)/hack-coff $@
+
 $(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
 	$(call if_changed,gzip)
 
@@ -127,22 +133,35 @@
 	$(call if_changed_dep,bootcc)
 	$(call cmd,addsection)
 
-$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required))
+$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
 $(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
-	$(call cmd,bootld,$(obj-boot))
+	$(call cmd,bootld,$(obj-boot),zImage.lds)
 
-$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
+$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
 $(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
-	$(call cmd,bootld,$(obj-boot))
+	$(call cmd,bootld,$(obj-boot),zImage.lds)
 
-$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
+# For 32-bit powermacs, build the COFF images as well as the ELF images.
+coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
+coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
+
+$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y)
 	@cp -f $< $@
 	$(call if_changed,addnote)
 
-$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
+$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote $(coffrdimg-y-y)
 	@cp -f $< $@
 	$(call if_changed,addnote)
 
+$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+	$(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+	$(call cmd,gencoff)
+
+$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
+			   $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+	$(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+	$(call cmd,gencoff)
+
 #-----------------------------------------------------------
 # build u-boot images
 #-----------------------------------------------------------
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index d2f2ace..e0192c2 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -12,17 +12,23 @@
 #include "ppc_asm.h"
 
 	.text
+	/* a procedure descriptor used when booting this as a COFF file */
+_zimage_start_opd:
+	.long	_zimage_start, 0, 0, 0
+
 	.globl	_zimage_start
 _zimage_start:
+	/* Work out the offset between the address we were linked at
+	   and the address where we're running. */
 	bl	1f
-
-1:
-	mflr	r0
+1:	mflr	r0
 	lis	r9,1b@ha
 	addi	r9,r9,1b@l
 	subf.	r0,r9,r0
-	beq	3f
+	beq	3f		/* if running at same address as linked */
 
+	/* The .got2 section contains a list of addresses, so add
+	   the address offset onto each entry. */
 	lis	r9,__got2_start@ha
 	addi	r9,r9,__got2_start@l
 	lis	r8,__got2_end@ha
@@ -32,15 +38,14 @@
 	srwi.	r8,r8,2
 	mtctr	r8
 	add	r9,r0,r9
-2:
-	lwz	r8,0(r9)
+2:	lwz	r8,0(r9)
 	add	r8,r8,r0
 	stw	r8,0(r9)
 	addi	r9,r9,4
 	bdnz	2b
 
-3:
-	lis	r9,_start@h
+	/* Do a cache flush for our text, in case OF didn't */
+3:	lis	r9,_start@h
 	add	r9,r0,r9
 	lis	r8,_etext@ha
 	addi	r8,r8,_etext@l
diff --git a/arch/powerpc/boot/hack-coff.c b/arch/powerpc/boot/hack-coff.c
new file mode 100644
index 0000000..5e5a657
--- /dev/null
+++ b/arch/powerpc/boot/hack-coff.c
@@ -0,0 +1,84 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC	0x010b
+
+#define get_16be(x)	((((unsigned char *)(x))[0] << 8) \
+			 + ((unsigned char *)(x))[1])
+#define put_16be(x, v)	(((unsigned char *)(x))[0] = (v) >> 8, \
+			 ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x)	((((unsigned char *)(x))[0] << 24) \
+			 + (((unsigned char *)(x))[1] << 16) \
+			 + (((unsigned char *)(x))[2] << 8) \
+			 + ((unsigned char *)(x))[3])
+
+int
+main(int ac, char **av)
+{
+    int fd;
+    int i, nsect;
+    int aoutsz;
+    struct external_filehdr fhdr;
+    AOUTHDR aout;
+    struct external_scnhdr shdr;
+
+    if (ac != 2) {
+	fprintf(stderr, "Usage: hack-coff coff-file\n");
+	exit(1);
+    }
+    if ((fd = open(av[1], 2)) == -1) {
+	perror(av[2]);
+	exit(1);
+    }
+    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+	goto readerr;
+    i = get_16be(fhdr.f_magic);
+    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+	fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+	exit(1);
+    }
+    aoutsz = get_16be(fhdr.f_opthdr);
+    if (read(fd, &aout, aoutsz) != aoutsz)
+	goto readerr;
+    nsect = get_16be(fhdr.f_nscns);
+    for (i = 0; i < nsect; ++i) {
+	if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+	    goto readerr;
+	if (strcmp(shdr.s_name, ".text") == 0) {
+	    put_16be(aout.o_snentry, i+1);
+	    put_16be(aout.o_sntext, i+1);
+	} else if (strcmp(shdr.s_name, ".data") == 0) {
+	    put_16be(aout.o_sndata, i+1);
+	} else if (strcmp(shdr.s_name, ".bss") == 0) {
+	    put_16be(aout.o_snbss, i+1);
+	}
+    }
+    put_16be(aout.magic, AOUT_MAGIC);
+    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+	|| write(fd, &aout, aoutsz) != aoutsz) {
+	fprintf(stderr, "%s: write error\n", av[1]);
+	exit(1);
+    }
+    close(fd);
+    exit(0);
+
+readerr:
+    fprintf(stderr, "%s: read error or file too short\n", av[1]);
+    exit(1);
+}
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 64ec931..55ec598 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -21,8 +21,8 @@
 
 
 /* Value picked to match that used by yaboot */
-#define PROG_START	0x01400000
-#define RAM_END		(512<<20) // Fixme: use OF */
+#define PROG_START	0x01400000	/* only used on 64-bit systems */
+#define RAM_END		(512<<20)	/* Fixme: use OF */
 #define	ONE_MB		0x100000
 
 extern char _start[];
@@ -160,6 +160,17 @@
 	elfoffset = (unsigned long)elf64ph->p_offset;
 	vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
 	vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
+
+#if defined(PROG_START)
+	/*
+	 * Maintain a "magic" minimum address. This keeps some older
+	 * firmware platforms running.
+	 */
+
+	if (claim_base < PROG_START)
+		claim_base = PROG_START;
+#endif
+
 	return 1;
 }
 
@@ -206,12 +217,18 @@
 		exit();
 	if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
 		exit();
-	stderr = stdout;
-	if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-		exit();
 
 	printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
 
+	/*
+	 * The first available claim_base must be above the end of the
+	 * the loaded kernel wrapper file (_start to _end includes the
+	 * initrd image if it is present) and rounded up to a nice
+	 * 1 MB boundary for good measure.
+	 */
+
+	claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
+
 	vmlinuz.addr = (unsigned long)_vmlinux_start;
 	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 
@@ -228,25 +245,6 @@
 		exit();
 	}
 
-	/*
-	 * The first available claim_base must be above the end of the
-	 * the loaded kernel wrapper file (_start to _end includes the
-	 * initrd image if it is present) and rounded up to a nice
-	 * 1 MB boundary for good measure.
-	 */
-
-	claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
-
-#if defined(PROG_START)
-	/*
-	 * Maintain a "magic" minimum address. This keeps some older
-	 * firmware platforms running.
-	 */
-
-	if (claim_base < PROG_START)
-		claim_base = PROG_START;
-#endif
-
 	/* We need to claim the memsize plus the file offset since gzip
 	 * will expand the header (file offset), then the kernel, then
 	 * possible rubbish we don't care about. But the kernel bss must
diff --git a/arch/powerpc/boot/prom.c b/arch/powerpc/boot/prom.c
index 4bea2f4..fa00577 100644
--- a/arch/powerpc/boot/prom.c
+++ b/arch/powerpc/boot/prom.c
@@ -13,487 +13,153 @@
 #include "prom.h"
 
 int (*prom)(void *);
+phandle chosen_handle;
+ihandle stdout;
 
-void *chosen_handle;
-
-void *stdin;
-void *stdout;
-void *stderr;
-
-
-int
-write(void *handle, void *ptr, int nb)
+int call_prom(const char *service, int nargs, int nret, ...)
 {
+	int i;
 	struct prom_args {
-		char *service;
+		const char *service;
 		int nargs;
 		int nret;
-		void *ihandle;
-		void *addr;
-		int len;
-		int actual;
+		unsigned int args[12];
 	} args;
+	va_list list;
 
-	args.service = "write";
-	args.nargs = 3;
-	args.nret = 1;
-	args.ihandle = handle;
-	args.addr = ptr;
-	args.len = nb;
-	args.actual = -1;
-	(*prom)(&args);
-	return args.actual;
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, nret);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (prom(&args) < 0)
+		return -1;
+
+	return (nret > 0)? args.args[nargs]: 0;
 }
 
-int
-read(void *handle, void *ptr, int nb)
+int call_prom_ret(const char *service, int nargs, int nret,
+		  unsigned int *rets, ...)
 {
+	int i;
 	struct prom_args {
-		char *service;
+		const char *service;
 		int nargs;
 		int nret;
-		void *ihandle;
-		void *addr;
-		int len;
-		int actual;
+		unsigned int args[12];
 	} args;
+	va_list list;
 
-	args.service = "read";
-	args.nargs = 3;
-	args.nret = 1;
-	args.ihandle = handle;
-	args.addr = ptr;
-	args.len = nb;
-	args.actual = -1;
-	(*prom)(&args);
-	return args.actual;
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, rets);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (prom(&args) < 0)
+		return -1;
+
+	if (rets != (void *) 0)
+		for (i = 1; i < nret; ++i)
+			rets[i-1] = args.args[nargs+i];
+
+	return (nret > 0)? args.args[nargs]: 0;
 }
 
-void
-exit()
+int write(void *handle, void *ptr, int nb)
 {
-	struct prom_args {
-		char *service;
-	} args;
-
-	for (;;) {
-		args.service = "exit";
-		(*prom)(&args);
-	}
+	return call_prom("write", 3, 1, handle, ptr, nb);
 }
 
-void
-pause(void)
-{
-	struct prom_args {
-		char *service;
-	} args;
-
-	args.service = "enter";
-	(*prom)(&args);
-}
-
-void *
-finddevice(const char *name)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		const char *devspec;
-		void *phandle;
-	} args;
-
-	args.service = "finddevice";
-	args.nargs = 1;
-	args.nret = 1;
-	args.devspec = name;
-	args.phandle = (void *) -1;
-	(*prom)(&args);
-	return args.phandle;
-}
-
-void *
-claim(unsigned long virt, unsigned long size, unsigned long align)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		unsigned int virt;
-		unsigned int size;
-		unsigned int align;
-		void *ret;
-	} args;
-
-	args.service = "claim";
-	args.nargs = 3;
-	args.nret = 1;
-	args.virt = virt;
-	args.size = size;
-	args.align = align;
-	(*prom)(&args);
-	return args.ret;
-}
-
-int
-getprop(void *phandle, const char *name, void *buf, int buflen)
-{
-	struct prom_args {
-		char *service;
-		int nargs;
-		int nret;
-		void *phandle;
-		const char *name;
-		void *buf;
-		int buflen;
-		int size;
-	} args;
-
-	args.service = "getprop";
-	args.nargs = 4;
-	args.nret = 1;
-	args.phandle = phandle;
-	args.name = name;
-	args.buf = buf;
-	args.buflen = buflen;
-	args.size = -1;
-	(*prom)(&args);
-	return args.size;
-}
-
-int
-putc(int c, void *f)
-{
-	char ch = c;
-
-	if (c == '\n')
-		putc('\r', f);
-	return write(f, &ch, 1) == 1? c: -1;
-}
-
-int
-putchar(int c)
-{
-	return putc(c, stdout);
-}
-
-int
-fputs(char *str, void *f)
-{
-	int n = strlen(str);
-
-	return write(f, str, n) == n? 0: -1;
-}
-
-size_t strnlen(const char * s, size_t count)
-{
-	const char *sc;
-
-	for (sc = s; count-- && *sc != '\0'; ++sc)
-		/* nothing */;
-	return sc - s;
-}
-
-extern unsigned int __div64_32(unsigned long long *dividend,
-			       unsigned int divisor);
-
-/* The unnecessary pointer compare is there
- * to check for type safety (n must be 64bit)
+/*
+ * Older OF's require that when claiming a specific range of addresses,
+ * we claim the physical space in the /memory node and the virtual
+ * space in the chosen mmu node, and then do a map operation to
+ * map virtual to physical.
  */
-# define do_div(n,base) ({						\
-	unsigned int __base = (base);					\
-	unsigned int __rem;						\
-	(void)(((typeof((n)) *)0) == ((unsigned long long *)0));	\
-	if (((n) >> 32) == 0) {						\
-		__rem = (unsigned int)(n) % __base;			\
-		(n) = (unsigned int)(n) / __base;			\
-	} else								\
-		__rem = __div64_32(&(n), __base);			\
-	__rem;								\
- })
+static int need_map = -1;
+static ihandle chosen_mmu;
+static phandle memory;
 
-static int skip_atoi(const char **s)
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
 {
-	int i, c;
-
-	for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
-		i = i*10 + c - '0';
-	return i;
+	for (; *s2; ++s2)
+		if (*s1++ != *s2)
+			return 0;
+	return 1;
 }
 
-#define ZEROPAD	1		/* pad with zero */
-#define SIGN	2		/* unsigned/signed long */
-#define PLUS	4		/* show plus */
-#define SPACE	8		/* space if plus */
-#define LEFT	16		/* left justified */
-#define SPECIAL	32		/* 0x */
-#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
-
-static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
+static int check_of_version(void)
 {
-	char c,sign,tmp[66];
-	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
-	int i;
+	phandle oprom, chosen;
+	char version[64];
 
-	if (type & LARGE)
-		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	if (type & LEFT)
-		type &= ~ZEROPAD;
-	if (base < 2 || base > 36)
+	oprom = finddevice("/openprom");
+	if (oprom == (phandle) -1)
 		return 0;
-	c = (type & ZEROPAD) ? '0' : ' ';
-	sign = 0;
-	if (type & SIGN) {
-		if ((signed long long)num < 0) {
-			sign = '-';
-			num = - (signed long long)num;
-			size--;
-		} else if (type & PLUS) {
-			sign = '+';
-			size--;
-		} else if (type & SPACE) {
-			sign = ' ';
-			size--;
+	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+		return 0;
+	version[sizeof(version)-1] = 0;
+	printf("OF version = '%s'\r\n", version);
+	if (!string_match(version, "Open Firmware, 1.")
+	    && !string_match(version, "FirmWorks,3."))
+		return 0;
+	chosen = finddevice("/chosen");
+	if (chosen == (phandle) -1) {
+		chosen = finddevice("/chosen@0");
+		if (chosen == (phandle) -1) {
+			printf("no chosen\n");
+			return 0;
 		}
 	}
-	if (type & SPECIAL) {
-		if (base == 16)
-			size -= 2;
-		else if (base == 8)
-			size--;
+	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+		printf("no mmu\n");
+		return 0;
 	}
-	i = 0;
-	if (num == 0)
-		tmp[i++]='0';
-	else while (num != 0) {
-		tmp[i++] = digits[do_div(num, base)];
-	}
-	if (i > precision)
-		precision = i;
-	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
-	if (sign)
-		*str++ = sign;
-	if (type & SPECIAL) {
-		if (base==8)
-			*str++ = '0';
-		else if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
+	memory = (ihandle) call_prom("open", 1, 1, "/memory");
+	if (memory == (ihandle) -1) {
+		memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
+		if (memory == (ihandle) -1) {
+			printf("no memory node\n");
+			return 0;
 		}
 	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
+	printf("old OF detected\r\n");
+	return 1;
 }
 
-int vsprintf(char *buf, const char *fmt, va_list args)
+void *claim(unsigned long virt, unsigned long size, unsigned long align)
 {
-	int len;
-	unsigned long long num;
-	int i, base;
-	char * str;
-	const char *s;
+	int ret;
+	unsigned int result;
 
-	int flags;		/* flags to number() */
-
-	int field_width;	/* width of output field */
-	int precision;		/* min. # of digits for integers; max
-				   number of chars for from string */
-	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
-	                        /* 'z' support added 23/7/1999 S.H.    */
-				/* 'z' changed to 'Z' --davidm 1/25/99 */
-
+	if (need_map < 0)
+		need_map = check_of_version();
+	if (align || !need_map)
+		return (void *) call_prom("claim", 3, 1, virt, size, align);
 	
-	for (str=buf ; *fmt ; ++fmt) {
-		if (*fmt != '%') {
-			*str++ = *fmt;
-			continue;
-		}
-			
-		/* process flags */
-		flags = 0;
-		repeat:
-			++fmt;		/* this also skips first '%' */
-			switch (*fmt) {
-				case '-': flags |= LEFT; goto repeat;
-				case '+': flags |= PLUS; goto repeat;
-				case ' ': flags |= SPACE; goto repeat;
-				case '#': flags |= SPECIAL; goto repeat;
-				case '0': flags |= ZEROPAD; goto repeat;
-				}
-		
-		/* get field width */
-		field_width = -1;
-		if ('0' <= *fmt && *fmt <= '9')
-			field_width = skip_atoi(&fmt);
-		else if (*fmt == '*') {
-			++fmt;
-			/* it's the next argument */
-			field_width = va_arg(args, int);
-			if (field_width < 0) {
-				field_width = -field_width;
-				flags |= LEFT;
-			}
-		}
-
-		/* get the precision */
-		precision = -1;
-		if (*fmt == '.') {
-			++fmt;	
-			if ('0' <= *fmt && *fmt <= '9')
-				precision = skip_atoi(&fmt);
-			else if (*fmt == '*') {
-				++fmt;
-				/* it's the next argument */
-				precision = va_arg(args, int);
-			}
-			if (precision < 0)
-				precision = 0;
-		}
-
-		/* get the conversion qualifier */
-		qualifier = -1;
-		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
-			qualifier = *fmt;
-			++fmt;
-		}
-
-		/* default base */
-		base = 10;
-
-		switch (*fmt) {
-		case 'c':
-			if (!(flags & LEFT))
-				while (--field_width > 0)
-					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
-				*str++ = ' ';
-			continue;
-
-		case 's':
-			s = va_arg(args, char *);
-			if (!s)
-				s = "<NULL>";
-
-			len = strnlen(s, precision);
-
-			if (!(flags & LEFT))
-				while (len < field_width--)
-					*str++ = ' ';
-			for (i = 0; i < len; ++i)
-				*str++ = *s++;
-			while (len < field_width--)
-				*str++ = ' ';
-			continue;
-
-		case 'p':
-			if (field_width == -1) {
-				field_width = 2*sizeof(void *);
-				flags |= ZEROPAD;
-			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
-			continue;
-
-
-		case 'n':
-			if (qualifier == 'l') {
-				long * ip = va_arg(args, long *);
-				*ip = (str - buf);
-			} else if (qualifier == 'Z') {
-				size_t * ip = va_arg(args, size_t *);
-				*ip = (str - buf);
-			} else {
-				int * ip = va_arg(args, int *);
-				*ip = (str - buf);
-			}
-			continue;
-
-		case '%':
-			*str++ = '%';
-			continue;
-
-		/* integer number formats - set up the flags and "break" */
-		case 'o':
-			base = 8;
-			break;
-
-		case 'X':
-			flags |= LARGE;
-		case 'x':
-			base = 16;
-			break;
-
-		case 'd':
-		case 'i':
-			flags |= SIGN;
-		case 'u':
-			break;
-
-		default:
-			*str++ = '%';
-			if (*fmt)
-				*str++ = *fmt;
-			else
-				--fmt;
-			continue;
-		}
-		if (qualifier == 'l') {
-			num = va_arg(args, unsigned long);
-			if (flags & SIGN)
-				num = (signed long) num;
-		} else if (qualifier == 'Z') {
-			num = va_arg(args, size_t);
-		} else if (qualifier == 'h') {
-			num = (unsigned short) va_arg(args, int);
-			if (flags & SIGN)
-				num = (signed short) num;
-		} else {
-			num = va_arg(args, unsigned int);
-			if (flags & SIGN)
-				num = (signed int) num;
-		}
-		str = number(str, num, base, field_width, precision, flags);
-	}
-	*str = '\0';
-	return str-buf;
-}
-
-int sprintf(char * buf, const char *fmt, ...)
-{
-	va_list args;
-	int i;
-
-	va_start(args, fmt);
-	i=vsprintf(buf,fmt,args);
-	va_end(args);
-	return i;
-}
-
-static char sprint_buf[1024];
-
-int
-printf(const char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	write(stdout, sprint_buf, n);
-	return n;
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+			    align, size, virt);
+	if (ret != 0 || result == -1)
+		return (void *) -1;
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+			    align, size, virt);
+	/* 0x12 == coherent + read/write */
+	ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
+			0x12, size, virt, virt);
+	return (void *) virt;
 }
diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
index 96ab5ae..3e2ddd4 100644
--- a/arch/powerpc/boot/prom.h
+++ b/arch/powerpc/boot/prom.h
@@ -1,18 +1,34 @@
 #ifndef _PPC_BOOT_PROM_H_
 #define _PPC_BOOT_PROM_H_
 
-extern int (*prom) (void *);
-extern void *chosen_handle;
+typedef void *phandle;
+typedef void *ihandle;
 
-extern void *stdin;
-extern void *stdout;
-extern void *stderr;
+extern int (*prom) (void *);
+extern phandle chosen_handle;
+extern ihandle stdout;
+
+int	call_prom(const char *service, int nargs, int nret, ...);
+int	call_prom_ret(const char *service, int nargs, int nret,
+		      unsigned int *rets, ...);
 
 extern int write(void *handle, void *ptr, int nb);
-extern int read(void *handle, void *ptr, int nb);
-extern void exit(void);
-extern void pause(void);
-extern void *finddevice(const char *);
-extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
-extern int getprop(void *phandle, const char *name, void *buf, int buflen);
+extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
+
+static inline void exit(void)
+{
+	call_prom("exit", 0, 0);
+}
+
+static inline phandle finddevice(const char *name)
+{
+	return (phandle) call_prom("finddevice", 1, 1, name);
+}
+
+static inline int getprop(void *phandle, const char *name,
+			  void *buf, int buflen)
+{
+	return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+}
+
 #endif				/* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/boot/rs6000.h b/arch/powerpc/boot/rs6000.h
new file mode 100644
index 0000000..433f450
--- /dev/null
+++ b/arch/powerpc/boot/rs6000.h
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+   Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+   FIXME: Can someone provide a transliteration of this name into ASCII?
+   Using the following chars caused a compiler warning on HIUX (so I replaced
+   them with octal escapes), and isn't useful without an understanding of what
+   character set it is.
+   Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+   and John Gilmore of Cygnus Support.  */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+	char f_magic[2];	/* magic number			*/
+	char f_nscns[2];	/* number of sections		*/
+	char f_timdat[4];	/* time & date stamp		*/
+	char f_symptr[4];	/* file pointer to symtab	*/
+	char f_nsyms[4];	/* number of symtab entries	*/
+	char f_opthdr[2];	/* sizeof(optional hdr)		*/
+	char f_flags[2];	/* flags			*/
+};
+
+        /* IBM RS/6000 */
+#define U802WRMAGIC     0730    /* writeable text segments **chh**      */
+#define U802ROMAGIC     0735    /* readonly sharable text segments      */
+#define U802TOCMAGIC    0737    /* readonly text segments and TOC       */
+
+#define BADMAG(x)	\
+	((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+	 (x).f_magic != U802TOCMAGIC)
+
+#define	FILHDR	struct external_filehdr
+#define	FILHSZ	20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+  unsigned char	magic[2];	/* type of file			*/
+  unsigned char	vstamp[2];	/* version stamp		*/
+  unsigned char	tsize[4];	/* text size in bytes, padded to FW bdry */
+  unsigned char	dsize[4];	/* initialized data "  "	*/
+  unsigned char	bsize[4];	/* uninitialized data "   "	*/
+  unsigned char	entry[4];	/* entry pt.			*/
+  unsigned char	text_start[4];	/* base of text used for this file */
+  unsigned char	data_start[4];	/* base of data used for this file */
+  unsigned char	o_toc[4];	/* address of TOC */
+  unsigned char	o_snentry[2];	/* section number of entry point */
+  unsigned char	o_sntext[2];	/* section number of .text section */
+  unsigned char	o_sndata[2];	/* section number of .data section */
+  unsigned char	o_sntoc[2];	/* section number of TOC */
+  unsigned char	o_snloader[2];	/* section number of .loader section */
+  unsigned char	o_snbss[2];	/* section number of .bss section */
+  unsigned char	o_algntext[2];	/* .text alignment */
+  unsigned char	o_algndata[2];	/* .data alignment */
+  unsigned char	o_modtype[2];	/* module type (??) */
+  unsigned char o_cputype[2];	/* cpu type */
+  unsigned char	o_maxstack[4];	/* max stack size (??) */
+  unsigned char o_maxdata[4];	/* max data size (??) */
+  unsigned char	o_resv2[12];	/* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define	RS6K_AOUTHDR_OMAGIC	0x0107	/* old: text & data writeable */
+#define	RS6K_AOUTHDR_NMAGIC	0x0108	/* new: text r/o, data r/w */
+#define	RS6K_AOUTHDR_ZMAGIC	0x010B	/* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+	char		s_name[8];	/* section name			*/
+	char		s_paddr[4];	/* physical address, aliased s_nlib */
+	char		s_vaddr[4];	/* virtual address		*/
+	char		s_size[4];	/* section size			*/
+	char		s_scnptr[4];	/* file ptr to raw data for section */
+	char		s_relptr[4];	/* file ptr to relocation	*/
+	char		s_lnnoptr[4];	/* file ptr to line numbers	*/
+	char		s_nreloc[2];	/* number of relocation entries	*/
+	char		s_nlnno[2];	/* number of line number entries*/
+	char		s_flags[4];	/* flags			*/
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT	".text"
+#define _DATA	".data"
+#define _BSS	".bss"
+#define _PAD	".pad"
+#define _LOADER	".loader"
+
+#define	SCNHDR	struct external_scnhdr
+#define	SCNHSZ	40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER.  */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG.  */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+   another section header with STYP_OVRFLO set.  */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+	union {
+		char l_symndx[4];	/* function name symbol index, iff l_lnno == 0*/
+		char l_paddr[4];	/* (physical) address of line number	*/
+	} l_addr;
+	char l_lnno[2];	/* line number		*/
+};
+
+
+#define	LINENO	struct external_lineno
+#define	LINESZ	6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN	8	/* # characters in a symbol name	*/
+#define E_FILNMLEN	14	/* # characters in a file name		*/
+#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+  union {
+    char e_name[E_SYMNMLEN];
+    struct {
+      char e_zeroes[4];
+      char e_offset[4];
+    } e;
+  } e;
+  char e_value[4];
+  char e_scnum[2];
+  char e_type[2];
+  char e_sclass[1];
+  char e_numaux[1];
+};
+
+
+
+#define N_BTMASK	(017)
+#define N_TMASK		(060)
+#define N_BTSHFT	(4)
+#define N_TSHIFT	(2)
+
+
+union external_auxent {
+	struct {
+		char x_tagndx[4];	/* str, un, or enum tag indx */
+		union {
+			struct {
+			    char  x_lnno[2]; /* declaration line number */
+			    char  x_size[2]; /* str/union/array size */
+			} x_lnsz;
+			char x_fsize[4];	/* size of function */
+		} x_misc;
+		union {
+			struct {		/* if ISFCN, tag, or .bb */
+			    char x_lnnoptr[4];	/* ptr to fcn line # */
+			    char x_endndx[4];	/* entry ndx past block end */
+			} x_fcn;
+			struct {		/* if ISARY, up to 4 dimen. */
+			    char x_dimen[E_DIMNUM][2];
+			} x_ary;
+		} x_fcnary;
+		char x_tvndx[2];		/* tv index */
+	} x_sym;
+
+	union {
+		char x_fname[E_FILNMLEN];
+		struct {
+			char x_zeroes[4];
+			char x_offset[4];
+		} x_n;
+	} x_file;
+
+	struct {
+		char x_scnlen[4];			/* section length */
+		char x_nreloc[2];	/* # relocation entries */
+		char x_nlinno[2];	/* # line numbers */
+	} x_scn;
+
+        struct {
+		char x_tvfill[4];	/* tv fill value */
+		char x_tvlen[2];	/* length of .tv */
+		char x_tvran[2][2];	/* tv range */
+	} x_tv;		/* info about .tv section (in auxent of symbol .tv)) */
+
+	struct {
+		unsigned char x_scnlen[4];
+		unsigned char x_parmhash[4];
+		unsigned char x_snhash[2];
+		unsigned char x_smtyp[1];
+		unsigned char x_smclas[1];
+		unsigned char x_stab[4];
+		unsigned char x_snstab[2];
+	} x_csect;
+
+};
+
+#define	SYMENT	struct external_syment
+#define	SYMESZ	18
+#define	AUXENT	union external_auxent
+#define	AUXESZ	18
+#define DBXMASK 0x80		/* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_size[1];
+  char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
new file mode 100644
index 0000000..b5aa522
--- /dev/null
+++ b/arch/powerpc/boot/stdio.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
+
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+
+extern unsigned int __div64_32(unsigned long long *dividend,
+			       unsigned int divisor);
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({						\
+	unsigned int __base = (base);					\
+	unsigned int __rem;						\
+	(void)(((typeof((n)) *)0) == ((unsigned long long *)0));	\
+	if (((n) >> 32) == 0) {						\
+		__rem = (unsigned int)(n) % __base;			\
+		(n) = (unsigned int)(n) / __base;			\
+	} else								\
+		__rem = __div64_32(&(n), __base);			\
+	__rem;								\
+ })
+
+static int skip_atoi(const char **s)
+{
+	int i, c;
+
+	for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
+		i = i*10 + c - '0';
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
+{
+	char c,sign,tmp[66];
+	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	int i;
+
+	if (type & LARGE)
+		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ';
+	sign = 0;
+	if (type & SIGN) {
+		if ((signed long long)num < 0) {
+			sign = '-';
+			num = - (signed long long)num;
+			size--;
+		} else if (type & PLUS) {
+			sign = '+';
+			size--;
+		} else if (type & SPACE) {
+			sign = ' ';
+			size--;
+		}
+	}
+	if (type & SPECIAL) {
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	}
+	i = 0;
+	if (num == 0)
+		tmp[i++]='0';
+	else while (num != 0) {
+		tmp[i++] = digits[do_div(num, base)];
+	}
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type&(ZEROPAD+LEFT)))
+		while(size-->0)
+			*str++ = ' ';
+	if (sign)
+		*str++ = sign;
+	if (type & SPECIAL) {
+		if (base==8)
+			*str++ = '0';
+		else if (base==16) {
+			*str++ = '0';
+			*str++ = digits[33];
+		}
+	}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			*str++ = c;
+	while (i < precision--)
+		*str++ = '0';
+	while (i-- > 0)
+		*str++ = tmp[i];
+	while (size-- > 0)
+		*str++ = ' ';
+	return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	int len;
+	unsigned long long num;
+	int i, base;
+	char * str;
+	const char *s;
+
+	int flags;		/* flags to number() */
+
+	int field_width;	/* width of output field */
+	int precision;		/* min. # of digits for integers; max
+				   number of chars for from string */
+	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+	                        /* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' changed to 'Z' --davidm 1/25/99 */
+
+	
+	for (str=buf ; *fmt ; ++fmt) {
+		if (*fmt != '%') {
+			*str++ = *fmt;
+			continue;
+		}
+			
+		/* process flags */
+		flags = 0;
+		repeat:
+			++fmt;		/* this also skips first '%' */
+			switch (*fmt) {
+				case '-': flags |= LEFT; goto repeat;
+				case '+': flags |= PLUS; goto repeat;
+				case ' ': flags |= SPACE; goto repeat;
+				case '#': flags |= SPECIAL; goto repeat;
+				case '0': flags |= ZEROPAD; goto repeat;
+				}
+		
+		/* get field width */
+		field_width = -1;
+		if ('0' <= *fmt && *fmt <= '9')
+			field_width = skip_atoi(&fmt);
+		else if (*fmt == '*') {
+			++fmt;
+			/* it's the next argument */
+			field_width = va_arg(args, int);
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			++fmt;	
+			if ('0' <= *fmt && *fmt <= '9')
+				precision = skip_atoi(&fmt);
+			else if (*fmt == '*') {
+				++fmt;
+				/* it's the next argument */
+				precision = va_arg(args, int);
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
+			qualifier = *fmt;
+			++fmt;
+		}
+
+		/* default base */
+		base = 10;
+
+		switch (*fmt) {
+		case 'c':
+			if (!(flags & LEFT))
+				while (--field_width > 0)
+					*str++ = ' ';
+			*str++ = (unsigned char) va_arg(args, int);
+			while (--field_width > 0)
+				*str++ = ' ';
+			continue;
+
+		case 's':
+			s = va_arg(args, char *);
+			if (!s)
+				s = "<NULL>";
+
+			len = strnlen(s, precision);
+
+			if (!(flags & LEFT))
+				while (len < field_width--)
+					*str++ = ' ';
+			for (i = 0; i < len; ++i)
+				*str++ = *s++;
+			while (len < field_width--)
+				*str++ = ' ';
+			continue;
+
+		case 'p':
+			if (field_width == -1) {
+				field_width = 2*sizeof(void *);
+				flags |= ZEROPAD;
+			}
+			str = number(str,
+				(unsigned long) va_arg(args, void *), 16,
+				field_width, precision, flags);
+			continue;
+
+
+		case 'n':
+			if (qualifier == 'l') {
+				long * ip = va_arg(args, long *);
+				*ip = (str - buf);
+			} else if (qualifier == 'Z') {
+				size_t * ip = va_arg(args, size_t *);
+				*ip = (str - buf);
+			} else {
+				int * ip = va_arg(args, int *);
+				*ip = (str - buf);
+			}
+			continue;
+
+		case '%':
+			*str++ = '%';
+			continue;
+
+		/* integer number formats - set up the flags and "break" */
+		case 'o':
+			base = 8;
+			break;
+
+		case 'X':
+			flags |= LARGE;
+		case 'x':
+			base = 16;
+			break;
+
+		case 'd':
+		case 'i':
+			flags |= SIGN;
+		case 'u':
+			break;
+
+		default:
+			*str++ = '%';
+			if (*fmt)
+				*str++ = *fmt;
+			else
+				--fmt;
+			continue;
+		}
+		if (qualifier == 'l') {
+			num = va_arg(args, unsigned long);
+			if (flags & SIGN)
+				num = (signed long) num;
+		} else if (qualifier == 'Z') {
+			num = va_arg(args, size_t);
+		} else if (qualifier == 'h') {
+			num = (unsigned short) va_arg(args, int);
+			if (flags & SIGN)
+				num = (signed short) num;
+		} else {
+			num = va_arg(args, unsigned int);
+			if (flags & SIGN)
+				num = (signed int) num;
+		}
+		str = number(str, num, base, field_width, precision, flags);
+	}
+	*str = '\0';
+	return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsprintf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
+
+static char sprint_buf[1024];
+
+int
+printf(const char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	write(stdout, sprint_buf, n);
+	return n;
+}
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
index 24bd3a8..eb9e16c 100644
--- a/arch/powerpc/boot/stdio.h
+++ b/arch/powerpc/boot/stdio.h
@@ -7,10 +7,4 @@
 
 extern int vsprintf(char *buf, const char *fmt, va_list args);
 
-extern int putc(int c, void *f);
-extern int putchar(int c);
-extern int getchar(void);
-
-extern int fputs(char *str, void *f);
-
 #endif				/* _PPC_BOOT_STDIO_H_ */
diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S
index b1eeaed..ac3d43b 100644
--- a/arch/powerpc/boot/string.S
+++ b/arch/powerpc/boot/string.S
@@ -107,10 +107,12 @@
 	rlwinm.	r7,r5,32-3,3,31		/* r7 = r5 >> 3 */
 	addi	r6,r3,-4
 	addi	r4,r4,-4
-	beq	2f			/* if less than 8 bytes to do */
+	beq	3f			/* if less than 8 bytes to do */
 	andi.	r0,r6,3			/* get dest word aligned */
 	mtctr	r7
 	bne	5f
+	andi.	r0,r4,3			/* check src word aligned too */
+	bne	3f
 1:	lwz	r7,4(r4)
 	lwzu	r8,8(r4)
 	stw	r7,4(r6)
@@ -132,6 +134,11 @@
 	bdnz	4b
 	blr
 5:	subfic	r0,r0,4
+	cmpw	cr1,r0,r5
+	add	r7,r0,r4
+	andi.	r7,r7,3			/* will source be word-aligned too? */
+	ble	cr1,3b
+	bne	3b			/* do byte-by-byte if not */
 	mtctr	r0
 6:	lbz	r7,4(r4)
 	addi	r4,r4,1
@@ -149,10 +156,12 @@
 	rlwinm.	r7,r5,32-3,3,31		/* r7 = r5 >> 3 */
 	add	r6,r3,r5
 	add	r4,r4,r5
-	beq	2f
+	beq	3f
 	andi.	r0,r6,3
 	mtctr	r7
 	bne	5f
+	andi.	r0,r4,3
+	bne	3f
 1:	lwz	r7,-4(r4)
 	lwzu	r8,-8(r4)
 	stw	r7,-4(r6)
@@ -171,7 +180,12 @@
 	stbu	r0,-1(r6)
 	bdnz	4b
 	blr
-5:	mtctr	r0
+5:	cmpw	cr1,r0,r5
+	subf	r7,r0,r4
+	andi.	r7,r7,3
+	ble	cr1,3b
+	bne	3b
+	mtctr	r0
 6:	lbzu	r7,-1(r4)
 	stbu	r7,-1(r6)
 	bdnz	6b
diff --git a/arch/powerpc/boot/zImage.coff.lds b/arch/powerpc/boot/zImage.coff.lds
new file mode 100644
index 0000000..6016251a1
--- /dev/null
+++ b/arch/powerpc/boot/zImage.coff.lds
@@ -0,0 +1,46 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_start)
+SECTIONS
+{
+  . = (5*1024*1024);
+  _start = .;
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+  }
+  _etext = .;
+  . = ALIGN(4096);
+  .data    :
+  {
+    *(.rodata*)
+    *(.data*)
+    *(.sdata*)
+    __got2_start = .;
+    *(.got2)
+    __got2_end = .;
+
+    _vmlinux_start =  .;
+    *(.kernel:vmlinux.strip)
+    _vmlinux_end =  .;
+
+    _initrd_start =  .;
+    *(.kernel:initrd)
+    _initrd_end =  .;
+  }
+
+  . = ALIGN(4096);
+  _edata  =  .;
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss)
+   *(.bss)
+  }
+  _end = . ;
+
+  /DISCARD/ :
+  {
+    *(.comment)
+  }
+}
diff --git a/arch/powerpc/configs/mpc834x_sys_defconfig b/arch/powerpc/configs/mpc834x_sys_defconfig
new file mode 100644
index 0000000..3bff761
--- /dev/null
+++ b/arch/powerpc/configs/mpc834x_sys_defconfig
@@ -0,0 +1,911 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-g461d4edf-dirty
+# Fri Jan 13 11:01:47 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC834x_SYS=y
+CONFIG_MPC834x=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# SEC2.x Options
+#
+CONFIG_MPC8349E_SEC2x=y
+
+#
+# SEC2.x Test Options
+#
+CONFIG_MPC8349E_SEC2xTEST=y
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 56399c5..840aad4 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -135,7 +135,7 @@
 	DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
 	DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
 	DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
-	DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
+	DEFINE(PACALPPACAPTR, offsetof(struct paca_struct, lppaca_ptr));
 	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
 
 	DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
diff --git a/arch/powerpc/kernel/cpu_setup_power4.S b/arch/powerpc/kernel/cpu_setup_power4.S
index cca942f..b61d86e 100644
--- a/arch/powerpc/kernel/cpu_setup_power4.S
+++ b/arch/powerpc/kernel/cpu_setup_power4.S
@@ -130,7 +130,7 @@
 	mfcr	r7
 
 	/* Get storage ptr */
-	LOADADDR(r5,cpu_state_storage)
+	LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
 
 	/* We only deal with 970 for now */
 	mfspr	r0,SPRN_PVR
@@ -164,7 +164,7 @@
 	/* Get storage ptr (FIXME when using anton reloc as we
 	 * are running with translation disabled here
 	 */
-	LOADADDR(r5,cpu_state_storage)
+	LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
 
 	/* We only deal with 970 for now */
 	mfspr	r0,SPRN_PVR
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 43c74a6..1069645 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -55,7 +55,8 @@
 #define COMMON_USER_POWER4	(COMMON_USER_PPC64 | PPC_FEATURE_POWER4)
 #define COMMON_USER_POWER5	(COMMON_USER_PPC64 | PPC_FEATURE_POWER5)
 #define COMMON_USER_POWER5_PLUS	(COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS)
-
+#define COMMON_USER_BOOKE	(PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
+				 PPC_FEATURE_BOOKE)
 
 /* We only set the spe features if the kernel was compiled with
  * spe support
@@ -79,7 +80,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/power3",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "power3",
 	},
 	{	/* Power3+ */
 		.pvr_mask		= 0xffff0000,
@@ -92,7 +94,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/power3",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "power3",
 	},
 	{	/* Northstar */
 		.pvr_mask		= 0xffff0000,
@@ -105,7 +108,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "rs64",
 	},
 	{	/* Pulsar */
 		.pvr_mask		= 0xffff0000,
@@ -118,7 +122,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "rs64",
 	},
 	{	/* I-star */
 		.pvr_mask		= 0xffff0000,
@@ -131,7 +136,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "rs64",
 	},
 	{	/* S-star */
 		.pvr_mask		= 0xffff0000,
@@ -144,7 +150,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power3,
 		.oprofile_cpu_type	= "ppc64/rs64",
-		.oprofile_type		= RS64,
+		.oprofile_type		= PPC_OPROFILE_RS64,
+		.platform		= "rs64",
 	},
 	{	/* Power4 */
 		.pvr_mask		= 0xffff0000,
@@ -157,7 +164,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power4,
 		.oprofile_cpu_type	= "ppc64/power4",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "power4",
 	},
 	{	/* Power4+ */
 		.pvr_mask		= 0xffff0000,
@@ -170,7 +178,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_power4,
 		.oprofile_cpu_type	= "ppc64/power4",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "power4",
 	},
 	{	/* PPC970 */
 		.pvr_mask		= 0xffff0000,
@@ -184,7 +193,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "ppc970",
 	},
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
@@ -204,7 +214,8 @@
 		.num_pmcs		= 8,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "ppc970",
 	},
 #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
 #ifdef CONFIG_PPC64
@@ -219,7 +230,8 @@
 		.dcache_bsize		= 128,
 		.cpu_setup		= __setup_cpu_ppc970,
 		.oprofile_cpu_type	= "ppc64/970",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "ppc970",
 	},
 	{	/* Power5 GR */
 		.pvr_mask		= 0xffff0000,
@@ -232,7 +244,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_power4,
 		.oprofile_cpu_type	= "ppc64/power5",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "power5",
 	},
 	{	/* Power5 GS */
 		.pvr_mask		= 0xffff0000,
@@ -245,7 +258,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_power4,
 		.oprofile_cpu_type	= "ppc64/power5+",
-		.oprofile_type		= POWER4,
+		.oprofile_type		= PPC_OPROFILE_POWER4,
+		.platform		= "power5+",
 	},
 	{	/* Cell Broadband Engine */
 		.pvr_mask		= 0xffff0000,
@@ -257,6 +271,7 @@
 		.icache_bsize		= 128,
 		.dcache_bsize		= 128,
 		.cpu_setup		= __setup_cpu_be,
+		.platform		= "ppc-cell-be",
 	},
 	{	/* default match */
 		.pvr_mask		= 0x00000000,
@@ -268,6 +283,7 @@
 		.dcache_bsize		= 128,
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_power4,
+		.platform		= "power4",
 	}
 #endif	/* CONFIG_PPC64 */
 #ifdef CONFIG_PPC32
@@ -281,6 +297,7 @@
 			PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc601",
 	},
 	{	/* 603 */
 		.pvr_mask		= 0xffff0000,
@@ -290,7 +307,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* 603e */
 		.pvr_mask		= 0xffff0000,
@@ -300,7 +318,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* 603ev */
 		.pvr_mask		= 0xffff0000,
@@ -310,7 +329,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* 604 */
 		.pvr_mask		= 0xffff0000,
@@ -321,7 +341,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 2,
-		.cpu_setup		= __setup_cpu_604
+		.cpu_setup		= __setup_cpu_604,
+		.platform		= "ppc604",
 	},
 	{	/* 604e */
 		.pvr_mask		= 0xfffff000,
@@ -332,7 +353,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_604
+		.cpu_setup		= __setup_cpu_604,
+		.platform		= "ppc604",
 	},
 	{	/* 604r */
 		.pvr_mask		= 0xffff0000,
@@ -343,7 +365,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_604
+		.cpu_setup		= __setup_cpu_604,
+		.platform		= "ppc604",
 	},
 	{	/* 604ev */
 		.pvr_mask		= 0xffff0000,
@@ -354,7 +377,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_604
+		.cpu_setup		= __setup_cpu_604,
+		.platform		= "ppc604",
 	},
 	{	/* 740/750 (0x4202, don't support TAU ?) */
 		.pvr_mask		= 0xffffffff,
@@ -365,7 +389,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
 	},
 	{	/* 750CX (80100 and 8010x?) */
 		.pvr_mask		= 0xfffffff0,
@@ -376,7 +401,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750cx
+		.cpu_setup		= __setup_cpu_750cx,
+		.platform		= "ppc750",
 	},
 	{	/* 750CX (82201 and 82202) */
 		.pvr_mask		= 0xfffffff0,
@@ -387,7 +413,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750cx
+		.cpu_setup		= __setup_cpu_750cx,
+		.platform		= "ppc750",
 	},
 	{	/* 750CXe (82214) */
 		.pvr_mask		= 0xfffffff0,
@@ -398,7 +425,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750cx
+		.cpu_setup		= __setup_cpu_750cx,
+		.platform		= "ppc750",
 	},
 	{	/* 750CXe "Gekko" (83214) */
 		.pvr_mask		= 0xffffffff,
@@ -409,7 +437,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750cx
+		.cpu_setup		= __setup_cpu_750cx,
+		.platform		= "ppc750",
 	},
 	{	/* 745/755 */
 		.pvr_mask		= 0xfffff000,
@@ -420,7 +449,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
 	},
 	{	/* 750FX rev 1.x */
 		.pvr_mask		= 0xffffff00,
@@ -431,7 +461,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
 	},
 	{	/* 750FX rev 2.0 must disable HID0[DPM] */
 		.pvr_mask		= 0xffffffff,
@@ -442,7 +473,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
 	},
 	{	/* 750FX (All revs except 2.0) */
 		.pvr_mask		= 0xffff0000,
@@ -453,7 +485,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750fx
+		.cpu_setup		= __setup_cpu_750fx,
+		.platform		= "ppc750",
 	},
 	{	/* 750GX */
 		.pvr_mask		= 0xffff0000,
@@ -464,7 +497,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750fx
+		.cpu_setup		= __setup_cpu_750fx,
+		.platform		= "ppc750",
 	},
 	{	/* 740/750 (L2CR bit need fixup for 740) */
 		.pvr_mask		= 0xffff0000,
@@ -475,7 +509,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_750
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
 	},
 	{	/* 7400 rev 1.1 ? (no TAU) */
 		.pvr_mask		= 0xffffffff,
@@ -486,7 +521,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_7400
+		.cpu_setup		= __setup_cpu_7400,
+		.platform		= "ppc7400",
 	},
 	{	/* 7400 */
 		.pvr_mask		= 0xffff0000,
@@ -497,7 +533,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_7400
+		.cpu_setup		= __setup_cpu_7400,
+		.platform		= "ppc7400",
 	},
 	{	/* 7410 */
 		.pvr_mask		= 0xffff0000,
@@ -508,7 +545,8 @@
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
-		.cpu_setup		= __setup_cpu_7410
+		.cpu_setup		= __setup_cpu_7410,
+		.platform		= "ppc7400",
 	},
 	{	/* 7450 2.0 - no doze/nap */
 		.pvr_mask		= 0xffffffff,
@@ -521,7 +559,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7450 2.1 */
 		.pvr_mask		= 0xffffffff,
@@ -534,7 +573,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7450 2.3 and newer */
 		.pvr_mask		= 0xffff0000,
@@ -547,7 +587,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7455 rev 1.x */
 		.pvr_mask		= 0xffffff00,
@@ -560,7 +601,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7455 rev 2.0 */
 		.pvr_mask		= 0xffffffff,
@@ -573,7 +615,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7455 others */
 		.pvr_mask		= 0xffff0000,
@@ -586,7 +629,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7447/7457 Rev 1.0 */
 		.pvr_mask		= 0xffffffff,
@@ -599,7 +643,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7447/7457 Rev 1.1 */
 		.pvr_mask		= 0xffffffff,
@@ -612,7 +657,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7447/7457 Rev 1.2 and later */
 		.pvr_mask		= 0xffff0000,
@@ -625,7 +671,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7447A */
 		.pvr_mask		= 0xffff0000,
@@ -638,7 +685,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 7448 */
 		.pvr_mask		= 0xffff0000,
@@ -651,7 +699,8 @@
 		.num_pmcs		= 6,
 		.cpu_setup		= __setup_cpu_745x,
 		.oprofile_cpu_type      = "ppc/7450",
-		.oprofile_type		= G4,
+		.oprofile_type		= PPC_OPROFILE_G4,
+		.platform		= "ppc7450",
 	},
 	{	/* 82xx (8240, 8245, 8260 are all 603e cores) */
 		.pvr_mask		= 0x7fff0000,
@@ -661,7 +710,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* All G2_LE (603e core, plus some) have the same pvr */
 		.pvr_mask		= 0x7fff0000,
@@ -671,7 +721,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* e300 (a 603e core, plus some) on 83xx */
 		.pvr_mask		= 0x7fff0000,
@@ -681,7 +732,8 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
-		.cpu_setup		= __setup_cpu_603
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
 	},
 	{	/* default match, we assume split I/D cache & TB (non-601)... */
 		.pvr_mask		= 0x00000000,
@@ -691,6 +743,7 @@
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc603",
 	},
 #endif /* CLASSIC_PPC */
 #ifdef CONFIG_8xx
@@ -704,6 +757,7 @@
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
+		.platform		= "ppc823",
 	},
 #endif /* CONFIG_8xx */
 #ifdef CONFIG_40x
@@ -715,6 +769,7 @@
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
+		.platform		= "ppc403",
 	},
 	{	/* 403GCX */
 		.pvr_mask		= 0xffffff00,
@@ -725,6 +780,7 @@
 		 	PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
+		.platform		= "ppc403",
 	},
 	{	/* 403G ?? */
 		.pvr_mask		= 0xffff0000,
@@ -734,6 +790,7 @@
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
 		.icache_bsize		= 16,
 		.dcache_bsize		= 16,
+		.platform		= "ppc403",
 	},
 	{	/* 405GP */
 		.pvr_mask		= 0xffff0000,
@@ -744,6 +801,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* STB 03xxx */
 		.pvr_mask		= 0xffff0000,
@@ -754,6 +812,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* STB 04xxx */
 		.pvr_mask		= 0xffff0000,
@@ -764,6 +823,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* NP405L */
 		.pvr_mask		= 0xffff0000,
@@ -774,6 +834,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* NP4GS3 */
 		.pvr_mask		= 0xffff0000,
@@ -784,6 +845,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{   /* NP405H */
 		.pvr_mask		= 0xffff0000,
@@ -794,6 +856,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* 405GPr */
 		.pvr_mask		= 0xffff0000,
@@ -804,6 +867,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{   /* STBx25xx */
 		.pvr_mask		= 0xffff0000,
@@ -814,6 +878,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* 405LP */
 		.pvr_mask		= 0xffff0000,
@@ -823,6 +888,7 @@
 		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* Xilinx Virtex-II Pro  */
 		.pvr_mask		= 0xffff0000,
@@ -833,6 +899,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 	{	/* 405EP */
 		.pvr_mask		= 0xffff0000,
@@ -843,6 +910,7 @@
 			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc405",
 	},
 
 #endif /* CONFIG_40x */
@@ -852,81 +920,90 @@
 		.pvr_value		= 0x40000850,
 		.cpu_name		= "440EP Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER, /* 440EP has an FPU */
+		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x400008d3,
 		.cpu_name		= "440EP Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= COMMON_USER, /* 440EP has an FPU */
+		.cpu_user_features	= COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{	/* 440GP Rev. B */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x40000440,
 		.cpu_name		= "440GP Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440gp",
 	},
 	{	/* 440GP Rev. C */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x40000481,
 		.cpu_name		= "440GP Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440gp",
 	},
 	{ /* 440GX Rev. A */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x50000850,
 		.cpu_name		= "440GX Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{ /* 440GX Rev. B */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x50000851,
 		.cpu_name		= "440GX Rev. B",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{ /* 440GX Rev. C */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x50000892,
 		.cpu_name		= "440GX Rev. C",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{ /* 440GX Rev. F */
 		.pvr_mask		= 0xf0000fff,
 		.pvr_value		= 0x50000894,
 		.cpu_name		= "440GX Rev. F",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{ /* 440SP Rev. A */
 		.pvr_mask		= 0xff000fff,
 		.pvr_value		= 0x53000891,
 		.cpu_name		= "440SP Rev. A",
 		.cpu_features		= CPU_FTRS_44X,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 	{ /* 440SPe Rev. A */
 		.pvr_mask		= 0xff000fff,
@@ -934,9 +1011,10 @@
 		.cpu_name		= "440SPe Rev. A",
 		.cpu_features		= CPU_FTR_SPLIT_ID_CACHE |
 			CPU_FTR_USE_TB,
-		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.cpu_user_features	= COMMON_USER_BOOKE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "ppc440",
 	},
 #endif /* CONFIG_44x */
 #ifdef CONFIG_FSL_BOOKE
@@ -946,10 +1024,11 @@
 		.cpu_name		= "e200z5",
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E200,
-		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE |
+		.cpu_user_features	= COMMON_USER_BOOKE |
+			PPC_FEATURE_HAS_EFP_SINGLE |
 			PPC_FEATURE_UNIFIED_CACHE,
 		.dcache_bsize		= 32,
+		.platform		= "ppc5554",
 	},
 	{	/* e200z6 */
 		.pvr_mask		= 0xfff00000,
@@ -957,11 +1036,12 @@
 		.cpu_name		= "e200z6",
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E200,
-		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+		.cpu_user_features	= COMMON_USER_BOOKE |
+			PPC_FEATURE_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE |
 			PPC_FEATURE_UNIFIED_CACHE,
 		.dcache_bsize		= 32,
+		.platform		= "ppc5554",
 	},
 	{	/* e500 */
 		.pvr_mask		= 0xffff0000,
@@ -969,14 +1049,15 @@
 		.cpu_name		= "e500",
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E500,
-		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+		.cpu_user_features	= COMMON_USER_BOOKE |
+			PPC_FEATURE_SPE_COMP |
 			PPC_FEATURE_HAS_EFP_SINGLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
 		.oprofile_cpu_type	= "ppc/e500",
-		.oprofile_type		= BOOKE,
+		.oprofile_type		= PPC_OPROFILE_BOOKE,
+		.platform		= "ppc8540",
 	},
 	{	/* e500v2 */
 		.pvr_mask		= 0xffff0000,
@@ -984,14 +1065,16 @@
 		.cpu_name		= "e500v2",
 		/* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
 		.cpu_features		= CPU_FTRS_E500_2,
-		.cpu_user_features	= PPC_FEATURE_32 |
-			PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
-			PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+			PPC_FEATURE_SPE_COMP |
+			PPC_FEATURE_HAS_EFP_SINGLE |
+			PPC_FEATURE_HAS_EFP_DOUBLE,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
 		.num_pmcs		= 4,
 		.oprofile_cpu_type	= "ppc/e500",
-		.oprofile_type		= BOOKE,
+		.oprofile_type		= PPC_OPROFILE_BOOKE,
+		.platform		= "ppc8548",
 	},
 #endif
 #if !CLASSIC_PPC
@@ -1003,6 +1086,7 @@
 		.cpu_user_features	= PPC_FEATURE_32,
 		.icache_bsize		= 32,
 		.dcache_bsize		= 32,
+		.platform		= "powerpc",
 	}
 #endif /* !CLASSIC_PPC */
 #endif /* CONFIG_PPC32 */
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 036b71d..d8da2a3 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -988,7 +988,7 @@
 	stwu	r1,-INT_FRAME_SIZE(r1)
 	mflr	r0
 	stw	r0,INT_FRAME_SIZE+4(r1)
-	LOADADDR(r4, rtas)
+	LOAD_REG_ADDR(r4, rtas)
 	lis	r6,1f@ha	/* physical return address for rtas */
 	addi	r6,r6,1f@l
 	tophys(r6,r6)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index aacebb3..5420363 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -511,7 +511,8 @@
 	cmpdi	0,r5,0
 	beq	4f
 	/* Check for pending interrupts (iSeries) */
-	ld	r3,PACALPPACA+LPPACAANYINT(r13)
+	ld	r3,PACALPPACAPTR(r13)
+	ld	r3,LPPACAANYINT(r3)
 	cmpdi	r3,0
 	beq+	4f			/* skip do_IRQ if no interrupts */
 
@@ -689,9 +690,8 @@
         std	r6,PACASAVEDMSR(r13)
 
 	/* Setup our real return addr */	
-	SET_REG_TO_LABEL(r4,.rtas_return_loc)
-	SET_REG_TO_CONST(r9,PAGE_OFFSET)
-	sub	r4,r4,r9
+	LOAD_REG_ADDR(r4,.rtas_return_loc)
+	clrldi	r4,r4,2			/* convert to realmode address */
        	mtlr	r4
 
 	li	r0,0
@@ -706,7 +706,7 @@
 	sync				/* disable interrupts so SRR0/1 */
 	mtmsrd	r0			/* don't get trashed */
 
-	SET_REG_TO_LABEL(r4,rtas)
+	LOAD_REG_ADDR(r4, rtas)
 	ld	r5,RTASENTRY(r4)	/* get the rtas->entry value */
 	ld	r4,RTASBASE(r4)		/* get the rtas->base value */
 	
@@ -718,8 +718,7 @@
 _STATIC(rtas_return_loc)
 	/* relocation is off at this point */
 	mfspr	r4,SPRN_SPRG3	        /* Get PACA */
-	SET_REG_TO_CONST(r5, PAGE_OFFSET)
-        sub     r4,r4,r5                /* RELOC the PACA base pointer */
+	clrldi	r4,r4,2			/* convert to realmode address */
 
 	mfmsr   r6
 	li	r0,MSR_RI
@@ -728,7 +727,7 @@
 	mtmsrd  r6
         
         ld	r1,PACAR1(r4)           /* Restore our SP */
-	LOADADDR(r3,.rtas_restore_regs)
+	LOAD_REG_IMMEDIATE(r3,.rtas_restore_regs)
         ld	r4,PACASAVEDMSR(r4)     /* Restore our MSR */
 
 	mtspr	SPRN_SRR0,r3
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index b780b42..e4362df 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -39,9 +39,9 @@
  * to another.  Instead we call giveup_fpu in switch_to.
  */
 #ifndef CONFIG_SMP
-	LOADBASE(r3, last_task_used_math)
+	LOAD_REG_ADDRBASE(r3, last_task_used_math)
 	toreal(r3)
-	PPC_LL	r4,OFF(last_task_used_math)(r3)
+	PPC_LL	r4,ADDROFF(last_task_used_math)(r3)
 	PPC_LCMPI	0,r4,0
 	beq	1f
 	toreal(r4)
@@ -77,7 +77,7 @@
 #ifndef CONFIG_SMP
 	subi	r4,r5,THREAD
 	fromreal(r4)
-	PPC_STL	r4,OFF(last_task_used_math)(r3)
+	PPC_STL	r4,ADDROFF(last_task_used_math)(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	/* we haven't used ctr or xer or lr */
@@ -113,8 +113,8 @@
 1:
 #ifndef CONFIG_SMP
 	li	r5,0
-	LOADBASE(r4,last_task_used_math)
-	PPC_STL	r5,OFF(last_task_used_math)(r4)
+	LOAD_REG_ADDRBASE(r4,last_task_used_math)
+	PPC_STL	r5,ADDROFF(last_task_used_math)(r4)
 #endif /* CONFIG_SMP */
 	blr
 
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 1c066d1..3082684 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -154,12 +154,12 @@
 	bne	100b
 
 #ifdef CONFIG_HMT
-	LOADADDR(r4, .hmt_init)
+	SET_REG_IMMEDIATE(r4, .hmt_init)
 	mtctr	r4
 	bctr
 #else
 #ifdef CONFIG_SMP
-	LOADADDR(r4, .pSeries_secondary_smp_init)
+	LOAD_REG_IMMEDIATE(r4, .pSeries_secondary_smp_init)
 	mtctr	r4
 	mr	r3,r24
 	bctr
@@ -205,9 +205,10 @@
 #define EX_LR		72
 
 /*
- * We're short on space and time in the exception prolog, so we can't use
- * the normal LOADADDR macro. Normally we just need the low halfword of the
- * address, but for Kdump we need the whole low word.
+ * We're short on space and time in the exception prolog, so we can't
+ * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
+ * low halfword of the address, but for Kdump we need the whole low
+ * word.
  */
 #ifdef CONFIG_CRASH_DUMP
 #define LOAD_HANDLER(reg, label)					\
@@ -254,8 +255,9 @@
 
 #define EXCEPTION_PROLOG_ISERIES_2					\
 	mfmsr	r10;							\
-	ld	r11,PACALPPACA+LPPACASRR0(r13);				\
-	ld	r12,PACALPPACA+LPPACASRR1(r13);				\
+	ld	r12,PACALPPACAPTR(r13);					\
+	ld	r11,LPPACASRR0(r12);					\
+	ld	r12,LPPACASRR1(r12);					\
 	ori	r10,r10,MSR_RI;						\
 	mtmsrd	r10,1
 
@@ -634,7 +636,8 @@
 	std	r12,PACA_EXSLB+EX_R12(r13)
 	mfspr	r10,SPRN_SPRG1
 	std	r10,PACA_EXSLB+EX_R13(r13)
-	ld	r12,PACALPPACA+LPPACASRR1(r13);
+	ld	r12,PACALPPACAPTR(r13)
+	ld	r12,LPPACASRR1(r12)
 	b	.slb_miss_realmode
 
 	STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN)
@@ -644,7 +647,8 @@
 	mtspr	SPRN_SPRG1,r13		/* save r13 */
 	mfspr	r13,SPRN_SPRG3		/* get paca address into r13 */
 	std	r3,PACA_EXSLB+EX_R3(r13)
-	ld	r3,PACALPPACA+LPPACASRR0(r13)	/* get SRR0 value */
+	ld	r3,PACALPPACAPTR(r13)
+	ld	r3,LPPACASRR0(r3)	/* get SRR0 value */
 	std	r9,PACA_EXSLB+EX_R9(r13)
 	mfcr	r9
 #ifdef __DISABLED__
@@ -656,7 +660,8 @@
 	std	r12,PACA_EXSLB+EX_R12(r13)
 	mfspr	r10,SPRN_SPRG1
 	std	r10,PACA_EXSLB+EX_R13(r13)
-	ld	r12,PACALPPACA+LPPACASRR1(r13);
+	ld	r12,PACALPPACAPTR(r13)
+	ld	r12,LPPACASRR1(r12)
 	b	.slb_miss_realmode
 
 #ifdef __DISABLED__
@@ -713,7 +718,7 @@
 	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
 					 * should start */
 	sync
-	LOADADDR(r3,current_set)
+	LOAD_REG_IMMEDIATE(r3,current_set)
 	sldi	r28,r24,3		/* get current_set[cpu#] */
 	ldx	r3,r3,r28
 	addi	r1,r3,THREAD_SIZE
@@ -745,17 +750,19 @@
 	.globl decrementer_iSeries_masked
 decrementer_iSeries_masked:
 	li	r11,1
-	stb	r11,PACALPPACA+LPPACADECRINT(r13)
-	LOADBASE(r12,tb_ticks_per_jiffy)
-	lwz	r12,OFF(tb_ticks_per_jiffy)(r12)
+	ld	r12,PACALPPACAPTR(r13)
+	stb	r11,LPPACADECRINT(r12)
+	LOAD_REG_ADDRBASE(r12,tb_ticks_per_jiffy)
+	lwz	r12,ADDROFF(tb_ticks_per_jiffy)(r12)
 	mtspr	SPRN_DEC,r12
 	/* fall through */
 
 	.globl hardware_interrupt_iSeries_masked
 hardware_interrupt_iSeries_masked:
 	mtcrf	0x80,r9		/* Restore regs */
-	ld	r11,PACALPPACA+LPPACASRR0(r13)
-	ld	r12,PACALPPACA+LPPACASRR1(r13)
+	ld	r12,PACALPPACAPTR(r13)
+	ld	r11,LPPACASRR0(r12)
+	ld	r12,LPPACASRR1(r12)
 	mtspr	SPRN_SRR0,r11
 	mtspr	SPRN_SRR1,r12
 	ld	r9,PACA_EXGEN+EX_R9(r13)
@@ -994,7 +1001,8 @@
 	ld	r3,PACA_EXSLB+EX_R3(r13)
 	lwz	r9,PACA_EXSLB+EX_CCR(r13)	/* get saved CR */
 #ifdef CONFIG_PPC_ISERIES
-	ld	r11,PACALPPACA+LPPACASRR0(r13)	/* get SRR0 value */
+	ld	r11,PACALPPACAPTR(r13)
+	ld	r11,LPPACASRR0(r11)		/* get SRR0 value */
 #endif /* CONFIG_PPC_ISERIES */
 
 	mtlr	r10
@@ -1412,7 +1420,7 @@
 	 * physical cpu id in r24, we need to search the pacas to find
 	 * which logical id maps to our physical one.
 	 */
-	LOADADDR(r13, paca) 		/* Get base vaddr of paca array	 */
+	LOAD_REG_IMMEDIATE(r13, paca)	/* Get base vaddr of paca array	 */
 	li	r5,0			/* logical cpu id                */
 1:	lhz	r6,PACAHWCPUID(r13)	/* Load HW procid from paca      */
 	cmpw	r6,r24			/* Compare to our id             */
@@ -1446,8 +1454,8 @@
 #ifdef CONFIG_PPC_ISERIES
 _STATIC(__start_initialization_iSeries)
 	/* Clear out the BSS */
-	LOADADDR(r11,__bss_stop)
-	LOADADDR(r8,__bss_start)
+	LOAD_REG_IMMEDIATE(r11,__bss_stop)
+	LOAD_REG_IMMEDIATE(r8,__bss_start)
 	sub	r11,r11,r8		/* bss size			*/
 	addi	r11,r11,7		/* round up to an even double word */
 	rldicl. r11,r11,61,3		/* shift right by 3		*/
@@ -1458,17 +1466,17 @@
 3:	stdu	r0,8(r8)
 	bdnz	3b
 4:
-	LOADADDR(r1,init_thread_union)
+	LOAD_REG_IMMEDIATE(r1,init_thread_union)
 	addi	r1,r1,THREAD_SIZE
 	li	r0,0
 	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
 
-	LOADADDR(r3,cpu_specs)
-	LOADADDR(r4,cur_cpu_spec)
+	LOAD_REG_IMMEDIATE(r3,cpu_specs)
+	LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
 	li	r5,0
 	bl	.identify_cpu
 
-	LOADADDR(r2,__toc_start)
+	LOAD_REG_IMMEDIATE(r2,__toc_start)
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
@@ -1528,7 +1536,7 @@
 	li	r24,0
 
 	/* Switch off MMU if not already */
-	LOADADDR(r4, .__after_prom_start - KERNELBASE)
+	LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
 	add	r4,r4,r30
 	bl	.__mmu_off
 	b	.__after_prom_start
@@ -1548,7 +1556,7 @@
 	/* put a relocation offset into r3 */
 	bl	.reloc_offset
 
-	LOADADDR(r2,__toc_start)
+	LOAD_REG_IMMEDIATE(r2,__toc_start)
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
@@ -1588,9 +1596,9 @@
  */
 	bl	.reloc_offset
 	mr	r26,r3
-	SET_REG_TO_CONST(r27,KERNELBASE)
+	LOAD_REG_IMMEDIATE(r27, KERNELBASE)
 
-	LOADADDR(r3, PHYSICAL_START)	/* target addr */
+	LOAD_REG_IMMEDIATE(r3, PHYSICAL_START)	/* target addr */
 
 	// XXX FIXME: Use phys returned by OF (r30)
 	add	r4,r27,r26 		/* source addr			 */
@@ -1598,7 +1606,7 @@
 					/*   i.e. where we are running	 */
 					/*	the source addr		 */
 
-	LOADADDR(r5,copy_to_here)	/* # bytes of memory to copy	 */
+	LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
 	sub	r5,r5,r27
 
 	li	r6,0x100		/* Start offset, the first 0x100 */
@@ -1608,11 +1616,11 @@
 					/* this includes the code being	 */
 					/* executed here.		 */
 
-	LOADADDR(r0, 4f)		/* Jump to the copy of this code */
+	LOAD_REG_IMMEDIATE(r0, 4f)	/* Jump to the copy of this code */
 	mtctr	r0			/* that we just made/relocated	 */
 	bctr
 
-4:	LOADADDR(r5,klimit)
+4:	LOAD_REG_IMMEDIATE(r5,klimit)
 	add	r5,r5,r26
 	ld	r5,0(r5)		/* get the value of klimit */
 	sub	r5,r5,r27
@@ -1694,7 +1702,7 @@
 	mtmsrd	r3			/* RI on */
 
 	/* Set up a paca value for this processor. */
-	LOADADDR(r4, paca) 		 /* Get base vaddr of paca array	*/
+	LOAD_REG_IMMEDIATE(r4, paca)	/* Get base vaddr of paca array	*/
 	mulli	r13,r24,PACA_SIZE	 /* Calculate vaddr of right paca */
 	add	r13,r13,r4		/* for this processor.		*/
 	mtspr	SPRN_SPRG3,r13		 /* Save vaddr of paca in SPRG3	*/
@@ -1731,7 +1739,7 @@
 	bl	.early_setup_secondary
 
 	/* Initialize the kernel stack.  Just a repeat for iSeries.	 */
-	LOADADDR(r3,current_set)
+	LOAD_REG_ADDR(r3, current_set)
 	sldi	r28,r24,3		/* get current_set[cpu#]	 */
 	ldx	r1,r3,r28
 	addi	r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
@@ -1742,8 +1750,8 @@
 	mtlr	r7
 
 	/* enable MMU and jump to start_secondary */
-	LOADADDR(r3,.start_secondary_prolog)
-	SET_REG_TO_CONST(r4, MSR_KERNEL)
+	LOAD_REG_ADDR(r3, .start_secondary_prolog)
+	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
 #ifdef DO_SOFT_DISABLE
 	ori	r4,r4,MSR_EE
 #endif
@@ -1792,8 +1800,8 @@
 	 * be detached from the kernel completely. Besides, we need
 	 * to clear it now for kexec-style entry.
 	 */
-	LOADADDR(r11,__bss_stop)
-	LOADADDR(r8,__bss_start)
+	LOAD_REG_IMMEDIATE(r11,__bss_stop)
+	LOAD_REG_IMMEDIATE(r8,__bss_start)
 	sub	r11,r11,r8		/* bss size			*/
 	addi	r11,r11,7		/* round up to an even double word */
 	rldicl. r11,r11,61,3		/* shift right by 3		*/
@@ -1831,7 +1839,7 @@
 	/* up the htab.  This is done because we have relocated the  */
 	/* kernel but are still running in real mode. */
 
-	LOADADDR(r3,init_thread_union)
+	LOAD_REG_IMMEDIATE(r3,init_thread_union)
 	add	r3,r3,r26
 
 	/* set up a stack pointer (physical address) */
@@ -1840,14 +1848,14 @@
 	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
 
 	/* set up the TOC (physical address) */
-	LOADADDR(r2,__toc_start)
+	LOAD_REG_IMMEDIATE(r2,__toc_start)
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 	add	r2,r2,r26
 
-	LOADADDR(r3,cpu_specs)
+	LOAD_REG_IMMEDIATE(r3, cpu_specs)
 	add	r3,r3,r26
-	LOADADDR(r4,cur_cpu_spec)
+	LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
 	add	r4,r4,r26
 	mr	r5,r26
 	bl	.identify_cpu
@@ -1863,11 +1871,11 @@
 	 * nowhere it can be initialized differently before we reach this
 	 * code
 	 */
-	LOADADDR(r27, boot_cpuid)
+	LOAD_REG_IMMEDIATE(r27, boot_cpuid)
 	add	r27,r27,r26
 	lwz	r27,0(r27)
 
-	LOADADDR(r24, paca) 		/* Get base vaddr of paca array	 */
+	LOAD_REG_IMMEDIATE(r24, paca) 	/* Get base vaddr of paca array	 */
 	mulli	r13,r27,PACA_SIZE	/* Calculate vaddr of right paca */
 	add	r13,r13,r24		/* for this processor.		 */
 	add	r13,r13,r26		/* convert to physical addr	 */
@@ -1880,8 +1888,8 @@
 	mr	r3,r31
  	bl	.early_setup
 
-	LOADADDR(r3,.start_here_common)
-	SET_REG_TO_CONST(r4, MSR_KERNEL)
+	LOAD_REG_IMMEDIATE(r3, .start_here_common)
+	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
 	mtspr	SPRN_SRR0,r3
 	mtspr	SPRN_SRR1,r4
 	rfid
@@ -1895,7 +1903,7 @@
 	/* The following code sets up the SP and TOC now that we are */
 	/* running with translation enabled. */
 
-	LOADADDR(r3,init_thread_union)
+	LOAD_REG_IMMEDIATE(r3,init_thread_union)
 
 	/* set up the stack */
 	addi	r1,r3,THREAD_SIZE
@@ -1908,16 +1916,16 @@
 	li	r3,0
 	bl	.do_cpu_ftr_fixups
 
-	LOADADDR(r26, boot_cpuid)
+	LOAD_REG_IMMEDIATE(r26, boot_cpuid)
 	lwz	r26,0(r26)
 
-	LOADADDR(r24, paca) 		/* Get base vaddr of paca array  */
+	LOAD_REG_IMMEDIATE(r24, paca)	/* Get base vaddr of paca array  */
 	mulli	r13,r26,PACA_SIZE	/* Calculate vaddr of right paca */
 	add	r13,r13,r24		/* for this processor.		 */
 	mtspr	SPRN_SPRG3,r13
 
 	/* ptr to current */
-	LOADADDR(r4,init_task)
+	LOAD_REG_IMMEDIATE(r4, init_task)
 	std	r4,PACACURRENT(r13)
 
 	/* Load the TOC */
@@ -1940,7 +1948,7 @@
 
 _GLOBAL(hmt_init)
 #ifdef CONFIG_HMT
-	LOADADDR(r5, hmt_thread_data)
+	LOAD_REG_IMMEDIATE(r5, hmt_thread_data)
 	mfspr	r7,SPRN_PVR
 	srwi	r7,r7,16
 	cmpwi	r7,0x34			/* Pulsar  */
@@ -1961,7 +1969,7 @@
 	b	101f
 
 __hmt_secondary_hold:
-	LOADADDR(r5, hmt_thread_data)
+	LOAD_REG_IMMEDIATE(r5, hmt_thread_data)
 	clrldi	r5,r5,4
 	li	r7,0
 	mfspr	r6,SPRN_PIR
@@ -1989,7 +1997,7 @@
 
 #ifdef CONFIG_HMT
 _GLOBAL(hmt_start_secondary)
-	LOADADDR(r4,__hmt_secondary_hold)
+	LOAD_REG_IMMEDIATE(r4,__hmt_secondary_hold)
 	clrldi	r4,r4,4
 	mtspr	SPRN_NIADORM, r4
 	mfspr	r4, SPRN_MSRDORM
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index 1494e2f..c16b4af 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -38,14 +38,14 @@
 	/* We must dynamically check for the NAP feature as it
 	 * can be cleared by CPU init after the fixups are done
 	 */
-	LOADBASE(r3,cur_cpu_spec)
-	ld	r4,OFF(cur_cpu_spec)(r3)
+	LOAD_REG_ADDRBASE(r3,cur_cpu_spec)
+	ld	r4,ADDROFF(cur_cpu_spec)(r3)
 	ld	r4,CPU_SPEC_FEATURES(r4)
 	andi.	r0,r4,CPU_FTR_CAN_NAP
 	beqlr
 	/* Now check if user or arch enabled NAP mode */
-	LOADBASE(r3,powersave_nap)
-	lwz	r4,OFF(powersave_nap)(r3)
+	LOAD_REG_ADDRBASE(r3,powersave_nap)
+	lwz	r4,ADDROFF(powersave_nap)(r3)
 	cmpwi	0,r4,0
 	beqlr
 
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5651032..d1fffce 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -238,14 +238,10 @@
         irq_exit();
 
 #ifdef CONFIG_PPC_ISERIES
-	{
-		struct paca_struct *lpaca = get_paca();
-
-		if (lpaca->lppaca.int_dword.fields.decr_int) {
-			lpaca->lppaca.int_dword.fields.decr_int = 0;
-			/* Signal a fake decrementer interrupt */
-			timer_interrupt(regs);
-		}
+	if (get_lppaca()->int_dword.fields.decr_int) {
+		get_lppaca()->int_dword.fields.decr_int = 0;
+		/* Signal a fake decrementer interrupt */
+		timer_interrupt(regs);
 	}
 #endif
 }
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 9dda16c..1ae96a8 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -55,15 +55,13 @@
 {
 	unsigned long sum_purr = 0;
 	int cpu;
-	struct paca_struct *lpaca;
 
 	for_each_cpu(cpu) {
-		lpaca = paca + cpu;
-		sum_purr += lpaca->lppaca.emulated_time_base;
+		sum_purr += lppaca[cpu].emulated_time_base;
 
 #ifdef PURR_DEBUG
 		printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n",
-			cpu, lpaca->lppaca.emulated_time_base);
+			cpu, lppaca[cpu].emulated_time_base);
 #endif
 	}
 	return sum_purr;
@@ -79,12 +77,11 @@
 	unsigned long pool_id, lp_index;
 	int shared, entitled_capacity, max_entitled_capacity;
 	int processors, max_processors;
-	struct paca_struct *lpaca = get_paca();
 	unsigned long purr = get_purr();
 
 	seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
 
-	shared = (int)(lpaca->lppaca_ptr->shared_proc);
+	shared = (int)(get_lppaca()->shared_proc);
 	seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n",
 		   e2a(xItExtVpdPanel.mfgID[2]),
 		   e2a(xItExtVpdPanel.mfgID[3]),
@@ -402,7 +399,7 @@
 			   (h_resource >> 0 * 8) & 0xffff);
 
 		/* pool related entries are apropriate for shared configs */
-		if (paca[0].lppaca.shared_proc) {
+		if (lppaca[0].shared_proc) {
 
 			h_pic(&pool_idle_time, &pool_procs);
 
@@ -451,7 +448,7 @@
 	seq_printf(m, "partition_potential_processors=%d\n",
 		   partition_potential_processors);
 
-	seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.shared_proc);
+	seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 01d0d97..be98202 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -68,7 +68,7 @@
 	mflr	r0
 	bl	1f
 1:	mflr	r3
-	LOADADDR(r4,1b)
+	LOAD_REG_IMMEDIATE(r4,1b)
 	subf	r3,r4,r3
 	mtlr	r0
 	blr
@@ -80,7 +80,7 @@
 	mflr	r0
 	bl	1f
 1:	mflr	r5
-	LOADADDR(r4,1b)
+	LOAD_REG_IMMEDIATE(r4,1b)
 	subf	r5,r4,r5
 	add	r3,r3,r5
 	mtlr	r0
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index ae48a00..2778cce 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -39,7 +39,7 @@
 	mflr	r0
 	bl	1f
 1:	mflr	r3
-	LOADADDR(r4,1b)
+	LOAD_REG_IMMEDIATE(r4,1b)
 	subf	r3,r4,r3
 	mtlr	r0
 	blr
@@ -51,7 +51,7 @@
 	mflr	r0
 	bl	1f
 1:	mflr	r5
-	LOADADDR(r4,1b)
+	LOAD_REG_IMMEDIATE(r4,1b)
 	subf	r5,r4,r5
 	add	r3,r3,r5
 	mtlr	r0
@@ -498,15 +498,15 @@
  */
 _GLOBAL(do_cpu_ftr_fixups)
 	/* Get CPU 0 features */
-	LOADADDR(r6,cur_cpu_spec)
+	LOAD_REG_IMMEDIATE(r6,cur_cpu_spec)
 	sub	r6,r6,r3
 	ld	r4,0(r6)
 	sub	r4,r4,r3
 	ld	r4,CPU_SPEC_FEATURES(r4)
 	/* Get the fixup table */
-	LOADADDR(r6,__start___ftr_fixup)
+	LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup)
 	sub	r6,r6,r3
-	LOADADDR(r7,__stop___ftr_fixup)
+	LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup)
 	sub	r7,r7,r3
 	/* Do the fixup */
 1:	cmpld	r6,r7
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 7065e40..22d83d4 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -132,6 +132,8 @@
 struct bus_type of_platform_bus_type = {
        .name	= "of_platform",
        .match	= of_platform_bus_match,
+       .probe	= of_device_probe,
+       .remove	= of_device_remove,
        .suspend	= of_device_suspend,
        .resume	= of_device_resume,
 };
@@ -150,8 +152,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &of_platform_bus_type;
-	drv->driver.probe = of_device_probe;
-	drv->driver.remove = of_device_remove;
 
 	/* register with core */
 	count = driver_register(&drv->driver);
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 999bdd8..5d1b708 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -25,6 +25,28 @@
  * field correctly */
 extern unsigned long __toc_start;
 
+/*
+ * iSeries structure which the hypervisor knows about - this structure
+ * should not cross a page boundary.  The vpa_init/register_vpa call
+ * is now known to fail if the lppaca structure crosses a page
+ * boundary.  The lppaca is also used on POWER5 pSeries boxes.  The
+ * lppaca is 640 bytes long, and cannot readily change since the
+ * hypervisor knows its layout, so a 1kB alignment will suffice to
+ * ensure that it doesn't cross a page boundary.
+ */
+struct lppaca lppaca[] = {
+	[0 ... (NR_CPUS-1)] = {
+		.desc = 0xd397d781,	/* "LpPa" */
+		.size = sizeof(struct lppaca),
+		.dyn_proc_status = 2,
+		.decr_val = 0x00ff0000,
+		.fpregs_in_use = 1,
+		.end_of_quantum = 0xfffffffffffffffful,
+		.slb_count = 64,
+		.vmxregs_in_use = 0,
+	},
+};
+
 /* The Paca is an array with one entry per processor.  Each contains an
  * lppaca, which contains the information shared between the
  * hypervisor and Linux.
@@ -35,27 +57,17 @@
  * processor (not thread).
  */
 #define PACA_INIT_COMMON(number, start, asrr, asrv)			    \
+	.lppaca_ptr = &lppaca[number],					    \
 	.lock_token = 0x8000,						    \
 	.paca_index = (number),		/* Paca Index */		    \
 	.kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,		    \
 	.stab_real = (asrr), 		/* Real pointer to segment table */ \
 	.stab_addr = (asrv),		/* Virt pointer to segment table */ \
 	.cpu_start = (start),		/* Processor start */		    \
-	.hw_cpu_id = 0xffff,						    \
-	.lppaca = {							    \
-		.desc = 0xd397d781,	/* "LpPa" */			    \
-		.size = sizeof(struct lppaca),				    \
-		.dyn_proc_status = 2,					    \
-		.decr_val = 0x00ff0000,					    \
-		.fpregs_in_use = 1,					    \
-		.end_of_quantum = 0xfffffffffffffffful,			    \
-		.slb_count = 64,					    \
-		.vmxregs_in_use = 0,					    \
-	},								    \
+	.hw_cpu_id = 0xffff,
 
 #ifdef CONFIG_PPC_ISERIES
 #define PACA_INIT_ISERIES(number)					    \
-	.lppaca_ptr = &paca[number].lppaca,				    \
 	.reg_save_ptr = &iseries_reg_save[number],
 
 #define PACA_INIT(number)						    \
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 16d9a90..d9a459c 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -230,8 +230,7 @@
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
 #endif /* CONFIG_8xx */
-#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) ||\
-	defined(CONFIG_83xx)
+#if defined(CONFIG_8xx) || defined(CONFIG_40x)
 EXPORT_SYMBOL(__res);
 #endif
 
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 02e2115..d50c8df 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1627,6 +1627,11 @@
 		kfree(prop->value);
 		kfree(prop);
 		prop = next;
+
+		if (!prop) {
+			prop = node->deadprops;
+			node->deadprops = NULL;
+		}
 	}
 	kfree(node->intrs);
 	kfree(node->full_name);
@@ -1774,6 +1779,23 @@
 __initcall(prom_reconfig_setup);
 #endif
 
+struct property *of_find_property(struct device_node *np, const char *name,
+				  int *lenp)
+{
+	struct property *pp;
+
+	read_lock(&devtree_lock);
+	for (pp = np->properties; pp != 0; pp = pp->next)
+		if (strcmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			break;
+		}
+	read_unlock(&devtree_lock);
+
+	return pp;
+}
+
 /*
  * Find a property with a given name for a given node
  * and return the value.
@@ -1781,15 +1803,8 @@
 unsigned char *get_property(struct device_node *np, const char *name,
 			    int *lenp)
 {
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next)
-		if (strcmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			return pp->value;
-		}
-	return NULL;
+	struct property *pp = of_find_property(np,name,lenp);
+	return pp ? pp->value : NULL;
 }
 EXPORT_SYMBOL(get_property);
 
@@ -1823,4 +1838,82 @@
 	return 0;
 }
 
+/*
+ * Remove a property from a node.  Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property.  Instead we just move the property
+ * to the "dead properties" list, so it won't be found any more.
+ */
+int prom_remove_property(struct device_node *np, struct property *prop)
+{
+	struct property **next;
+	int found = 0;
 
+	write_lock(&devtree_lock);
+	next = &np->properties;
+	while (*next) {
+		if (*next == prop) {
+			/* found the node */
+			*next = prop->next;
+			prop->next = np->deadprops;
+			np->deadprops = prop;
+			found = 1;
+			break;
+		}
+		next = &(*next)->next;
+	}
+	write_unlock(&devtree_lock);
+
+	if (!found)
+		return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+	/* try to remove the proc node as well */
+	if (np->pde)
+		proc_device_tree_remove_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+	return 0;
+}
+
+/*
+ * Update a property in a node.  Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property.  Instead we just move the property
+ * to the "dead properties" list, and add the new property to the
+ * property list
+ */
+int prom_update_property(struct device_node *np,
+			 struct property *newprop,
+			 struct property *oldprop)
+{
+	struct property **next;
+	int found = 0;
+
+	write_lock(&devtree_lock);
+	next = &np->properties;
+	while (*next) {
+		if (*next == oldprop) {
+			/* found the node */
+			newprop->next = oldprop->next;
+			*next = newprop;
+			oldprop->next = np->deadprops;
+			np->deadprops = oldprop;
+			found = 1;
+			break;
+		}
+		next = &(*next)->next;
+	}
+	write_unlock(&devtree_lock);
+
+	if (!found)
+		return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+	/* try to add to proc as well if it was initialized */
+	if (np->pde)
+		proc_device_tree_update_prop(np->pde, newprop, oldprop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 309ae1d..a8099c8 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -113,7 +113,8 @@
 
 static int of_bus_pci_match(struct device_node *np)
 {
-	return !strcmp(np->type, "pci");
+	/* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
+	return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 4b9cfe4..7fe4a5c 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -36,6 +36,11 @@
 	.lock = SPIN_LOCK_UNLOCKED
 };
 
+struct rtas_suspend_me_data {
+	long waiting;
+	struct rtas_args *args;
+};
+
 EXPORT_SYMBOL(rtas);
 
 DEFINE_SPINLOCK(rtas_data_buf_lock);
@@ -556,6 +561,80 @@
 	} while (status == RTAS_BUSY);
 }
 
+static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
+#ifdef CONFIG_PPC_PSERIES
+static void rtas_percpu_suspend_me(void *info)
+{
+	long rc;
+	long flags;
+	struct rtas_suspend_me_data *data =
+		(struct rtas_suspend_me_data *)info;
+
+	/*
+	 * We use "waiting" to indicate our state.  As long
+	 * as it is >0, we are still trying to all join up.
+	 * If it goes to 0, we have successfully joined up and
+	 * one thread got H_Continue.  If any error happens,
+	 * we set it to <0.
+	 */
+	local_irq_save(flags);
+	do {
+		rc = plpar_hcall_norets(H_JOIN);
+		smp_rmb();
+	} while (rc == H_Success && data->waiting > 0);
+	if (rc == H_Success)
+		goto out;
+
+	if (rc == H_Continue) {
+		data->waiting = 0;
+		rtas_call(ibm_suspend_me_token, 0, 1,
+			  data->args->args);
+	} else {
+		data->waiting = -EBUSY;
+		printk(KERN_ERR "Error on H_Join hypervisor call\n");
+	}
+
+out:
+	/* before we restore interrupts, make sure we don't
+	 * generate a spurious soft lockup errors
+	 */
+	touch_softlockup_watchdog();
+	local_irq_restore(flags);
+	return;
+}
+
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+	int i;
+
+	struct rtas_suspend_me_data data;
+
+	data.waiting = 1;
+	data.args = args;
+
+	/* Call function on all CPUs.  One of us will make the
+	 * rtas call
+	 */
+	if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
+		data.waiting = -EINVAL;
+
+	if (data.waiting != 0)
+		printk(KERN_ERR "Error doing global join\n");
+
+	/* Prod each CPU.  This won't hurt, and will wake
+	 * anyone we successfully put to sleep with H_Join
+	 */
+	for_each_cpu(i)
+		plpar_hcall_norets(H_PROD, i);
+
+	return data.waiting;
+}
+#else /* CONFIG_PPC_PSERIES */
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+	return -ENOSYS;
+}
+#endif
 
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
@@ -563,6 +642,7 @@
 	unsigned long flags;
 	char *buff_copy, *errbuf = NULL;
 	int nargs;
+	int rc;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -581,6 +661,17 @@
 			   nargs * sizeof(rtas_arg_t)) != 0)
 		return -EFAULT;
 
+	if (args.token == RTAS_UNKNOWN_SERVICE)
+		return -EINVAL;
+
+	/* Need to handle ibm,suspend_me call specially */
+	if (args.token == ibm_suspend_me_token) {
+		rc = rtas_ibm_suspend_me(&args);
+		if (rc)
+			return rc;
+		goto copy_return;
+	}
+
 	buff_copy = get_errorlog_buffer();
 
 	spin_lock_irqsave(&rtas.lock, flags);
@@ -604,6 +695,7 @@
 		kfree(buff_copy);
 	}
 
+ copy_return:
 	/* Copy out args. */
 	if (copy_to_user(uargs->args + nargs,
 			 args.args + nargs,
@@ -675,8 +767,10 @@
 	 * the stop-self token if any
 	 */
 #ifdef CONFIG_PPC64
-	if (_machine == PLATFORM_PSERIES_LPAR)
+	if (_machine == PLATFORM_PSERIES_LPAR) {
 		rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
+		ibm_suspend_me_token = rtas_token("ibm,suspend-me");
+	}
 #endif
 	rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
 
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index d5c52fa..be12041 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -100,7 +100,8 @@
 void machine_restart(char *cmd)
 {
 	machine_shutdown();
-	ppc_md.restart(cmd);
+	if (ppc_md.restart)
+		ppc_md.restart(cmd);
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
@@ -112,7 +113,8 @@
 void machine_power_off(void)
 {
 	machine_shutdown();
-	ppc_md.power_off();
+	if (ppc_md.power_off)
+		ppc_md.power_off();
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
@@ -129,7 +131,8 @@
 void machine_halt(void)
 {
 	machine_shutdown();
-	ppc_md.halt();
+	if (ppc_md.halt)
+		ppc_md.halt();
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 56f50e9..c4a294d 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -431,7 +431,7 @@
 	profile_tick(CPU_PROFILING, regs);
 
 #ifdef CONFIG_PPC_ISERIES
-	get_paca()->lppaca.int_dword.fields.decr_int = 0;
+	get_lppaca()->int_dword.fields.decr_int = 0;
 #endif
 
 	while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu)))
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 13c4149..13c655b 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -76,7 +76,7 @@
 	struct vio_dev *viodev = to_vio_dev(dev);
 	struct vio_driver *viodrv = to_vio_driver(dev->driver);
 
-	if (viodrv->shutdown)
+	if (dev->driver && viodrv->shutdown)
 		viodrv->shutdown(viodev);
 }
 
@@ -91,9 +91,6 @@
 
 	/* fill in 'struct driver' fields */
 	viodrv->driver.bus = &vio_bus_type;
-	viodrv->driver.probe = vio_bus_probe;
-	viodrv->driver.remove = vio_bus_remove;
-	viodrv->driver.shutdown = vio_bus_shutdown;
 
 	return driver_register(&viodrv->driver);
 }
@@ -295,4 +292,7 @@
 	.name = "vio",
 	.uevent = vio_hotplug,
 	.match = vio_bus_match,
+	.probe = vio_bus_probe,
+	.remove = vio_bus_remove,
+	.shutdown = vio_bus_shutdown,
 };
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index 35bd03c..8362fa2 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -28,15 +28,13 @@
 void __spin_yield(raw_spinlock_t *lock)
 {
 	unsigned int lock_value, holder_cpu, yield_count;
-	struct paca_struct *holder_paca;
 
 	lock_value = lock->slock;
 	if (lock_value == 0)
 		return;
 	holder_cpu = lock_value & 0xffff;
 	BUG_ON(holder_cpu >= NR_CPUS);
-	holder_paca = &paca[holder_cpu];
-	yield_count = holder_paca->lppaca.yield_count;
+	yield_count = lppaca[holder_cpu].yield_count;
 	if ((yield_count & 1) == 0)
 		return;		/* virtual cpu is currently running */
 	rmb();
@@ -60,15 +58,13 @@
 {
 	int lock_value;
 	unsigned int holder_cpu, yield_count;
-	struct paca_struct *holder_paca;
 
 	lock_value = rw->lock;
 	if (lock_value >= 0)
 		return;		/* no write lock at present */
 	holder_cpu = lock_value & 0xffff;
 	BUG_ON(holder_cpu >= NR_CPUS);
-	holder_paca = &paca[holder_cpu];
-	yield_count = holder_paca->lppaca.yield_count;
+	yield_count = lppaca[holder_cpu].yield_count;
 	if ((yield_count & 1) == 0)
 		return;		/* virtual cpu is currently running */
 	rmb();
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 71615eb..cc2535b 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -140,19 +140,19 @@
 
 	switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
-		case RS64:
+		case PPC_OPROFILE_RS64:
 			model = &op_model_rs64;
 			break;
-		case POWER4:
+		case PPC_OPROFILE_POWER4:
 			model = &op_model_power4;
 			break;
 #else
-		case G4:
+		case PPC_OPROFILE_G4:
 			model = &op_model_7450;
 			break;
 #endif
 #ifdef CONFIG_FSL_BOOKE
-		case BOOKE:
+		case PPC_OPROFILE_BOOKE:
 			model = &op_model_fsl_booke;
 			break;
 #endif
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index b20812d..7675e67 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -7,6 +7,7 @@
 
 config MPC834x_SYS
 	bool "Freescale MPC834x SYS"
+	select DEFAULT_UIMAGE
 	help
 	  This option enables support for the MPC 834x SYS evaluation board.
 
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
new file mode 100644
index 0000000..2098dd0
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -0,0 +1,243 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc834x_sys.c
+ *
+ * MPC834x SYS board specific routines
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc83xx.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc83xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+#ifdef CONFIG_PCI
+extern int mpc83xx_pci2_busno;
+
+static int
+mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *       A      B      C      D
+	     */
+	{
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* idsel 0x11 */
+		{PIRQC, PIRQD, PIRQA, PIRQB},	/* idsel 0x12 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},	/* idsel 0x13 */
+		{0, 0, 0, 0},
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* idsel 0x15 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},	/* idsel 0x16 */
+		{PIRQC, PIRQD, PIRQA, PIRQB},	/* idsel 0x17 */
+		{PIRQB, PIRQC, PIRQD, PIRQA},	/* idsel 0x18 */
+		{0, 0, 0, 0},			/* idsel 0x19 */
+		{0, 0, 0, 0},			/* idsel 0x20 */
+	};
+
+	const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static int
+mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (mpc83xx_pci2_busno)
+		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc834x_sys_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc834x_sys_setup_arch()", 0);
+
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np != 0) {
+		unsigned int *fp = (int *) get_property(np, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_PCI
+	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+		add_bridge(np);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = mpc83xx_map_irq;
+	ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef  CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_HDA1;
+#endif
+}
+
+void __init
+mpc834x_sys_init_IRQ(void)
+{
+	u8 senses[8] = {
+		0,			/* EXT 0 */
+		IRQ_SENSE_LEVEL,	/* EXT 1 */
+		IRQ_SENSE_LEVEL,	/* EXT 2 */
+		0,			/* EXT 3 */
+#ifdef CONFIG_PCI
+		IRQ_SENSE_LEVEL,	/* EXT 4 */
+		IRQ_SENSE_LEVEL,	/* EXT 5 */
+		IRQ_SENSE_LEVEL,	/* EXT 6 */
+		IRQ_SENSE_LEVEL,	/* EXT 7 */
+#else
+		0,			/* EXT 4 */
+		0,			/* EXT 5 */
+		0,			/* EXT 6 */
+		0,			/* EXT 7 */
+#endif
+	};
+
+	ipic_init(get_immrbase() + 0x00700, 0, 0, senses, 8);
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	ipic_set_default_priority();
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong	ds1374_get_rtc_time(void);
+extern int	ds1374_set_rtc_time(ulong);
+
+static int __init
+mpc834x_rtc_hookup(void)
+{
+	struct timespec	tv;
+
+	ppc_md.get_rtc_time = ds1374_get_rtc_time;
+	ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = (ppc_md.get_rtc_time)();
+	do_settimeofday(&tv);
+
+	return 0;
+}
+late_initcall(mpc834x_rtc_hookup);
+#endif
+
+static void
+mpc83xx_restart(char *cmd)
+{
+#define RST_OFFSET	0x00000900
+#define RST_PROT_REG	0x00000018
+#define RST_CTRL_REG	0x0000001c
+	__be32 __iomem *reg;
+
+	// map reset register space
+	reg = ioremap(get_immrbase() + 0x900, 0xff);
+
+	local_irq_disable();
+
+	/* enable software reset "RSTE" */
+	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+
+	/* set software hard reset */
+	out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
+	for(;;);
+}
+
+static long __init
+mpc83xx_time_init(void)
+{
+#define SPCR_OFFSET	0x00000110
+#define SPCR_TBEN	0x00400000
+	__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
+	__be32 tmp;
+
+	tmp = in_be32(spcr);
+	out_be32(spcr, tmp|SPCR_TBEN);
+
+	iounmap(spcr);
+
+	return 0;
+}
+void __init
+platform_init(void)
+{
+	/* setup the PowerPC module struct */
+	ppc_md.setup_arch = mpc834x_sys_setup_arch;
+
+	ppc_md.init_IRQ = mpc834x_sys_init_IRQ;
+	ppc_md.get_irq = ipic_get_irq;
+
+	ppc_md.restart = mpc83xx_restart;
+
+	ppc_md.time_init = mpc83xx_time_init;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = generic_calibrate_decr;
+
+	ppc_md.progress = udbg_progress;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc834x_sys_init(): exit", 0);
+
+	return;
+}
+
+
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h
new file mode 100644
index 0000000..e4ca39f
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h
@@ -0,0 +1,23 @@
+/*
+ * arch/powerppc/platforms/83xx/mpc834x_sys.h
+ *
+ * MPC834X SYS common board definitions
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MACH_MPC83XX_SYS_H__
+#define __MACH_MPC83XX_SYS_H__
+
+#define PIRQA	MPC83xx_IRQ_EXT4
+#define PIRQB	MPC83xx_IRQ_EXT5
+#define PIRQC	MPC83xx_IRQ_EXT6
+#define PIRQD	MPC83xx_IRQ_EXT7
+
+#endif                /* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
new file mode 100644
index 0000000..ce9e66a
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -0,0 +1,14 @@
+#ifndef __MPC83XX_H__
+#define __MPC83XX_H__
+
+#include <linux/init.h>
+#include <linux/device.h>
+
+/*
+ * Declaration for the various functions exported by the
+ * mpc83xx_* files. Mostly for use by mpc83xx_setup
+ */
+
+extern int add_bridge(struct device_node *dev);
+
+#endif /* __MPC83XX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
new file mode 100644
index 0000000..469cdac
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -0,0 +1,99 @@
+/*
+ * FSL SoC setup code
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+int mpc83xx_pci2_busno;
+
+#ifdef CONFIG_PCI
+int __init add_bridge(struct device_node *dev)
+{
+	int len;
+	struct pci_controller *hose;
+	struct resource rsrc;
+	int *bus_range;
+	int primary = 1, has_address = 0;
+	phys_addr_t immr = get_immrbase();
+
+	DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+	/* Fetch host bridge registers address */
+	has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+	/* Get bus range if any */
+	bus_range = (int *) get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s, assume"
+		       " bus 0\n", dev->full_name);
+	}
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return -ENOMEM;
+	hose->arch_data = dev;
+	hose->set_cfg_type = 1;
+
+	hose->first_busno = bus_range ? bus_range[0] : 0;
+	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+	/* MPC83xx supports up to two host controllers one at 0x8500 from immrbar
+	 * the other at 0x8600, we consider the 0x8500 the primary controller
+	 */
+	/* PCI 1 */
+	if ((rsrc.start & 0xfffff) == 0x8500) {
+		setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304);
+	}
+	/* PCI 2*/
+	if ((rsrc.start & 0xfffff) == 0x8600) {
+		setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
+		primary = 0;
+		hose->bus_offset = hose->first_busno;
+		mpc83xx_pci2_busno = hose->first_busno;
+	}
+
+	printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
+	       "Firmware bus number: %d->%d\n",
+		rsrc.start, hose->first_busno, hose->last_busno);
+
+	DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+		hose, hose->cfg_addr, hose->cfg_data);
+
+	/* Interpret the "ranges" property */
+	/* This also maps the I/O region and sets isa_io/mem_base */
+	pci_process_bridge_OF_ranges(hose, dev, primary);
+
+	return 0;
+}
+
+#endif
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index 82c429d..00c52f2 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -135,12 +135,13 @@
 hydra_init(void)
 {
 	struct device_node *np;
+	struct resource r;
 
 	np = find_devices("mac-io");
-	if (np == NULL || np->n_addrs == 0)
+	if (np == NULL || of_address_to_resource(np, 0, &r))
 		return 0;
-	Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
-	printk("Hydra Mac I/O at %lx\n", np->addrs[0].address);
+	Hydra = ioremap(r.start, r.end-r.start);
+	printk("Hydra Mac I/O at %lx\n", r.start);
 	printk("Hydra Feature_Control was %x",
 	       in_le32(&Hydra->Feature_Control));
 	out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
@@ -177,18 +178,24 @@
 {
 	u32 __iomem *reg;
 	u32 val;
-	unsigned long addr = dev->addrs[0].address;
+	struct resource r;
 
-	setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
+	if (of_address_to_resource(dev, 0, &r)) {
+		printk(KERN_ERR "No address for Python PCI controller\n");
+		return;
+	}
 
 	/* Clear the magic go-slow bit */
-	reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40);
+	reg = ioremap(r.start + 0xf6000, 0x40);
+	BUG_ON(!reg); 
 	val = in_be32(&reg[12]);
 	if (val & PRG_CL_RESET_VALID) {
 		out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
 		in_be32(&reg[12]);
 	}
 	iounmap(reg);
+
+	setup_indirect_pci(hose, r.start + 0xf8000, r.start + 0xf8010);
 }
 
 /* Marvell Discovery II based Pegasos 2 */
@@ -218,7 +225,7 @@
 	char *model, *machine;
 	int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
 	struct device_node *root = find_path_device("/");
-
+	struct resource r;
 	/*
 	 * The PCI host bridge nodes on some machines don't have
 	 * properties to adequately identify them, so we have to
@@ -238,7 +245,7 @@
 			continue;
 		++index;
 		/* The GG2 bridge on the LongTrail doesn't have an address */
-		if (dev->n_addrs < 1 && !is_longtrail) {
+		if (of_address_to_resource(dev, 0, &r) && !is_longtrail) {
 			printk(KERN_WARNING "Can't use %s: no address\n",
 			       dev->full_name);
 			continue;
@@ -255,8 +262,8 @@
 			printk(KERN_INFO "PCI buses %d..%d",
 			       bus_range[0], bus_range[1]);
 		printk(" controlled by %s", dev->type);
-		if (dev->n_addrs > 0)
-			printk(" at %lx", dev->addrs[0].address);
+		if (!is_longtrail)
+			printk(" at %lx", r.start);
 		printk("\n");
 
 		hose = pcibios_alloc_controller();
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 4ec8ba7..2dc87aa 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -352,9 +352,10 @@
 		opaddr = opprop[na-1];	/* assume 32-bit */
 		oplen /= na * sizeof(unsigned int);
 	} else {
-		if (np->n_addrs == 0)
+		struct resource r;
+		if (of_address_to_resource(np, 0, &r))
 			return;
-		opaddr = np->addrs[0].address;
+		opaddr = r.start;
 		oplen = 0;
 	}
 
@@ -377,7 +378,7 @@
 	 */
 	if (oplen < len) {
 		printk(KERN_ERR "Insufficient addresses for distributed"
-		       " OpenPIC (%d < %d)\n", np->n_addrs, len);
+		       " OpenPIC (%d < %d)\n", oplen, len);
 		len = oplen;
 	}
 
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 737ee5d..36a0f97 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -21,6 +21,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/init.h>
 #include <linux/bcd.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/nvram.h>
@@ -37,14 +38,16 @@
 long __init chrp_time_init(void)
 {
 	struct device_node *rtcs;
+	struct resource r;
 	int base;
 
 	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
 	if (rtcs == NULL)
 		rtcs = find_compatible_devices("rtc", "ds1385-rtc");
-	if (rtcs == NULL || rtcs->addrs == NULL)
+	if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
 		return 0;
-	base = rtcs->addrs[0].address;
+	
+	base = r.start;
 	nvram_as1 = 0;
 	nvram_as0 = base;
 	nvram_data = base + 1;
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 83442ea..be3fbfc 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -334,14 +334,12 @@
  */
 int iSeries_get_irq(struct pt_regs *regs)
 {
-	struct paca_struct *lpaca;
 	/* -2 means ignore this interrupt */
 	int irq = -2;
 
-	lpaca = get_paca();
 #ifdef CONFIG_SMP
-	if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
-		lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
+	if (get_lppaca()->int_dword.fields.ipi_cnt) {
+		get_lppaca()->int_dword.fields.ipi_cnt = 0;
 		iSeries_smp_message_recv(regs);
 	}
 #endif /* CONFIG_SMP */
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
index dfe7aa1..7641fc7 100644
--- a/arch/powerpc/platforms/iseries/misc.S
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -44,7 +44,8 @@
 	/* Check pending interrupts */
 	/*   A decrementer, IPI or PMC interrupt may have occurred
 	 *   while we were in the hypervisor (which enables) */
-	ld	r4,PACALPPACA+LPPACAANYINT(r13)
+	ld	r4,PACALPPACAPTR(r13)
+	ld	r4,LPPACAANYINT(r4)
 	cmpdi	r4,0
 	beqlr
 
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index c6bbe5c..3f87901 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -538,7 +538,7 @@
  */
 static void __init iSeries_setup_arch(void)
 {
-	if (get_paca()->lppaca.shared_proc) {
+	if (get_lppaca()->shared_proc) {
 		ppc_md.idle_loop = iseries_shared_idle;
 		printk(KERN_INFO "Using shared processor idle loop\n");
 	} else {
@@ -647,7 +647,7 @@
 	 * The decrementer stops during the yield.  Force a fake decrementer
 	 * here and let the timer_interrupt code sort out the actual time.
 	 */
-	get_paca()->lppaca.int_dword.fields.decr_int = 1;
+	get_lppaca()->int_dword.fields.decr_int = 1;
 	process_iSeries_events();
 }
 
@@ -883,7 +883,7 @@
 	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
 
 	for (i = 0; i < NR_CPUS; i++) {
-		if (paca[i].lppaca.dyn_proc_status >= 2)
+		if (lppaca[i].dyn_proc_status >= 2)
 			continue;
 
 		snprintf(p, 32 - (p - buf), "@%d", i);
@@ -891,7 +891,7 @@
 
 		dt_prop_str(dt, "device_type", "cpu");
 
-		index = paca[i].lppaca.dyn_hv_phys_proc_index;
+		index = lppaca[i].dyn_hv_phys_proc_index;
 		d = &xIoHriProcessorVpd[index];
 
 		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index fcb094e..6f9d407 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -91,7 +91,7 @@
 	BUG_ON((nr < 0) || (nr >= NR_CPUS));
 
 	/* Verify that our partition has a processor nr */
-	if (paca[nr].lppaca.dyn_proc_status >= 2)
+	if (lppaca[nr].dyn_proc_status >= 2)
 		return;
 
 	/* The processor is currently spinning, waiting
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 1fe445a..8952528 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -254,11 +254,11 @@
 void vpa_init(int cpu)
 {
 	int hwcpu = get_hard_smp_processor_id(cpu);
-	unsigned long vpa = __pa(&paca[cpu].lppaca);
+	unsigned long vpa = __pa(&lppaca[cpu]);
 	long ret;
 
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
-		paca[cpu].lppaca.vmxregs_in_use = 1;
+		lppaca[cpu].vmxregs_in_use = 1;
 
 	ret = register_vpa(hwcpu, vpa);
 
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index d886416..86cfa6e 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -350,6 +350,100 @@
 	return rv;
 }
 
+static char *parse_node(char *buf, size_t bufsize, struct device_node **npp)
+{
+	char *handle_str;
+	phandle handle;
+	*npp = NULL;
+
+	handle_str = buf;
+
+	buf = strchr(buf, ' ');
+	if (!buf)
+		return NULL;
+	*buf = '\0';
+	buf++;
+
+	handle = simple_strtoul(handle_str, NULL, 10);
+
+	*npp = of_find_node_by_phandle(handle);
+	return buf;
+}
+
+static int do_add_property(char *buf, size_t bufsize)
+{
+	struct property *prop = NULL;
+	struct device_node *np;
+	unsigned char *value;
+	char *name, *end;
+	int length;
+	end = buf + bufsize;
+	buf = parse_node(buf, bufsize, &np);
+
+	if (!np)
+		return -ENODEV;
+
+	if (parse_next_property(buf, end, &name, &length, &value) == NULL)
+		return -EINVAL;
+
+	prop = new_property(name, length, value, NULL);
+	if (!prop)
+		return -ENOMEM;
+
+	prom_add_property(np, prop);
+
+	return 0;
+}
+
+static int do_remove_property(char *buf, size_t bufsize)
+{
+	struct device_node *np;
+	char *tmp;
+	struct property *prop;
+	buf = parse_node(buf, bufsize, &np);
+
+	if (!np)
+		return -ENODEV;
+
+	tmp = strchr(buf,' ');
+	if (tmp)
+		*tmp = '\0';
+
+	if (strlen(buf) == 0)
+		return -EINVAL;
+
+	prop = of_find_property(np, buf, NULL);
+
+	return prom_remove_property(np, prop);
+}
+
+static int do_update_property(char *buf, size_t bufsize)
+{
+	struct device_node *np;
+	unsigned char *value;
+	char *name, *end;
+	int length;
+	struct property *newprop, *oldprop;
+	buf = parse_node(buf, bufsize, &np);
+	end = buf + bufsize;
+
+	if (!np)
+		return -ENODEV;
+
+	if (parse_next_property(buf, end, &name, &length, &value) == NULL)
+		return -EINVAL;
+
+	newprop = new_property(name, length, value, NULL);
+	if (!newprop)
+		return -ENOMEM;
+
+	oldprop = of_find_property(np, name,NULL);
+	if (!oldprop)
+		return -ENODEV;
+
+	return prom_update_property(np, newprop, oldprop);
+}
+
 /**
  * ofdt_write - perform operations on the Open Firmware device tree
  *
@@ -392,6 +486,12 @@
 		rv = do_add_node(tmp, count - (tmp - kbuf));
 	else if (!strcmp(kbuf, "remove_node"))
 		rv = do_remove_node(tmp);
+	else if (!strcmp(kbuf, "add_property"))
+		rv = do_add_property(tmp, count - (tmp - kbuf));
+	else if (!strcmp(kbuf, "remove_property"))
+		rv = do_remove_property(tmp, count - (tmp - kbuf));
+	else if (!strcmp(kbuf, "update_property"))
+		rv = do_update_property(tmp, count - (tmp - kbuf));
 	else
 		rv = -EINVAL;
 out:
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 68b7f08..da6ceba 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -190,7 +190,7 @@
 
 	/* instruct hypervisor to maintain PMCs */
 	if (firmware_has_feature(FW_FEATURE_SPLPAR))
-		get_paca()->lppaca.pmcregs_in_use = 1;
+		get_lppaca()->pmcregs_in_use = 1;
 }
 
 static void __init pSeries_setup_arch(void)
@@ -234,7 +234,7 @@
 	/* Choose an idle loop */
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
 		vpa_init(boot_cpuid);
-		if (get_paca()->lppaca.shared_proc) {
+		if (get_lppaca()->shared_proc) {
 			printk(KERN_INFO "Using shared processor idle loop\n");
 			ppc_md.idle_loop = pseries_shared_idle;
 		} else {
@@ -444,10 +444,10 @@
 
 static inline void dedicated_idle_sleep(unsigned int cpu)
 {
-	struct paca_struct *ppaca = &paca[cpu ^ 1];
+	struct lppaca *plppaca = &lppaca[cpu ^ 1];
 
 	/* Only sleep if the other thread is not idle */
-	if (!(ppaca->lppaca.idle)) {
+	if (!(plppaca->idle)) {
 		local_irq_disable();
 
 		/*
@@ -480,7 +480,6 @@
 
 static void pseries_dedicated_idle(void)
 { 
-	struct paca_struct *lpaca = get_paca();
 	unsigned int cpu = smp_processor_id();
 	unsigned long start_snooze;
 	unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
@@ -491,7 +490,7 @@
 		 * Indicate to the HV that we are idle. Now would be
 		 * a good time to find other work to dispatch.
 		 */
-		lpaca->lppaca.idle = 1;
+		get_lppaca()->idle = 1;
 
 		if (!need_resched()) {
 			start_snooze = get_tb() +
@@ -518,7 +517,7 @@
 			HMT_medium();
 		}
 
-		lpaca->lppaca.idle = 0;
+		get_lppaca()->idle = 0;
 		ppc64_runlatch_on();
 
 		preempt_enable_no_resched();
@@ -532,7 +531,6 @@
 
 static void pseries_shared_idle(void)
 {
-	struct paca_struct *lpaca = get_paca();
 	unsigned int cpu = smp_processor_id();
 
 	while (1) {
@@ -540,7 +538,7 @@
 		 * Indicate to the HV that we are idle. Now would be
 		 * a good time to find other work to dispatch.
 		 */
-		lpaca->lppaca.idle = 1;
+		get_lppaca()->idle = 1;
 
 		while (!need_resched() && !cpu_is_offline(cpu)) {
 			local_irq_disable();
@@ -564,7 +562,7 @@
 			HMT_medium();
 		}
 
-		lpaca->lppaca.idle = 0;
+		get_lppaca()->idle = 0;
 		ppc64_runlatch_on();
 
 		preempt_enable_no_resched();
@@ -588,7 +586,7 @@
 {
 	/* Don't risk a hypervisor call if we're crashing */
 	if (!crash_shutdown) {
-		unsigned long vpa = __pa(&get_paca()->lppaca);
+		unsigned long vpa = __pa(get_lppaca());
 
 		if (unregister_vpa(hard_smp_processor_id(), vpa)) {
 			printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 0ae8413..4c2b356 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
+obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
new file mode 100644
index 0000000..064c9de
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -0,0 +1,317 @@
+/*
+ * FSL SoC setup code
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+#include <mm/mmu_decl.h>
+
+static phys_addr_t immrbase = -1;
+
+phys_addr_t get_immrbase(void)
+{
+	struct device_node *soc;
+
+	if (immrbase != -1)
+		return immrbase;
+
+	soc = of_find_node_by_type(NULL, "soc");
+	if (soc != 0) {
+		unsigned int size;
+		void *prop = get_property(soc, "reg", &size);
+		immrbase = of_translate_address(soc, prop);
+		of_node_put(soc);
+	};
+
+	return immrbase;
+}
+EXPORT_SYMBOL(get_immrbase);
+
+static const char * gfar_tx_intr = "tx";
+static const char * gfar_rx_intr = "rx";
+static const char * gfar_err_intr = "error";
+
+static int __init gfar_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *mdio_dev, *gfar_dev;
+	struct resource res;
+	int ret;
+
+	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) {
+		int k;
+		struct device_node *child = NULL;
+		struct gianfar_mdio_data mdio_data;
+
+		memset(&res, 0, sizeof(res));
+		memset(&mdio_data, 0, sizeof(mdio_data));
+
+		ret = of_address_to_resource(np, 0, &res);
+		if (ret)
+			goto mdio_err;
+
+		mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
+		if (IS_ERR(mdio_dev)) {
+			ret = PTR_ERR(mdio_dev);
+			goto mdio_err;
+		}
+
+		for (k = 0; k < 32; k++)
+			mdio_data.irq[k] = -1;
+
+		while ((child = of_get_next_child(np, child)) != NULL) {
+			if (child->n_intrs) {
+				u32 *id = (u32 *) get_property(child, "reg", NULL);
+				mdio_data.irq[*id] = child->intrs[0].line;
+			}
+		}
+
+		ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data));
+		if (ret)
+			goto mdio_unreg;
+	}
+
+	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) {
+		struct resource r[4];
+		struct device_node *phy, *mdio;
+		struct gianfar_platform_data gfar_data;
+		unsigned int *id;
+		char *model;
+		void *mac_addr;
+		phandle *ph;
+
+		memset(r, 0, sizeof(r));
+		memset(&gfar_data, 0, sizeof(gfar_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto gfar_err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		model = get_property(np, "model", NULL);
+
+		/* If we aren't the FEC we have multiple interrupts */
+		if (model && strcasecmp(model, "FEC")) {
+			r[1].name = gfar_tx_intr;
+
+			r[2].name = gfar_rx_intr;
+			r[2].start = np->intrs[1].line;
+			r[2].end = np->intrs[1].line;
+			r[2].flags = IORESOURCE_IRQ;
+
+			r[3].name = gfar_err_intr;
+			r[3].start = np->intrs[2].line;
+			r[3].end = np->intrs[2].line;
+			r[3].flags = IORESOURCE_IRQ;
+		}
+
+		gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1);
+
+		if (IS_ERR(gfar_dev)) {
+			ret = PTR_ERR(gfar_dev);
+			goto gfar_err;
+		}
+
+		mac_addr = get_property(np, "address", NULL);
+		memcpy(gfar_data.mac_addr, mac_addr, 6);
+
+		if (model && !strcasecmp(model, "TSEC"))
+			gfar_data.device_flags =
+				FSL_GIANFAR_DEV_HAS_GIGABIT |
+				FSL_GIANFAR_DEV_HAS_COALESCE |
+				FSL_GIANFAR_DEV_HAS_RMON |
+				FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+		if (model && !strcasecmp(model, "eTSEC"))
+			gfar_data.device_flags =
+				FSL_GIANFAR_DEV_HAS_GIGABIT |
+				FSL_GIANFAR_DEV_HAS_COALESCE |
+				FSL_GIANFAR_DEV_HAS_RMON |
+				FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+				FSL_GIANFAR_DEV_HAS_CSUM |
+				FSL_GIANFAR_DEV_HAS_VLAN |
+				FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+
+		ph = (phandle *) get_property(np, "phy-handle", NULL);
+		phy = of_find_node_by_phandle(*ph);
+
+		if (phy == NULL) {
+			ret = -ENODEV;
+			goto gfar_unreg;
+		}
+
+		mdio = of_get_parent(phy);
+
+		id = (u32 *) get_property(phy, "reg", NULL);
+		ret = of_address_to_resource(mdio, 0, &res);
+		if (ret) {
+			of_node_put(phy);
+			of_node_put(mdio);
+			goto gfar_unreg;
+		}
+
+		gfar_data.phy_id = *id;
+		gfar_data.bus_id = res.start;
+
+		of_node_put(phy);
+		of_node_put(mdio);
+
+		ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data));
+		if (ret)
+			goto gfar_unreg;
+	}
+
+	return 0;
+
+mdio_unreg:
+	platform_device_unregister(mdio_dev);
+mdio_err:
+	return ret;
+
+gfar_unreg:
+	platform_device_unregister(gfar_dev);
+gfar_err:
+	return ret;
+}
+arch_initcall(gfar_of_init);
+
+static int __init fsl_i2c_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *i2c_dev;
+	int ret;
+
+	for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) {
+		struct resource r[2];
+		struct fsl_i2c_platform_data i2c_data;
+		unsigned char * flags = NULL;
+
+		memset(&r, 0, sizeof(r));
+		memset(&i2c_data, 0, sizeof(i2c_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto i2c_err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
+		if (IS_ERR(i2c_dev)) {
+			ret = PTR_ERR(i2c_dev);
+			goto i2c_err;
+		}
+
+		i2c_data.device_flags = 0;
+		flags = get_property(np, "dfsrr", NULL);
+		if (flags)
+			i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+
+		flags = get_property(np, "fsl5200-clocking", NULL);
+		if (flags)
+			i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
+
+		ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data));
+		if (ret)
+			goto i2c_unreg;
+	}
+
+	return 0;
+
+i2c_unreg:
+	platform_device_unregister(i2c_dev);
+i2c_err:
+	return ret;
+}
+arch_initcall(fsl_i2c_of_init);
+
+#ifdef CONFIG_PPC_83xx
+static int __init mpc83xx_wdt_init(void)
+{
+	struct resource r;
+	struct device_node *soc, *np;
+	struct platform_device *dev;
+	unsigned int *freq;
+	int ret;
+
+	np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
+
+	if (!np) {
+		ret = -ENODEV;
+		goto mpc83xx_wdt_nodev;
+	}
+
+	soc = of_find_node_by_type(NULL, "soc");
+
+	if (!soc) {
+		ret = -ENODEV;
+		goto mpc83xx_wdt_nosoc;
+	}
+
+	freq = (unsigned int *)get_property(soc, "bus-frequency", NULL);
+	if (!freq) {
+		ret = -ENODEV;
+		goto mpc83xx_wdt_err;
+	}
+
+	memset(&r, 0, sizeof(r));
+
+	ret = of_address_to_resource(np, 0, &r);
+	if (ret)
+		goto mpc83xx_wdt_err;
+
+	dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
+	if (IS_ERR(dev)) {
+		ret = PTR_ERR(dev);
+		goto mpc83xx_wdt_err;
+	}
+
+	ret = platform_device_add_data(dev, freq, sizeof(int));
+	if (ret)
+		goto mpc83xx_wdt_unreg;
+
+	of_node_put(soc);
+	of_node_put(np);
+
+	return 0;
+
+mpc83xx_wdt_unreg:
+	platform_device_unregister(dev);
+mpc83xx_wdt_err:
+	of_node_put(soc);
+mpc83xx_wdt_nosoc:
+	of_node_put(np);
+mpc83xx_wdt_nodev:
+	return ret;
+}
+arch_initcall(mpc83xx_wdt_init);
+#endif
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
new file mode 100644
index 0000000..c433d3f
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -0,0 +1,8 @@
+#ifndef __PPC_FSL_SOC_H
+#define __PPC_FSL_SOC_H
+#ifdef __KERNEL__
+
+extern phys_addr_t get_immrbase(void);
+
+#endif
+#endif
diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c
index ebc4db8..8ace2a1 100644
--- a/arch/ppc/4xx_io/serial_sicc.c
+++ b/arch/ppc/4xx_io/serial_sicc.c
@@ -215,7 +215,6 @@
  * memory if large numbers of serial ports are open.
  */
 static u_char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 #define HIGH_BITS_OFFSET    ((sizeof(long)-sizeof(int))*8)
 
diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
index de09787..3e6ca7f 100644
--- a/arch/ppc/kernel/head_8xx.S
+++ b/arch/ppc/kernel/head_8xx.S
@@ -375,6 +375,8 @@
 	lis	r11, swapper_pg_dir@h
 	ori	r11, r11, swapper_pg_dir@l
 	rlwimi	r10, r11, 0, 2, 19
+	stw	r12, 16(r0)
+	b LoadLargeDTLB
 3:
 	lwz	r11, 0(r10)	/* Get the level 1 entry */
 	rlwinm.	r10, r11,0,0,19	/* Extract page descriptor page address */
@@ -430,6 +432,81 @@
 InstructionTLBError:
 	b	InstructionAccess
 
+LoadLargeDTLB:
+	li	r12, 0
+	lwz	r11, 0(r10)	/* Get the level 1 entry */
+	rlwinm.	r10, r11,0,0,19	/* Extract page descriptor page address */
+	beq	3f		/* If zero, don't try to find a pte */
+
+	/* We have a pte table, so load fetch the pte from the table.
+	 */
+	ori	r11, r11, 1	/* Set valid bit in physical L2 page */
+	DO_8xx_CPU6(0x3b80, r3)
+	mtspr	SPRN_MD_TWC, r11	/* Load pte table base address */
+	mfspr	r10, SPRN_MD_TWC	/* ....and get the pte address */
+	lwz	r10, 0(r10)	/* Get the pte */
+
+	/* Insert the Guarded flag into the TWC from the Linux PTE.
+	 * It is bit 27 of both the Linux PTE and the TWC (at least
+	 * I got that right :-).  It will be better when we can put
+	 * this into the Linux pgd/pmd and load it in the operation
+	 * above.
+	 */
+	rlwimi	r11, r10, 0, 27, 27
+
+	rlwimi  r12, r10, 0, 0, 9	/* extract phys. addr */
+	mfspr	r3, SPRN_MD_EPN
+	rlwinm	r3, r3, 0, 0, 9		/* extract virtual address */
+	tophys(r3, r3)
+	cmpw	r3, r12			/* only use 8M page if it is a direct 
+					   kernel mapping */
+	bne	1f
+	ori     r11, r11, MD_PS8MEG
+	li	r12, 1
+	b	2f
+1:
+	li	r12, 0		/* can't use 8MB TLB, so zero r12. */
+2:
+	DO_8xx_CPU6(0x3b80, r3)
+	mtspr	SPRN_MD_TWC, r11
+
+	/* The Linux PTE won't go exactly into the MMU TLB.
+	 * Software indicator bits 21, 22 and 28 must be clear.
+	 * Software indicator bits 24, 25, 26, and 27 must be
+	 * set.  All other Linux PTE bits control the behavior
+	 * of the MMU.
+	 */
+3:	li	r11, 0x00f0
+	rlwimi	r10, r11, 0, 24, 28	/* Set 24-27, clear 28 */
+	cmpwi   r12, 1
+	bne 4f
+	ori     r10, r10, 0x8
+
+	mfspr	r12, SPRN_MD_EPN
+	lis	r3, 0xff80		/* 10-19 must be clear for 8MB TLB */
+	ori	r3, r3, 0x0fff
+	and	r12, r3, r12
+	DO_8xx_CPU6(0x3780, r3)
+	mtspr	SPRN_MD_EPN, r12
+
+	lis	r3, 0xff80		/* 10-19 must be clear for 8MB TLB */
+	ori	r3, r3, 0x0fff
+	and	r10, r3, r10
+4:
+	DO_8xx_CPU6(0x3d80, r3)
+	mtspr	SPRN_MD_RPN, r10	/* Update TLB entry */
+
+	mfspr	r10, SPRN_M_TW	/* Restore registers */
+	lwz	r11, 0(r0)
+	mtcr	r11
+	lwz	r11, 4(r0)
+
+	lwz	r12, 16(r0)
+#ifdef CONFIG_8xx_CPU6
+	lwz	r3, 8(r0)
+#endif
+	rfi
+
 /* This is the data TLB error on the MPC8xx.  This could be due to
  * many reasons, including a dirty update to a pte.  We can catch that
  * one here, but anything else is an error.  First, we track down the
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 95075f9..fb0da7c 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -270,7 +270,6 @@
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(irq_desc);
 EXPORT_SYMBOL(tb_ticks_per_jiffy);
-EXPORT_SYMBOL(get_wchan);
 EXPORT_SYMBOL(console_drivers);
 #ifdef CONFIG_XMON
 EXPORT_SYMBOL(xmon);
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 04bdc39b..012e1e6 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -51,9 +51,6 @@
 
 #include <syslib/ppc83xx_setup.h>
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-
 #ifndef CONFIG_PCI
 unsigned long isa_io_base = 0;
 unsigned long isa_mem_base = 0;
@@ -129,20 +126,21 @@
 	mdata->irq[1] = MPC83xx_IRQ_EXT2;
 	mdata->irq[2] = -1;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
index c5cde97..2eceb1e 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -52,10 +52,6 @@
 
 #include <syslib/ppc85xx_setup.h>
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-static const char *GFAR_PHY_3 = "phy0:3";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -102,27 +98,29 @@
 	mdata->irq[2] = -1;
 	mdata->irq[3] = MPC85xx_IRQ_EXT5;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
 	if (pdata) {
 		pdata->board_flags = 0;
-		pdata->bus_id = GFAR_PHY_3;
+		pdata->bus_id = 0;
+		pdata->phy_id = 3;
 		memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index 8e39a55..442c7ff 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -56,10 +56,6 @@
 #include <syslib/ppc85xx_setup.h>
 
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-static const char *GFAR_PHY_3 = "phy0:3";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -99,20 +95,21 @@
 	mdata->irq[2] = -1;
 	mdata->irq[3] = MPC85xx_IRQ_EXT5;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index 2959e3c..b332eba 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -395,9 +395,6 @@
 
 TODC_ALLOC();
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -461,34 +458,37 @@
 	mdata->irq[2] = -1;
 	mdata->irq[3] = -1;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 0;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index 45a5b81..e777ba8 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -91,9 +91,6 @@
 }
 #endif
 
-static const char *GFAR_PHY_25 = "phy0:25";
-static const char *GFAR_PHY_26 = "phy0:26";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -136,20 +133,21 @@
 	mdata->irq[25] = MPC85xx_IRQ_EXT6;
 	mdata->irq[26] = MPC85xx_IRQ_EXT7;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_25;
+		pdata->bus_id = 0;
+		pdata->phy_id = 25;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_26;
+		pdata->bus_id = 0;
+		pdata->phy_id = 26;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
index 15ce9d0..061bb7c 100644
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -93,9 +93,6 @@
 	0x0,				/* External 11: */
 };
 
-static const char *GFAR_PHY_2 = "phy0:2";
-static const char *GFAR_PHY_4 = "phy0:4";
-
 /*
  * Setup the architecture
  */
@@ -130,20 +127,21 @@
 	mdata->irq[2] = MPC85xx_IRQ_EXT5;
 	mdata->irq[4] = MPC85xx_IRQ_EXT5;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 	/*	pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-		pdata->bus_id = GFAR_PHY_2;
+		pdata->bus_id = 0;
+		pdata->phy_id = 2;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 	/*	pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-		pdata->bus_id = GFAR_PHY_4;
+		pdata->bus_id = 0;
+		pdata->phy_id = 4;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
index c6dfd8f..b436f4d 100644
--- a/arch/ppc/platforms/85xx/tqm85xx.c
+++ b/arch/ppc/platforms/85xx/tqm85xx.c
@@ -91,12 +91,6 @@
 	0x0,				/* External 11: */
 };
 
-static const char *GFAR_PHY_0 = "phy0:2";
-static const char *GFAR_PHY_1 = "phy0:1";
-#ifdef CONFIG_MPC8540
-static const char *GFAR_PHY_3 = "phy0:3";
-#endif
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -149,20 +143,21 @@
 	mdata->irq[2] = -1;
 	mdata->irq[3] = MPC85xx_IRQ_EXT8;
 	mdata->irq[31] = -1;
-	mdata->paddr += binfo->bi_immr_base;
 
 	/* setup the board related information for the enet controllers */
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_0;
+		pdata->bus_id = 0;
+		pdata->phy_id = 2;
 		memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
 	}
 
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
 	if (pdata) {
 		pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-		pdata->bus_id = GFAR_PHY_1;
+		pdata->bus_id = 0;
+		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
 	}
 
@@ -170,7 +165,8 @@
 	pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
 	if (pdata) {
 		pdata->board_flags = 0;
-		pdata->bus_id = GFAR_PHY_3;
+		pdata->bus_id = 0;
+		pdata->phy_id = 3;
 		memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
 	}
 #endif
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index 847df44..f9b95de 100644
--- a/arch/ppc/syslib/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -28,7 +28,6 @@
  */
 
 struct gianfar_mdio_data mpc83xx_mdio_pdata = {
-	.paddr = 0x24520,
 };
 
 static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
@@ -226,7 +225,14 @@
 		.name = "fsl-gianfar_mdio",
 		.id = 0,
 		.dev.platform_data = &mpc83xx_mdio_pdata,
-		.num_resources = 0,
+		.num_resources = 1,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x24520,
+				.end	= 0x2453f,
+				.flags	= IORESOURCE_MEM,
+			},
+		},
 	},
 };
 
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index 69949d2..00e9b6ff 100644
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -26,7 +26,6 @@
  * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
  */
 struct gianfar_mdio_data mpc85xx_mdio_pdata = {
-	.paddr = MPC85xx_MIIM_OFFSET,
 };
 
 static struct gianfar_platform_data mpc85xx_tsec1_pdata = {
@@ -720,7 +719,14 @@
 		.name = "fsl-gianfar_mdio",
 		.id = 0,
 		.dev.platform_data = &mpc85xx_mdio_pdata,
-		.num_resources = 0,
+		.num_resources = 1,
+		.resource = (struct resource[]) {
+			{
+				.start	= 0x24520,
+				.end	= 0x2453f,
+				.flags	= IORESOURCE_MEM,
+			},
+		},
 	},
 };
 
diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c
index 9ccce43..ab34b1d 100644
--- a/arch/ppc/syslib/ocp.c
+++ b/arch/ppc/syslib/ocp.c
@@ -189,6 +189,8 @@
 struct bus_type ocp_bus_type = {
 	.name = "ocp",
 	.match = ocp_device_match,
+	.probe = ocp_driver_probe,
+	.remove = ocp_driver_remove,
 	.suspend = ocp_device_suspend,
 	.resume = ocp_device_resume,
 };
@@ -210,8 +212,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &ocp_bus_type;
-	drv->driver.probe = ocp_device_probe;
-	drv->driver.remove = ocp_device_remove;
 
 	/* register with core */
 	return driver_register(&drv->driver);
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 7a1033d..c5ca2dc 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -114,80 +114,108 @@
 				    const u8 *in, unsigned int nbytes)
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(AES_BLOCK_SIZE - 1);
 
 	switch (sctx->key_len) {
 	case 16:
-		crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 24:
-		crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 32:
-		crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	}
-	return nbytes & ~(AES_BLOCK_SIZE - 1);
+	return nbytes;
 }
 
 static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(AES_BLOCK_SIZE - 1);
 
 	switch (sctx->key_len) {
 	case 16:
-		crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 24:
-		crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 32:
-		crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes);
+		ret = crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	}
-	return nbytes & ~(AES_BLOCK_SIZE - 1);
+	return nbytes;
 }
 
 static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(AES_BLOCK_SIZE - 1);
 
 	memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
 	switch (sctx->key_len) {
 	case 16:
-		crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 24:
-		crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 32:
-		crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	}
 	memcpy(desc->info, &sctx->iv, AES_BLOCK_SIZE);
 
-	return nbytes & ~(AES_BLOCK_SIZE - 1);
+	return nbytes;
 }
 
 static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
 				    const u8 *in, unsigned int nbytes)
 {
 	struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(AES_BLOCK_SIZE - 1);
 
 	memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
 	switch (sctx->key_len) {
 	case 16:
-		crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 24:
-		crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	case 32:
-		crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes);
+		ret = crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes);
+		BUG_ON((ret < 0) || (ret != nbytes));
 		break;
 	}
-	return nbytes & ~(AES_BLOCK_SIZE - 1);
+	return nbytes;
 }
 
 
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index a38bb2a..e3c37aa 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -15,10 +15,8 @@
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <asm/scatterlist.h>
 #include <linux/crypto.h>
+
 #include "crypt_s390.h"
 #include "crypto_des.h"
 
@@ -46,38 +44,92 @@
 	u8 key[DES3_192_KEY_SIZE];
 };
 
-static int
-des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des_setkey(void *ctx, const u8 *key, unsigned int keylen,
+		      u32 *flags)
 {
-	struct crypt_s390_des_ctx *dctx;
+	struct crypt_s390_des_ctx *dctx = ctx;
 	int ret;
 
-	dctx = ctx;
-	//test if key is valid (not a weak key)
+	/* test if key is valid (not a weak key) */
 	ret = crypto_des_check_key(key, keylen, flags);
-	if (ret == 0){
+	if (ret == 0)
 		memcpy(dctx->key, key, keylen);
-	}
 	return ret;
 }
 
-
-static void
-des_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des_encrypt(void *ctx, u8 *out, const u8 *in)
 {
-	struct crypt_s390_des_ctx *dctx;
+	struct crypt_s390_des_ctx *dctx = ctx;
 
-	dctx = ctx;
-	crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
+	crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
 }
 
-static void
-des_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des_decrypt(void *ctx, u8 *out, const u8 *in)
 {
-	struct crypt_s390_des_ctx *dctx;
+	struct crypt_s390_des_ctx *dctx = ctx;
 
-	dctx = ctx;
-	crypt_s390_km(KM_DEA_DECRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
+	crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+}
+
+static unsigned int des_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_DEA_ENCRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_DEA_DECRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES_BLOCK_SIZE - 1);
+
+	memcpy(sctx->iv, desc->info, DES_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_DEA_ENCRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	memcpy(desc->info, sctx->iv, DES_BLOCK_SIZE);
+	return nbytes;
+}
+
+static unsigned int des_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+				    const u8 *in, unsigned int nbytes)
+{
+	struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES_BLOCK_SIZE - 1);
+
+	memcpy(&sctx->iv, desc->info, DES_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_DEA_DECRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
 }
 
 static struct crypto_alg des_alg = {
@@ -87,12 +139,19 @@
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(des_alg.cra_list),
-	.cra_u			=	{ .cipher = {
-	.cia_min_keysize	=	DES_KEY_SIZE,
-	.cia_max_keysize	=	DES_KEY_SIZE,
-	.cia_setkey		= 	des_setkey,
-	.cia_encrypt		=	des_encrypt,
-	.cia_decrypt		=	des_decrypt } }
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	DES_KEY_SIZE,
+			.cia_max_keysize	=	DES_KEY_SIZE,
+			.cia_setkey		=	des_setkey,
+			.cia_encrypt		=	des_encrypt,
+			.cia_decrypt		=	des_decrypt,
+			.cia_encrypt_ecb	=	des_encrypt_ecb,
+			.cia_decrypt_ecb	=	des_decrypt_ecb,
+			.cia_encrypt_cbc	=	des_encrypt_cbc,
+			.cia_decrypt_cbc	=	des_decrypt_cbc,
+		}
+	}
 };
 
 /*
@@ -107,20 +166,18 @@
  *   Implementers MUST reject keys that exhibit this property.
  *
  */
-static int
-des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen,
+			   u32 *flags)
 {
 	int i, ret;
-	struct crypt_s390_des3_128_ctx *dctx;
+	struct crypt_s390_des3_128_ctx *dctx = ctx;
 	const u8* temp_key = key;
 
-	dctx = ctx;
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
-
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
 		return -EINVAL;
 	}
-	for (i = 0; i < 2; i++,	temp_key += DES_KEY_SIZE) {
+	for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
 		ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
 		if (ret < 0)
 			return ret;
@@ -129,24 +186,85 @@
 	return 0;
 }
 
-static void
-des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_128_ctx *dctx;
+	struct crypt_s390_des3_128_ctx *dctx = ctx;
 
-	dctx = ctx;
 	crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
-			DES3_128_BLOCK_SIZE);
+		      DES3_128_BLOCK_SIZE);
 }
 
-static void
-des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_128_ctx *dctx;
+	struct crypt_s390_des3_128_ctx *dctx = ctx;
 
-	dctx = ctx;
 	crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
-			DES3_128_BLOCK_SIZE);
+		      DES3_128_BLOCK_SIZE);
+}
+
+static unsigned int des3_128_encrypt_ecb(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_TDEA_128_ENCRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des3_128_decrypt_ecb(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_TDEA_128_DECRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des3_128_encrypt_cbc(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+
+	memcpy(sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_TDEA_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	memcpy(desc->info, sctx->iv, DES3_128_BLOCK_SIZE);
+	return nbytes;
+}
+
+static unsigned int des3_128_decrypt_cbc(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+
+	memcpy(&sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_TDEA_128_DECRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
 }
 
 static struct crypto_alg des3_128_alg = {
@@ -156,12 +274,19 @@
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_128_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(des3_128_alg.cra_list),
-	.cra_u			=	{ .cipher = {
-	.cia_min_keysize	=	DES3_128_KEY_SIZE,
-	.cia_max_keysize	=	DES3_128_KEY_SIZE,
-	.cia_setkey		= 	des3_128_setkey,
-	.cia_encrypt		=	des3_128_encrypt,
-	.cia_decrypt		=	des3_128_decrypt } }
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	DES3_128_KEY_SIZE,
+			.cia_max_keysize	=	DES3_128_KEY_SIZE,
+			.cia_setkey		=	des3_128_setkey,
+			.cia_encrypt		=	des3_128_encrypt,
+			.cia_decrypt		=	des3_128_decrypt,
+			.cia_encrypt_ecb	=	des3_128_encrypt_ecb,
+			.cia_decrypt_ecb	=	des3_128_decrypt_ecb,
+			.cia_encrypt_cbc	=	des3_128_encrypt_cbc,
+			.cia_decrypt_cbc	=	des3_128_decrypt_cbc,
+		}
+	}
 };
 
 /*
@@ -177,50 +302,108 @@
  *   property.
  *
  */
-static int
-des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen,
+			   u32 *flags)
 {
 	int i, ret;
-	struct crypt_s390_des3_192_ctx *dctx;
-	const u8* temp_key;
+	struct crypt_s390_des3_192_ctx *dctx = ctx;
+	const u8* temp_key = key;
 
-	dctx = ctx;
-	temp_key = key;
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
 	    memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
-	    					DES_KEY_SIZE))) {
+		   DES_KEY_SIZE))) {
 
 		*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
 		return -EINVAL;
 	}
 	for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
 		ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
-		if (ret < 0){
+		if (ret < 0)
 			return ret;
-		}
 	}
 	memcpy(dctx->key, key, keylen);
 	return 0;
 }
 
-static void
-des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_192_ctx *dctx;
+	struct crypt_s390_des3_192_ctx *dctx = ctx;
 
-	dctx = ctx;
 	crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
-			DES3_192_BLOCK_SIZE);
+		      DES3_192_BLOCK_SIZE);
 }
 
-static void
-des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-	struct crypt_s390_des3_192_ctx *dctx;
+	struct crypt_s390_des3_192_ctx *dctx = ctx;
 
-	dctx = ctx;
 	crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
-			DES3_192_BLOCK_SIZE);
+		      DES3_192_BLOCK_SIZE);
+}
+
+static unsigned int des3_192_encrypt_ecb(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_TDEA_192_ENCRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des3_192_decrypt_ecb(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+	ret = crypt_s390_km(KM_TDEA_192_DECRYPT, sctx->key, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
+}
+
+static unsigned int des3_192_encrypt_cbc(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+
+	memcpy(sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_TDEA_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	memcpy(desc->info, sctx->iv, DES3_192_BLOCK_SIZE);
+	return nbytes;
+}
+
+static unsigned int des3_192_decrypt_cbc(const struct cipher_desc *desc,
+					 u8 *out, const u8 *in,
+					 unsigned int nbytes)
+{
+	struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+	int ret;
+
+	/* only use complete blocks */
+	nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+
+	memcpy(&sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+	ret = crypt_s390_kmc(KMC_TDEA_192_DECRYPT, &sctx->iv, out, in, nbytes);
+	BUG_ON((ret < 0) || (ret != nbytes));
+
+	return nbytes;
 }
 
 static struct crypto_alg des3_192_alg = {
@@ -230,44 +413,43 @@
 	.cra_ctxsize		=	sizeof(struct crypt_s390_des3_192_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(des3_192_alg.cra_list),
-	.cra_u			=	{ .cipher = {
-	.cia_min_keysize	=	DES3_192_KEY_SIZE,
-	.cia_max_keysize	=	DES3_192_KEY_SIZE,
-	.cia_setkey		= 	des3_192_setkey,
-	.cia_encrypt		=	des3_192_encrypt,
-	.cia_decrypt		=	des3_192_decrypt } }
+	.cra_u			=	{
+		.cipher = {
+			.cia_min_keysize	=	DES3_192_KEY_SIZE,
+			.cia_max_keysize	=	DES3_192_KEY_SIZE,
+			.cia_setkey		=	des3_192_setkey,
+			.cia_encrypt		=	des3_192_encrypt,
+			.cia_decrypt		=	des3_192_decrypt,
+			.cia_encrypt_ecb	=	des3_192_encrypt_ecb,
+			.cia_decrypt_ecb	=	des3_192_decrypt_ecb,
+			.cia_encrypt_cbc	=	des3_192_encrypt_cbc,
+			.cia_decrypt_cbc	=	des3_192_decrypt_cbc,
+		}
+	}
 };
 
-
-
-static int
-init(void)
+static int init(void)
 {
-	int ret;
+	int ret = 0;
 
 	if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
 	    !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
-	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)){
+	    !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
 		return -ENOSYS;
-	}
 
-	ret = 0;
-	ret |= (crypto_register_alg(&des_alg) == 0)? 0:1;
-	ret |= (crypto_register_alg(&des3_128_alg) == 0)? 0:2;
-	ret |= (crypto_register_alg(&des3_192_alg) == 0)? 0:4;
-	if (ret){
+	ret |= (crypto_register_alg(&des_alg) == 0) ? 0:1;
+	ret |= (crypto_register_alg(&des3_128_alg) == 0) ? 0:2;
+	ret |= (crypto_register_alg(&des3_192_alg) == 0) ? 0:4;
+	if (ret) {
 		crypto_unregister_alg(&des3_192_alg);
 		crypto_unregister_alg(&des3_128_alg);
 		crypto_unregister_alg(&des_alg);
 		return -EEXIST;
 	}
-
-	printk(KERN_INFO "crypt_s390: des_s390 loaded.\n");
 	return 0;
 }
 
-static void __exit
-fini(void)
+static void __exit fini(void)
 {
 	crypto_unregister_alg(&des3_192_alg);
 	crypto_unregister_alg(&des3_128_alg);
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index b75bdbd..1ec5e92 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -51,6 +51,7 @@
 {
 	struct s390_sha256_ctx *sctx = ctx;
 	unsigned int index;
+	int ret;
 
 	/* how much is already in the buffer? */
 	index = sctx->count / 8 & 0x3f;
@@ -58,15 +59,29 @@
 	/* update message bit length */
 	sctx->count += len * 8;
 
-	/* process one block */
-	if ((index + len) >= SHA256_BLOCK_SIZE) {
+	if ((index + len) < SHA256_BLOCK_SIZE)
+		goto store;
+
+	/* process one stored block */
+	if (index) {
 		memcpy(sctx->buf + index, data, SHA256_BLOCK_SIZE - index);
-		crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
-				SHA256_BLOCK_SIZE);
+		ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
+				      SHA256_BLOCK_SIZE);
+		BUG_ON(ret != SHA256_BLOCK_SIZE);
 		data += SHA256_BLOCK_SIZE - index;
 		len -= SHA256_BLOCK_SIZE - index;
 	}
 
+	/* process as many blocks as possible */
+	if (len >= SHA256_BLOCK_SIZE) {
+		ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, data,
+				      len & ~(SHA256_BLOCK_SIZE - 1));
+		BUG_ON(ret != (len & ~(SHA256_BLOCK_SIZE - 1)));
+		data += ret;
+		len -= ret;
+	}
+
+store:
 	/* anything left? */
 	if (len)
 		memcpy(sctx->buf + index , data, len);
@@ -119,9 +134,9 @@
 	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
 	.dia_digestsize	=	SHA256_DIGEST_SIZE,
-	.dia_init   	= 	sha256_init,
-	.dia_update 	=	sha256_update,
-	.dia_final  	=	sha256_final } }
+	.dia_init	=	sha256_init,
+	.dia_update	=	sha256_update,
+	.dia_final	=	sha256_final } }
 };
 
 static int init(void)
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 2ff90a1..008c745 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -58,10 +58,18 @@
  */
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-	struct stack_frame *sf;
+	struct stack_frame *sf, *low, *high;
 
-	sf = (struct stack_frame *) tsk->thread.ksp;
-	sf = (struct stack_frame *) sf->back_chain;
+	if (!tsk || !task_stack_page(tsk))
+		return 0;
+	low = task_stack_page(tsk);
+	high = (struct stack_frame *) task_pt_regs(tsk);
+	sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN);
+	if (sf <= low || sf > high)
+		return 0;
+	sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+	if (sf <= low || sf > high)
+		return 0;
 	return sf->gprs[8];
 }
 
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index b03847d..de87842 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -268,7 +268,7 @@
 	reipl_diag();
 
 	if (MACHINE_IS_VM)
-		cpcmd ("IPL", NULL, 0);
+		cpcmd ("IPL", NULL, 0, NULL);
 	else
 		reipl (0x10000 | S390_lowcore.ipl_device);
 }
@@ -276,14 +276,14 @@
 static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
+                cpcmd(vmhalt_cmd, NULL, 0, NULL);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
 static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
+                cpcmd(vmpoff_cmd, NULL, 0, NULL);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
@@ -315,6 +315,11 @@
 	_machine_power_off();
 }
 
+/*
+ * Dummy power off function.
+ */
+void (*pm_power_off)(void) = machine_power_off;
+
 static void __init
 add_memory_hole(unsigned long start, unsigned long end)
 {
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index b0d8ca8..7c0fe15 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -214,7 +214,7 @@
 #endif
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-	account_user_vtime(current);
+	account_tick_vtime(current);
 #else
 	while (ticks--)
 		update_process_times(user_mode(regs));
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 22a895e..dfe6f08 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -32,7 +32,7 @@
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
-void account_user_vtime(struct task_struct *tsk)
+void account_tick_vtime(struct task_struct *tsk)
 {
 	cputime_t cputime;
 	__u64 timer, clock;
@@ -76,6 +76,31 @@
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
+void account_vtime(struct task_struct *tsk)
+{
+	cputime_t cputime;
+	__u64 timer;
+
+	timer = S390_lowcore.last_update_timer;
+	asm volatile ("  STPT %0"    /* Store current cpu timer value */
+		      : "=m" (S390_lowcore.last_update_timer) );
+	S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
+
+	cputime = S390_lowcore.user_timer >> 12;
+	S390_lowcore.user_timer -= cputime << 12;
+	S390_lowcore.steal_clock -= cputime << 12;
+	account_user_time(tsk, cputime);
+
+	cputime =  S390_lowcore.system_timer >> 12;
+	S390_lowcore.system_timer -= cputime << 12;
+	S390_lowcore.steal_clock -= cputime << 12;
+	account_system_time(tsk, 0, cputime);
+}
+
+/*
+ * Update process times based on virtual cpu times stored by entry.S
+ * to the lowcore fields user_timer, system_timer & steal_clock.
+ */
 void account_system_vtime(struct task_struct *tsk)
 {
 	cputime_t cputime;
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index d9b97b3..f20b51ff 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -4,5 +4,6 @@
 
 EXTRA_AFLAGS := -traditional
 
-lib-y += delay.o string.o spinlock.o
+lib-y += delay.o string.o
 lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o)
+lib-$(CONFIG_SMP) += spinlock.o
\ No newline at end of file
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 68d79c5..60f80a4 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 
-atomic_t spin_retry_counter;
 int spin_retry = 1000;
 
 /**
@@ -45,7 +44,6 @@
 			_diag44();
 			count = spin_retry;
 		}
-		atomic_inc(&spin_retry_counter);
 		if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
 			return;
 	}
@@ -58,7 +56,6 @@
 	int count = spin_retry;
 
 	while (count-- > 0) {
-		atomic_inc(&spin_retry_counter);
 		if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
 			return 1;
 	}
@@ -77,7 +74,6 @@
 			_diag44();
 			count = spin_retry;
 		}
-		atomic_inc(&spin_retry_counter);
 		old = rw->lock & 0x7fffffffU;
 		if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
 			return;
@@ -92,7 +88,6 @@
 	int count = spin_retry;
 
 	while (count-- > 0) {
-		atomic_inc(&spin_retry_counter);
 		old = rw->lock & 0x7fffffffU;
 		if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
 			return 1;
@@ -111,7 +106,6 @@
 			_diag44();
 			count = spin_retry;
 		}
-		atomic_inc(&spin_retry_counter);
 		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
 			return;
 	}
@@ -124,7 +118,6 @@
 	int count = spin_retry;
 
 	while (count-- > 0) {
-		atomic_inc(&spin_retry_counter);
 		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
 			return 1;
 	}
diff --git a/arch/sh/kernel/cpu/bus.c b/arch/sh/kernel/cpu/bus.c
index d4fee2a7..3278d23 100644
--- a/arch/sh/kernel/cpu/bus.c
+++ b/arch/sh/kernel/cpu/bus.c
@@ -53,21 +53,6 @@
 	return 0;
 }
 
-static struct device sh_bus_devices[SH_NR_BUSES] = {
-	{
-		.bus_id		= SH_BUS_NAME_VIRT,
-	},
-};
-
-struct bus_type sh_bus_types[SH_NR_BUSES] = {
-	{
-		.name		= SH_BUS_NAME_VIRT,
-		.match		= sh_bus_match,
-		.suspend	= sh_bus_suspend,
-		.resume		= sh_bus_resume,
-	},
-};
-
 static int sh_device_probe(struct device *dev)
 {
 	struct sh_dev *shdev = to_sh_dev(dev);
@@ -90,6 +75,23 @@
 	return 0;
 }
 
+static struct device sh_bus_devices[SH_NR_BUSES] = {
+	{
+		.bus_id		= SH_BUS_NAME_VIRT,
+	},
+};
+
+struct bus_type sh_bus_types[SH_NR_BUSES] = {
+	{
+		.name		= SH_BUS_NAME_VIRT,
+		.match		= sh_bus_match,
+		.probe		= sh_bus_probe,
+		.remove		= sh_bus_remove,
+		.suspend	= sh_bus_suspend,
+		.resume		= sh_bus_resume,
+	},
+};
+
 int sh_device_register(struct sh_dev *dev)
 {
 	if (!dev)
@@ -133,8 +135,6 @@
 		return -EINVAL;
 	}
 
-	drv->drv.probe  = sh_device_probe;
-	drv->drv.remove = sh_device_remove;
 	drv->drv.bus    = &sh_bus_types[drv->bus_id];
 
 	return driver_register(&drv->drv);
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 322972f..45435ff 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -67,7 +67,8 @@
 # in CFLAGS.  Otherwise, it would cause ld to complain about the two different
 # errnos.
 
-CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask
+CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
+	-Dmktime=kernel_mktime
 CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
 
 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
diff --git a/block/genhd.c b/block/genhd.c
index f1ed83f..db57546 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -38,34 +38,100 @@
 	return major % MAX_PROBE_HASH;
 }
 
-#ifdef CONFIG_PROC_FS
-/* get block device names in somewhat random order */
-int get_blkdev_list(char *p, int used)
+struct blkdev_info {
+        int index;
+        struct blk_major_name *bd;
+};
+
+/*
+ * iterate over a list of blkdev_info structures.  allows
+ * the major_names array to be iterated over from outside this file
+ * must be called with the block_subsys_sem held
+ */
+void *get_next_blkdev(void *dev)
+{
+        struct blkdev_info *info;
+
+        if (dev == NULL) {
+                info = kmalloc(sizeof(*info), GFP_KERNEL);
+                if (!info)
+                        goto out;
+                info->index=0;
+                info->bd = major_names[info->index];
+                if (info->bd)
+                        goto out;
+        } else {
+                info = dev;
+        }
+
+        while (info->index < ARRAY_SIZE(major_names)) {
+                if (info->bd)
+                        info->bd = info->bd->next;
+                if (info->bd)
+                        goto out;
+                /*
+                 * No devices on this chain, move to the next
+                 */
+                info->index++;
+                info->bd = (info->index < ARRAY_SIZE(major_names)) ?
+			major_names[info->index] : NULL;
+                if (info->bd)
+                        goto out;
+        }
+
+out:
+        return info;
+}
+
+void *acquire_blkdev_list(void)
+{
+        down(&block_subsys_sem);
+        return get_next_blkdev(NULL);
+}
+
+void release_blkdev_list(void *dev)
+{
+        up(&block_subsys_sem);
+        kfree(dev);
+}
+
+
+/*
+ * Count the number of records in the blkdev_list.
+ * must be called with the block_subsys_sem held
+ */
+int count_blkdev_list(void)
 {
 	struct blk_major_name *n;
-	int i, len;
+	int i, count;
 
-	len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
+	count = 0;
 
-	down(&block_subsys_sem);
 	for (i = 0; i < ARRAY_SIZE(major_names); i++) {
-		for (n = major_names[i]; n; n = n->next) {
-			/*
-			 * If the curent string plus the 5 extra characters
-			 * in the line would run us off the page, then we're done
-			 */
-			if ((len + used + strlen(n->name) + 5) >= PAGE_SIZE)
-				goto page_full;
-			len += sprintf(p+len, "%3d %s\n",
-				       n->major, n->name);
-		}
+		for (n = major_names[i]; n; n = n->next)
+				count++;
 	}
-page_full:
-	up(&block_subsys_sem);
 
-	return len;
+	return count;
 }
-#endif
+
+/*
+ * extract the major and name values from a blkdev_info struct
+ * passed in as a void to *dev.  Must be called with
+ * block_subsys_sem held
+ */
+int get_blkdev_info(void *dev, int *major, char **name)
+{
+        struct blkdev_info *info = dev;
+
+        if (info->bd == NULL)
+                return 1;
+
+        *major = info->bd->major;
+        *name = info->bd->name;
+        return 0;
+}
+
 
 int register_blkdev(unsigned int major, const char *name)
 {
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 48f446d..283c089 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -44,6 +44,8 @@
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/hwmon/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 7fc3f0f..7c45050 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -41,6 +41,7 @@
 obj-$(CONFIG_IEEE1394)		+= ieee1394/
 obj-y				+= cdrom/
 obj-$(CONFIG_MTD)		+= mtd/
+obj-$(CONFIG_SPI)		+= spi/
 obj-$(CONFIG_PCCARD)		+= pcmcia/
 obj-$(CONFIG_DIO)		+= dio/
 obj-$(CONFIG_SBUS)		+= sbus/
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7e1a445..3758b55 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -153,7 +153,7 @@
                              Transaction Management
    -------------------------------------------------------------------------- */
 
-static inline u32 acpi_ec_read_status(union acpi_ec *ec)
+static u32 acpi_ec_read_status(union acpi_ec *ec)
 {
 	u32 status = 0;
 
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 2b90501..730a9ce 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -78,7 +78,13 @@
 	pr_debug("%s: Matched Device %s with Driver %s\n",
 		 drv->bus->name, dev->bus_id, drv->name);
 	dev->driver = drv;
-	if (drv->probe) {
+	if (dev->bus->probe) {
+		ret = dev->bus->probe(dev);
+		if (ret) {
+			dev->driver = NULL;
+			goto ProbeFailed;
+		}
+	} else if (drv->probe) {
 		ret = drv->probe(dev);
 		if (ret) {
 			dev->driver = NULL;
@@ -203,7 +209,9 @@
 		sysfs_remove_link(&dev->kobj, "driver");
 		klist_remove(&dev->knode_driver);
 
-		if (drv->remove)
+		if (dev->bus->remove)
+			dev->bus->remove(dev);
+		else if (drv->remove)
 			drv->remove(dev);
 		dev->driver = NULL;
 		put_driver(drv);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 161f3a3..b400314 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -171,6 +171,11 @@
  */
 int driver_register(struct device_driver * drv)
 {
+	if ((drv->bus->probe && drv->probe) ||
+	    (drv->bus->remove && drv->remove) ||
+	    (drv->bus->shutdown && drv->shutdown)) {
+		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
+	}
 	klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
 	init_completion(&drv->unloaded);
 	return bus_add_driver(drv);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 3d384e3..e97e911 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -48,7 +48,7 @@
 	struct timer_list timeout;
 };
 
-static inline void
+static void
 fw_load_abort(struct firmware_priv *fw_priv)
 {
 	set_bit(FW_STATUS_ABORT, &fw_priv->status);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 0f81731..461554a 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -327,7 +327,7 @@
  *	@pdev:	platform device we're unregistering
  *
  *	Unregistration is done in 2 steps. Fisrt we release all resources
- *	and remove it from the sybsystem, then we drop reference count by
+ *	and remove it from the subsystem, then we drop reference count by
  *	calling platform_device_put().
  */
 void platform_device_unregister(struct platform_device * pdev)
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index f50a08b..c2475f3 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -35,12 +35,15 @@
  */
 void device_shutdown(void)
 {
-	struct device * dev;
+	struct device * dev, *devn;
 
 	down_write(&devices_subsys.rwsem);
-	list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
+	list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
 				kobj.entry) {
-		if (dev->driver && dev->driver->shutdown) {
+		if (dev->bus && dev->bus->shutdown) {
+			dev_dbg(dev, "shutdown\n");
+			dev->bus->shutdown(dev);
+		} else if (dev->driver && dev->driver->shutdown) {
 			dev_dbg(dev, "shutdown\n");
 			dev->driver->shutdown(dev);
 		}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 8647290..5f6d1a5 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -294,7 +294,7 @@
  * This helper just factors out common code between do_lo_send_direct_write()
  * and do_lo_send_write().
  */
-static inline int __do_lo_send_write(struct file *file,
+static int __do_lo_send_write(struct file *file,
 		u8 __user *buf, const int len, loff_t pos)
 {
 	ssize_t bw;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 51b7a5c..93affee 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -247,7 +247,7 @@
 	return rb_entry(n, struct pkt_rb_node, rb_node);
 }
 
-static inline void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
+static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
 {
 	rb_erase(&node->rb_node, &pd->bio_queue);
 	mempool_free(node, pd->rb_pool);
@@ -315,7 +315,7 @@
 /*
  * Add a bio to a single linked list defined by its head and tail pointers.
  */
-static inline void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
+static void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
 {
 	bio->bi_next = NULL;
 	if (*list_tail) {
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 8fddfdf..7bd4ef9 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -494,7 +494,7 @@
 	}
 }
 
-static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
+static void bcsp_complete_rx_pkt(struct hci_uart *hu)
 {
 	struct bcsp_struct *bcsp = hu->priv;
 	int pass_up;
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 667a21c..7ac365b 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -129,7 +129,6 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 #include <asm/uaccess.h>
 
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index caeecc2..a080cdd 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -220,7 +220,7 @@
 	ADVANCE_RING();
 }
 
-static __inline__ void r128_emit_state(drm_r128_private_t * dev_priv)
+static void r128_emit_state(drm_r128_private_t * dev_priv)
 {
 	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	unsigned int dirty = sarea_priv->dirty;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index e469f64..dd5dc8f 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -160,7 +160,6 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct esp_struct *info,
 					char *name, const char *routine)
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 204a730..e38a5f0 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -34,7 +34,6 @@
 #define DEBUG 
 
 static char *                  tmp_buf; 
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static int gs_debug;
 
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 050e70e..119e629 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -82,7 +82,6 @@
 static struct riscom_board * IRQ_to_board[16];
 static struct tty_driver *riscom_driver;
 static unsigned char * tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static unsigned long baud_table[] =  {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index f36342a..037c940 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -129,7 +129,6 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf = 0;
-DECLARE_MUTEX(tmp_buf_sem);
 
 /*
  * This is used to look up the divisor speeds and the timeouts
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 0a574bd..5343e9f 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -184,7 +184,6 @@
 
 static struct tty_driver *specialix_driver;
 static unsigned char * tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static unsigned long baud_table[] =  {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
@@ -2556,8 +2555,6 @@
 
 	func_enter();
 
-	init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
-
 	if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
 		for(i = 0; i < SX_NBOARD; i++) {
 			sx_board[i].base = iobase[i];
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 9f1b466..ede688a 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -951,7 +951,6 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int mgsl_paranoia_check(struct mgsl_struct *info,
 					char *name, const char *routine)
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index a654479..c0dfcf2 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -395,12 +395,38 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called machzwd.
 
+config SBC_EPX_C3_WATCHDOG
+	tristate "Winsystems SBC EPX-C3 watchdog"
+	depends on WATCHDOG && X86
+	---help---
+	  This is the driver for the built-in watchdog timer on the EPX-C3
+	  Single-board computer made by Winsystems, Inc.
+
+	  *Note*: This hardware watchdog is not probeable and thus there
+	  is no way to know if writing to its IO address will corrupt
+	  your system or have any real effect.  The only way to be sure
+	  that this driver does what you want is to make sure you
+	  are runnning it on an EPX-C3 from Winsystems with the watchdog
+	  timer at IO address 0x1ee and 0x1ef.  It will write to both those
+	  IO ports.  Basically, the assumption is made that if you compile
+	  this driver into your kernel and/or load it as a module, that you
+	  know what you are doing and that you are in fact running on an
+	  EPX-C3 board!
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sbc_epx_c3.
+
+
 # PowerPC Architecture
 
 config 8xx_WDT
 	tristate "MPC8xx Watchdog Timer"
 	depends on WATCHDOG && 8xx
 
+config 83xx_WDT
+	tristate "MPC83xx Watchdog Timer"
+	depends on WATCHDOG && PPC_83xx
+
 config MV64X60_WDT
 	tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
 	depends on WATCHDOG && MV64X60
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index cfd0a39..36c0b28 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -52,9 +52,11 @@
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 
 # PowerPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
 obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
 obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
new file mode 100644
index 0000000..5d6f506
--- /dev/null
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -0,0 +1,229 @@
+/*
+ * mpc83xx_wdt.c - MPC83xx watchdog userspace interface
+ *
+ * Authors: Dave Updegraff <dave@cray.org>
+ * 	    Kumar Gala <galak@kernel.crashing.org>
+ * 		Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
+ * 				..and from sc520_wdt
+ *
+ * Note: it appears that you can only actually ENABLE or DISABLE the thing
+ * once after POR. Once enabled, you cannot disable, and vice versa.
+ *
+ * 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/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+struct mpc83xx_wdt {
+	__be32 res0;
+	__be32 swcrr; /* System watchdog control register */
+#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
+#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
+#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
+#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
+	__be32 swcnr; /* System watchdog count register */
+	u8 res1[2];
+	__be16 swsrr; /* System watchdog service register */
+	u8 res2[0xF0];
+};
+
+static struct mpc83xx_wdt __iomem *wd_base;
+
+static u16 timeout = 0xffff;
+module_param(timeout, ushort, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535");
+
+static int reset = 1;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
+
+/*
+ * We always prescale, but if someone really doesn't want to they can set this
+ * to 0
+ */
+static int prescale = 1;
+static unsigned int timeout_sec;
+
+static unsigned long wdt_is_open;
+static spinlock_t wdt_spinlock;
+
+static void mpc83xx_wdt_keepalive(void)
+{
+	/* Ping the WDT */
+	spin_lock(&wdt_spinlock);
+	out_be16(&wd_base->swsrr, 0x556c);
+	out_be16(&wd_base->swsrr, 0xaa39);
+	spin_unlock(&wdt_spinlock);
+}
+
+static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	if (count)
+		mpc83xx_wdt_keepalive();
+	return count;
+}
+
+static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
+{
+	u32 tmp = SWCRR_SWEN;
+	if (test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+
+	/* Once we start the watchdog we can't stop it */
+	__module_get(THIS_MODULE);
+
+	/* Good, fire up the show */
+	if (prescale)
+		tmp |= SWCRR_SWPR;
+	if (reset)
+		tmp |= SWCRR_SWRI;
+
+	tmp |= timeout << 16;
+
+	out_be32(&wd_base->swcrr, tmp);
+
+	return nonseekable_open(inode, file);
+}
+
+static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
+{
+	printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n");
+	mpc83xx_wdt_keepalive();
+	clear_bit(0, &wdt_is_open);
+	return 0;
+}
+
+static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING,
+		.firmware_version = 1,
+		.identity = "MPC83xx",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+	case WDIOC_KEEPALIVE:
+		mpc83xx_wdt_keepalive();
+		return 0;
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout_sec, p);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct file_operations mpc83xx_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= mpc83xx_wdt_write,
+	.ioctl		= mpc83xx_wdt_ioctl,
+	.open		= mpc83xx_wdt_open,
+	.release	= mpc83xx_wdt_release,
+};
+
+static struct miscdevice mpc83xx_wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &mpc83xx_wdt_fops,
+};
+
+static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
+{
+	struct resource *r;
+	int ret;
+	unsigned int *freq = dev->dev.platform_data;
+
+	/* get a pointer to the register memory */
+	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+	if (!r) {
+		ret = -ENODEV;
+		goto err_out;
+	}
+
+	wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt));
+
+	if (wd_base == NULL) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	ret = misc_register(&mpc83xx_wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "cannot register miscdev on minor=%d "
+				"(err=%d)\n",
+				WATCHDOG_MINOR, ret);
+		goto err_unmap;
+	}
+
+	/* Calculate the timeout in seconds */
+	if (prescale)
+		timeout_sec = (timeout * 0x10000) / (*freq);
+	else
+		timeout_sec = timeout / (*freq);
+
+	printk(KERN_INFO "WDT driver for MPC83xx initialized. "
+		"mode:%s timeout=%d (%d seconds)\n",
+		reset ? "reset":"interrupt", timeout, timeout_sec);
+
+	spin_lock_init(&wdt_spinlock);
+
+	return 0;
+
+err_unmap:
+	iounmap(wd_base);
+err_out:
+	return ret;
+}
+
+static int __devexit mpc83xx_wdt_remove(struct platform_device *dev)
+{
+	misc_deregister(&mpc83xx_wdt_miscdev);
+	iounmap(wd_base);
+
+	return 0;
+}
+
+static struct platform_driver mpc83xx_wdt_driver = {
+	.probe		= mpc83xx_wdt_probe,
+	.remove		= __devexit_p(mpc83xx_wdt_remove),
+	.driver		= {
+		.name	= "mpc83xx_wdt",
+	},
+};
+
+static int __init mpc83xx_wdt_init(void)
+{
+	return platform_driver_register(&mpc83xx_wdt_driver);
+}
+
+static void __exit mpc83xx_wdt_exit(void)
+{
+	platform_driver_unregister(&mpc83xx_wdt_driver);
+}
+
+module_init(mpc83xx_wdt_init);
+module_exit(mpc83xx_wdt_exit);
+
+MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
+MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx uProcessor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
new file mode 100644
index 0000000..9517646
--- /dev/null
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -0,0 +1,216 @@
+/*
+ *	SBC EPX C3 0.1	A Hardware Watchdog Device for the Winsystems EPX-C3
+ *	single board computer
+ *
+ *	(c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, All Rights
+ *	Reserved.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define PFX "epx_c3: "
+static int epx_c3_alive;
+
+#define WATCHDOG_TIMEOUT 1		/* 1 sec default timeout */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
+#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
+
+static void epx_c3_start(void)
+{
+	outb(1, EPXC3_WATCHDOG_CTL_REG);
+}
+
+static void epx_c3_stop(void)
+{
+
+	outb(0, EPXC3_WATCHDOG_CTL_REG);
+
+	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void epx_c3_pet(void)
+{
+	outb(1, EPXC3_WATCHDOG_PET_REG);
+}
+
+/*
+ *	Allow only one person to hold it open
+ */
+static int epx_c3_open(struct inode *inode, struct file *file)
+{
+	if (epx_c3_alive)
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Activate timer */
+	epx_c3_start();
+	epx_c3_pet();
+
+	epx_c3_alive = 1;
+	printk(KERN_INFO "Started watchdog timer.\n");
+
+	return nonseekable_open(inode, file);
+}
+
+static int epx_c3_release(struct inode *inode, struct file *file)
+{
+	/* Shut off the timer.
+	 * Lock it in if it's a module and we defined ...NOWAYOUT */
+	if (!nowayout)
+		epx_c3_stop();		/* Turn the WDT off */
+
+	epx_c3_alive = 0;
+
+	return 0;
+}
+
+static ssize_t epx_c3_write(struct file *file, const char *data,
+			size_t len, loff_t *ppos)
+{
+	/* Refresh the timer. */
+	if (len)
+		epx_c3_pet();
+	return len;
+}
+
+static int epx_c3_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int options, retval = -EINVAL;
+	static struct watchdog_info ident = {
+		.options		= WDIOF_KEEPALIVEPING |
+					  WDIOF_MAGICCLOSE,
+		.firmware_version	= 0,
+		.identity		= "Winsystems EPX-C3 H/W Watchdog",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user((struct watchdog_info *)arg,
+				 &ident, sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0,(int *)arg);
+	case WDIOC_KEEPALIVE:
+		epx_c3_pet();
+		return 0;
+	case WDIOC_GETTIMEOUT:
+		return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+	case WDIOC_SETOPTIONS: {
+		if (get_user(options, (int *)arg))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD) {
+			epx_c3_stop();
+			retval = 0;
+		}
+
+		if (options & WDIOS_ENABLECARD) {
+			epx_c3_start();
+			retval = 0;
+		}
+
+		return retval;
+	}
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
+				void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		epx_c3_stop();		/* Turn the WDT off */
+
+	return NOTIFY_DONE;
+}
+
+static struct file_operations epx_c3_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= epx_c3_write,
+	.ioctl		= epx_c3_ioctl,
+	.open		= epx_c3_open,
+	.release	= epx_c3_release,
+};
+
+static struct miscdevice epx_c3_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &epx_c3_fops,
+};
+
+static struct notifier_block epx_c3_notifier = {
+	.notifier_call = epx_c3_notify_sys,
+};
+
+static const char banner[] __initdata =
+    KERN_INFO PFX "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
+
+static int __init watchdog_init(void)
+{
+	int ret;
+
+	ret = register_reboot_notifier(&epx_c3_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier "
+			"(err=%d)\n", ret);
+		return ret;
+	}
+
+	ret = misc_register(&epx_c3_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
+			"(err=%d)\n", WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&epx_c3_notifier);
+		return ret;
+	}
+
+	printk(banner);
+
+	return 0;
+}
+
+static void __exit watchdog_exit(void)
+{
+	misc_deregister(&epx_c3_miscdev);
+	unregister_reboot_notifier(&epx_c3_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC.  Note that there is no way to probe for this device -- so only use it if you are *sure* you are runnning on this specific SBC system from Winsystems!  It writes to IO ports 0x1ee and 0x1ef!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index a9163d0..277a843 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -41,7 +41,6 @@
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static void handle_update(void *data);
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
 
 /**
  * Two notifier lists: the "policy" list is involved in the 
@@ -127,7 +126,7 @@
 static unsigned int disable_ratelimit = 1;
 static DEFINE_SPINLOCK(disable_ratelimit_lock);
 
-static inline void cpufreq_debug_enable_ratelimit(void)
+static void cpufreq_debug_enable_ratelimit(void)
 {
 	unsigned long flags;
 
@@ -137,7 +136,7 @@
 	spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
 }
 
-static inline void cpufreq_debug_disable_ratelimit(void)
+static void cpufreq_debug_disable_ratelimit(void)
 {
 	unsigned long flags;
 
@@ -206,7 +205,7 @@
 static unsigned long l_p_j_ref;
 static unsigned int  l_p_j_ref_freq;
 
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 {
 	if (ci->flags & CPUFREQ_CONST_LOOPS)
 		return;
diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c
index ffe6f44..ca8e69d 100644
--- a/drivers/dio/dio-driver.c
+++ b/drivers/dio/dio-driver.c
@@ -83,7 +83,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &dio_bus_type;
-	drv->driver.probe = dio_device_probe;
 
 	/* register with core */
 	count = driver_register(&drv->driver);
@@ -145,7 +144,8 @@
 
 struct bus_type dio_bus_type = {
 	.name	= "dio",
-	.match	= dio_bus_match
+	.match	= dio_bus_match,
+	.probe	= dio_device_probe,
 };
 
 
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index dfedb77..fdb8b04 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -49,7 +49,7 @@
 MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
 MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("3.1");
+MODULE_VERSION("3.2");
 
 #define BIOS_SCAN_LIMIT 0xffffffff
 #define MAX_IMAGE_LENGTH 16
@@ -564,12 +564,10 @@
 
 static void callbackfn_rbu(const struct firmware *fw, void *context)
 {
-	int rc = 0;
+	rbu_data.entry_created = 0;
 
-	if (!fw || !fw->size) {
-		rbu_data.entry_created = 0;
+	if (!fw || !fw->size)
 		return;
-	}
 
 	spin_lock(&rbu_data.lock);
 	if (!strcmp(image_type, "mono")) {
@@ -592,15 +590,6 @@
 	} else
 		pr_debug("invalid image type specified.\n");
 	spin_unlock(&rbu_data.lock);
-
-	rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-		"dell_rbu", &rbu_device->dev, &context, callbackfn_rbu);
-	if (rc)
-		printk(KERN_ERR
-			"dell_rbu:%s request_firmware_nowait failed"
-			" %d\n", __FUNCTION__, rc);
-	else
-		rbu_data.entry_created = 1;
 }
 
 static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
@@ -735,14 +724,7 @@
 	sysfs_create_bin_file(&rbu_device->dev.kobj,
 		&rbu_packet_size_attr);
 
-	rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-		"dell_rbu", &rbu_device->dev, &context, callbackfn_rbu);
-	if (rc)
-		printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
-			" failed %d\n", __FUNCTION__, rc);
-	else
-		rbu_data.entry_created = 1;
-
+	rbu_data.entry_created = 0;
 	return rc;
 
 }
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 52b7747..0ce58b5 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -63,13 +63,6 @@
 	return rc;
 }
 
-struct bus_type i2c_bus_type = {
-	.name =		"i2c",
-	.match =	i2c_device_match,
-	.suspend =      i2c_bus_suspend,
-	.resume =       i2c_bus_resume,
-};
-
 static int i2c_device_probe(struct device *dev)
 {
 	return -ENODEV;
@@ -80,6 +73,15 @@
 	return 0;
 }
 
+struct bus_type i2c_bus_type = {
+	.name =		"i2c",
+	.match =	i2c_device_match,
+	.probe =	i2c_device_probe,
+	.remove =	i2c_device_remove,
+	.suspend =      i2c_bus_suspend,
+	.resume =       i2c_bus_resume,
+};
+
 void i2c_adapter_dev_release(struct device *dev)
 {
 	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
@@ -90,8 +92,6 @@
 	.owner = THIS_MODULE,
 	.name =	"i2c_adapter",
 	.bus = &i2c_bus_type,
-	.probe = i2c_device_probe,
-	.remove = i2c_device_remove,
 };
 
 static void i2c_adapter_class_dev_release(struct class_device *dev)
@@ -294,8 +294,6 @@
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.owner = owner;
 	driver->driver.bus = &i2c_bus_type;
-	driver->driver.probe = i2c_device_probe;
-	driver->driver.remove = i2c_device_remove;
 
 	res = driver_register(&driver->driver);
 	if (res)
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 9b2ebd2..3325660 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -980,7 +980,7 @@
  * and attempt to recover if there are problems.  Returns  0 if everything's
  * ok; nonzero if the request has been terminated.
  */
-static inline
+static
 int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 {
 	if (ireason == 2)
@@ -1539,7 +1539,7 @@
 /*
  * Write handling
  */
-static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
 {
 	/* Two notes about IDE interrupt reason here - 0 means that
 	 * the drive wants to receive data from us, 2 means that
@@ -3256,9 +3256,8 @@
 }
 #endif
 
-static int ide_cd_remove(struct device *dev)
+static void ide_cd_remove(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	struct cdrom_info *info = drive->driver_data;
 
 	ide_unregister_subdriver(drive, info->driver);
@@ -3266,8 +3265,6 @@
 	del_gendisk(info->disk);
 
 	ide_cd_put(info);
-
-	return 0;
 }
 
 static void ide_cd_release(struct kref *kref)
@@ -3291,7 +3288,7 @@
 	kfree(info);
 }
 
-static int ide_cd_probe(struct device *);
+static int ide_cd_probe(ide_drive_t *);
 
 #ifdef CONFIG_PROC_FS
 static int proc_idecd_read_capacity
@@ -3317,9 +3314,9 @@
 		.owner		= THIS_MODULE,
 		.name		= "ide-cdrom",
 		.bus		= &ide_bus_type,
-		.probe		= ide_cd_probe,
-		.remove		= ide_cd_remove,
 	},
+	.probe			= ide_cd_probe,
+	.remove			= ide_cd_remove,
 	.version		= IDECD_VERSION,
 	.media			= ide_cdrom,
 	.supports_dsc_overlap	= 1,
@@ -3413,9 +3410,8 @@
 module_param(ignore, charp, 0400);
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cd_probe(struct device *dev)
+static int ide_cd_probe(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	struct cdrom_info *info;
 	struct gendisk *g;
 	struct request_sense sense;
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index cab362e..ca25f9e 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -477,7 +477,7 @@
 	       && id->lba_capacity_2;
 }
 
-static inline void idedisk_check_hpa(ide_drive_t *drive)
+static void idedisk_check_hpa(ide_drive_t *drive)
 {
 	unsigned long long capacity, set_max;
 	int lba48 = idedisk_supports_lba48(drive->id);
@@ -997,9 +997,8 @@
 		printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
 }
 
-static int ide_disk_remove(struct device *dev)
+static void ide_disk_remove(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	struct ide_disk_obj *idkp = drive->driver_data;
 	struct gendisk *g = idkp->disk;
 
@@ -1010,8 +1009,6 @@
 	ide_cacheflush_p(drive);
 
 	ide_disk_put(idkp);
-
-	return 0;
 }
 
 static void ide_disk_release(struct kref *kref)
@@ -1027,12 +1024,10 @@
 	kfree(idkp);
 }
 
-static int ide_disk_probe(struct device *dev);
+static int ide_disk_probe(ide_drive_t *drive);
 
-static void ide_device_shutdown(struct device *dev)
+static void ide_device_shutdown(ide_drive_t *drive)
 {
-	ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-
 #ifdef	CONFIG_ALPHA
 	/* On Alpha, halt(8) doesn't actually turn the machine off,
 	   it puts you into the sort of firmware monitor. Typically,
@@ -1054,7 +1049,7 @@
 	}
 
 	printk("Shutdown: %s\n", drive->name);
-	dev->bus->suspend(dev, PMSG_SUSPEND);
+	drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
 }
 
 static ide_driver_t idedisk_driver = {
@@ -1062,10 +1057,10 @@
 		.owner		= THIS_MODULE,
 		.name		= "ide-disk",
 		.bus		= &ide_bus_type,
-		.probe		= ide_disk_probe,
-		.remove		= ide_disk_remove,
-		.shutdown	= ide_device_shutdown,
 	},
+	.probe			= ide_disk_probe,
+	.remove			= ide_disk_remove,
+	.shutdown		= ide_device_shutdown,
 	.version		= IDEDISK_VERSION,
 	.media			= ide_disk,
 	.supports_dsc_overlap	= 0,
@@ -1182,9 +1177,8 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-static int ide_disk_probe(struct device *dev)
+static int ide_disk_probe(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	struct ide_disk_obj *idkp;
 	struct gendisk *g;
 
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 5945f55..1f8db9a 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1871,9 +1871,8 @@
 	idefloppy_add_settings(drive);
 }
 
-static int ide_floppy_remove(struct device *dev)
+static void ide_floppy_remove(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	struct gendisk *g = floppy->disk;
 
@@ -1882,8 +1881,6 @@
 	del_gendisk(g);
 
 	ide_floppy_put(floppy);
-
-	return 0;
 }
 
 static void ide_floppy_release(struct kref *kref)
@@ -1922,16 +1919,16 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int ide_floppy_probe(struct device *);
+static int ide_floppy_probe(ide_drive_t *);
 
 static ide_driver_t idefloppy_driver = {
 	.gen_driver = {
 		.owner		= THIS_MODULE,
 		.name		= "ide-floppy",
 		.bus		= &ide_bus_type,
-		.probe		= ide_floppy_probe,
-		.remove		= ide_floppy_remove,
 	},
+	.probe			= ide_floppy_probe,
+	.remove			= ide_floppy_remove,
 	.version		= IDEFLOPPY_VERSION,
 	.media			= ide_floppy,
 	.supports_dsc_overlap	= 0,
@@ -2136,9 +2133,8 @@
 	.revalidate_disk= idefloppy_revalidate_disk
 };
 
-static int ide_floppy_probe(struct device *dev)
+static int ide_floppy_probe(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	idefloppy_floppy_t *floppy;
 	struct gendisk *g;
 
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index fab9b2b..0101d0d 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -4682,9 +4682,8 @@
 	idetape_add_settings(drive);
 }
 
-static int ide_tape_remove(struct device *dev)
+static void ide_tape_remove(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	idetape_tape_t *tape = drive->driver_data;
 
 	ide_unregister_subdriver(drive, tape->driver);
@@ -4692,8 +4691,6 @@
 	ide_unregister_region(tape->disk);
 
 	ide_tape_put(tape);
-
-	return 0;
 }
 
 static void ide_tape_release(struct kref *kref)
@@ -4745,16 +4742,16 @@
 
 #endif
 
-static int ide_tape_probe(struct device *);
+static int ide_tape_probe(ide_drive_t *);
 
 static ide_driver_t idetape_driver = {
 	.gen_driver = {
 		.owner		= THIS_MODULE,
 		.name		= "ide-tape",
 		.bus		= &ide_bus_type,
-		.probe		= ide_tape_probe,
-		.remove		= ide_tape_remove,
 	},
+	.probe			= ide_tape_probe,
+	.remove			= ide_tape_remove,
 	.version		= IDETAPE_VERSION,
 	.media			= ide_tape,
 	.supports_dsc_overlap 	= 1,
@@ -4825,9 +4822,8 @@
 	.ioctl		= idetape_ioctl,
 };
 
-static int ide_tape_probe(struct device *dev)
+static int ide_tape_probe(ide_drive_t *drive)
 {
-	ide_drive_t *drive = to_ide_device(dev);
 	idetape_tape_t *tape;
 	struct gendisk *g;
 	int minor;
@@ -4883,9 +4879,9 @@
 	idetape_setup(drive, tape, minor);
 
 	class_device_create(idetape_sysfs_class, NULL,
-			MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name);
+			MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
 	class_device_create(idetape_sysfs_class, NULL,
-			MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name);
+			MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
 
 	devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
 			S_IFCHR | S_IRUGO | S_IWUGO,
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 62ebefd..9834dce 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -308,7 +308,7 @@
 		ide_pio_sector(drive, write);
 }
 
-static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 				     unsigned int write)
 {
 	if (rq->bio)	/* fs request */
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index ec5a4cb..afeb02bb 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1949,10 +1949,41 @@
 	return 0;
 }
 
+static int generic_ide_probe(struct device *dev)
+{
+	ide_drive_t *drive = to_ide_device(dev);
+	ide_driver_t *drv = to_ide_driver(dev->driver);
+
+	return drv->probe ? drv->probe(drive) : -ENODEV;
+}
+
+static int generic_ide_remove(struct device *dev)
+{
+	ide_drive_t *drive = to_ide_device(dev);
+	ide_driver_t *drv = to_ide_driver(dev->driver);
+
+	if (drv->remove)
+		drv->remove(drive);
+
+	return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+	ide_drive_t *drive = to_ide_device(dev);
+	ide_driver_t *drv = to_ide_driver(dev->driver);
+
+	if (dev->driver && drv->shutdown)
+		drv->shutdown(drive);
+}
+
 struct bus_type ide_bus_type = {
 	.name		= "ide",
 	.match		= ide_bus_match,
 	.uevent		= ide_uevent,
+	.probe		= generic_ide_probe,
+	.remove		= generic_ide_remove,
+	.shutdown	= generic_ide_shutdown,
 	.dev_attrs	= ide_dev_attrs,
 	.suspend	= generic_ide_suspend,
 	.resume		= generic_ide_resume,
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 3a611fe..2514de3 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -856,7 +856,7 @@
 		       param->private_data_len);
 }
 
-static inline int cm_validate_req_param(struct ib_cm_req_param *param)
+static int cm_validate_req_param(struct ib_cm_req_param *param)
 {
 	/* peer-to-peer not supported */
 	if (param->peer_to_peer)
@@ -1005,7 +1005,7 @@
 		 (be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn))));
 }
 
-static inline void cm_format_paths_from_req(struct cm_req_msg *req_msg,
+static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
 					    struct ib_sa_path_rec *primary_path,
 					    struct ib_sa_path_rec *alt_path)
 {
@@ -3163,22 +3163,6 @@
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-static __be64 cm_get_ca_guid(struct ib_device *device)
-{
-	struct ib_device_attr *device_attr;
-	__be64 guid;
-	int ret;
-
-	device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
-	if (!device_attr)
-		return 0;
-
-	ret = ib_query_device(device, device_attr);
-	guid = ret ? 0 : device_attr->node_guid;
-	kfree(device_attr);
-	return guid;
-}
-
 static void cm_add_one(struct ib_device *device)
 {
 	struct cm_device *cm_dev;
@@ -3200,9 +3184,7 @@
 		return;
 
 	cm_dev->device = device;
-	cm_dev->ca_guid = cm_get_ca_guid(device);
-	if (!cm_dev->ca_guid)
-		goto error1;
+	cm_dev->ca_guid = device->node_guid;
 
 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
 	for (i = 1; i <= device->phys_port_cnt; i++) {
@@ -3217,11 +3199,11 @@
 							cm_recv_handler,
 							port);
 		if (IS_ERR(port->mad_agent))
-			goto error2;
+			goto error1;
 
 		ret = ib_modify_port(device, i, 0, &port_modify);
 		if (ret)
-			goto error3;
+			goto error2;
 	}
 	ib_set_client_data(device, &cm_client, cm_dev);
 
@@ -3230,9 +3212,9 @@
 	write_unlock_irqrestore(&cm.device_lock, flags);
 	return;
 
-error3:
-	ib_unregister_mad_agent(port->mad_agent);
 error2:
+	ib_unregister_mad_agent(port->mad_agent);
+error1:
 	port_modify.set_port_cap_mask = 0;
 	port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
 	while (--i) {
@@ -3240,7 +3222,6 @@
 		ib_modify_port(device, port->port_num, 0, &port_modify);
 		ib_unregister_mad_agent(port->mad_agent);
 	}
-error1:
 	kfree(cm_dev);
 }
 
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index e169e79..b2f3cb9 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -38,8 +38,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "core_priv.h"
 
@@ -57,13 +56,13 @@
 static LIST_HEAD(client_list);
 
 /*
- * device_sem protects access to both device_list and client_list.
+ * device_mutex protects access to both device_list and client_list.
  * There's no real point to using multiple locks or something fancier
  * like an rwsem: we always access both lists, and we're always
  * modifying one list or the other list.  In any case this is not a
  * hot path so there's no point in trying to optimize.
  */
-static DECLARE_MUTEX(device_sem);
+static DEFINE_MUTEX(device_mutex);
 
 static int ib_device_check_mandatory(struct ib_device *device)
 {
@@ -221,7 +220,7 @@
 {
 	int ret;
 
-	down(&device_sem);
+	mutex_lock(&device_mutex);
 
 	if (strchr(device->name, '%')) {
 		ret = alloc_name(device->name);
@@ -259,7 +258,7 @@
 	}
 
  out:
-	up(&device_sem);
+	mutex_unlock(&device_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(ib_register_device);
@@ -276,7 +275,7 @@
 	struct ib_client_data *context, *tmp;
 	unsigned long flags;
 
-	down(&device_sem);
+	mutex_lock(&device_mutex);
 
 	list_for_each_entry_reverse(client, &client_list, list)
 		if (client->remove)
@@ -284,7 +283,7 @@
 
 	list_del(&device->core_list);
 
-	up(&device_sem);
+	mutex_unlock(&device_mutex);
 
 	spin_lock_irqsave(&device->client_data_lock, flags);
 	list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
@@ -312,14 +311,14 @@
 {
 	struct ib_device *device;
 
-	down(&device_sem);
+	mutex_lock(&device_mutex);
 
 	list_add_tail(&client->list, &client_list);
 	list_for_each_entry(device, &device_list, core_list)
 		if (client->add && !add_client_context(device, client))
 			client->add(device);
 
-	up(&device_sem);
+	mutex_unlock(&device_mutex);
 
 	return 0;
 }
@@ -339,7 +338,7 @@
 	struct ib_device *device;
 	unsigned long flags;
 
-	down(&device_sem);
+	mutex_lock(&device_mutex);
 
 	list_for_each_entry(device, &device_list, core_list) {
 		if (client->remove)
@@ -355,7 +354,7 @@
 	}
 	list_del(&client->list);
 
-	up(&device_sem);
+	mutex_unlock(&device_mutex);
 }
 EXPORT_SYMBOL(ib_unregister_client);
 
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 1f1743c..5982d68 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -445,13 +445,7 @@
 		return -ENOMEM;
 
 	/*
-	 * It might be nice to pass the node GUID with the event, but
-	 * right now the only way to get it is to query the device
-	 * provider, and this can crash during device removal because
-	 * we are will be running after driver removal has started.
-	 * We could add a node_guid field to struct ib_device, or we
-	 * could just let userspace read the node GUID from sysfs when
-	 * devices are added.
+	 * It would be nice to pass the node GUID with the event...
 	 */
 
 	envp[i] = NULL;
@@ -623,21 +617,15 @@
 static ssize_t show_node_guid(struct class_device *cdev, char *buf)
 {
 	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
-	struct ib_device_attr attr;
-	ssize_t ret;
 
 	if (!ibdev_is_alive(dev))
 		return -ENODEV;
 
-	ret = ib_query_device(dev, &attr);
-	if (ret)
-		return ret;
-
 	return sprintf(buf, "%04x:%04x:%04x:%04x\n",
-		       be16_to_cpu(((__be16 *) &attr.node_guid)[0]),
-		       be16_to_cpu(((__be16 *) &attr.node_guid)[1]),
-		       be16_to_cpu(((__be16 *) &attr.node_guid)[2]),
-		       be16_to_cpu(((__be16 *) &attr.node_guid)[3]));
+		       be16_to_cpu(((__be16 *) &dev->node_guid)[0]),
+		       be16_to_cpu(((__be16 *) &dev->node_guid)[1]),
+		       be16_to_cpu(((__be16 *) &dev->node_guid)[2]),
+		       be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
 }
 
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index 6e15787..e95c429 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -42,6 +42,7 @@
 #include <linux/mount.h>
 #include <linux/cdev.h>
 #include <linux/idr.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -113,7 +114,7 @@
 	.remove = ib_ucm_remove_one
 };
 
-static DECLARE_MUTEX(ctx_id_mutex);
+static DEFINE_MUTEX(ctx_id_mutex);
 static DEFINE_IDR(ctx_id_table);
 static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES);
 
@@ -121,7 +122,7 @@
 {
 	struct ib_ucm_context *ctx;
 
-	down(&ctx_id_mutex);
+	mutex_lock(&ctx_id_mutex);
 	ctx = idr_find(&ctx_id_table, id);
 	if (!ctx)
 		ctx = ERR_PTR(-ENOENT);
@@ -129,7 +130,7 @@
 		ctx = ERR_PTR(-EINVAL);
 	else
 		atomic_inc(&ctx->ref);
-	up(&ctx_id_mutex);
+	mutex_unlock(&ctx_id_mutex);
 
 	return ctx;
 }
@@ -186,9 +187,9 @@
 		if (!result)
 			goto error;
 
-		down(&ctx_id_mutex);
+		mutex_lock(&ctx_id_mutex);
 		result = idr_get_new(&ctx_id_table, ctx, &ctx->id);
-		up(&ctx_id_mutex);
+		mutex_unlock(&ctx_id_mutex);
 	} while (result == -EAGAIN);
 
 	if (result)
@@ -550,9 +551,9 @@
 err2:
 	ib_destroy_cm_id(ctx->cm_id);
 err1:
-	down(&ctx_id_mutex);
+	mutex_lock(&ctx_id_mutex);
 	idr_remove(&ctx_id_table, ctx->id);
-	up(&ctx_id_mutex);
+	mutex_unlock(&ctx_id_mutex);
 	kfree(ctx);
 	return result;
 }
@@ -572,7 +573,7 @@
 	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
 		return -EFAULT;
 
-	down(&ctx_id_mutex);
+	mutex_lock(&ctx_id_mutex);
 	ctx = idr_find(&ctx_id_table, cmd.id);
 	if (!ctx)
 		ctx = ERR_PTR(-ENOENT);
@@ -580,7 +581,7 @@
 		ctx = ERR_PTR(-EINVAL);
 	else
 		idr_remove(&ctx_id_table, ctx->id);
-	up(&ctx_id_mutex);
+	mutex_unlock(&ctx_id_mutex);
 
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
@@ -1280,9 +1281,9 @@
 				 struct ib_ucm_context, file_list);
 		up(&file->mutex);
 
-		down(&ctx_id_mutex);
+		mutex_lock(&ctx_id_mutex);
 		idr_remove(&ctx_id_table, ctx->id);
-		up(&ctx_id_mutex);
+		mutex_unlock(&ctx_id_mutex);
 
 		ib_destroy_cm_id(ctx->cm_id);
 		ib_ucm_cleanup_events(ctx);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 7114e3f..f7eecbc 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -41,6 +41,7 @@
 
 #include <linux/kref.h>
 #include <linux/idr.h>
+#include <linux/mutex.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
@@ -88,7 +89,7 @@
 
 struct ib_uverbs_file {
 	struct kref				ref;
-	struct semaphore			mutex;
+	struct mutex				mutex;
 	struct ib_uverbs_device		       *device;
 	struct ib_ucontext		       *ucontext;
 	struct ib_event_handler			event_handler;
@@ -131,7 +132,7 @@
 	u32			async_events_reported;
 };
 
-extern struct semaphore ib_uverbs_idr_mutex;
+extern struct mutex ib_uverbs_idr_mutex;
 extern struct idr ib_uverbs_pd_idr;
 extern struct idr ib_uverbs_mr_idr;
 extern struct idr ib_uverbs_mw_idr;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index a02c5a0..407b628 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -67,7 +67,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 
 	if (file->ucontext) {
 		ret = -EINVAL;
@@ -119,7 +119,7 @@
 
 	fd_install(resp.async_fd, filp);
 
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	return in_len;
 
@@ -131,7 +131,7 @@
 	ibdev->dealloc_ucontext(ucontext);
 
 err:
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 	return ret;
 }
 
@@ -157,7 +157,7 @@
 	memset(&resp, 0, sizeof resp);
 
 	resp.fw_ver 		       = attr.fw_ver;
-	resp.node_guid 		       = attr.node_guid;
+	resp.node_guid 		       = file->device->ib_dev->node_guid;
 	resp.sys_image_guid 	       = attr.sys_image_guid;
 	resp.max_mr_size 	       = attr.max_mr_size;
 	resp.page_size_cap 	       = attr.page_size_cap;
@@ -290,7 +290,7 @@
 	pd->uobject = uobj;
 	atomic_set(&pd->usecnt, 0);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
 	if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
@@ -314,11 +314,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&uobj->list, &file->ucontext->pd_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -326,7 +326,7 @@
 	idr_remove(&ib_uverbs_pd_idr, uobj->id);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 	ib_dealloc_pd(pd);
 
 err:
@@ -346,7 +346,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 	if (!pd || pd->uobject->context != file->ucontext)
@@ -360,14 +360,14 @@
 
 	idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	kfree(uobj);
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -426,7 +426,7 @@
 
 	obj->umem.virt_base = cmd.hca_va;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 	if (!pd || pd->uobject->context != file->ucontext) {
@@ -476,11 +476,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -492,7 +492,7 @@
 	atomic_dec(&pd->usecnt);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	ib_umem_release(file->device->ib_dev, &obj->umem);
 
@@ -513,7 +513,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
 	if (!mr || mr->uobject->context != file->ucontext)
@@ -527,15 +527,15 @@
 
 	idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&memobj->uobject.list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	ib_umem_release(file->device->ib_dev, &memobj->umem);
 	kfree(memobj);
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -628,7 +628,7 @@
 	cq->cq_context    = ev_file;
 	atomic_set(&cq->usecnt, 0);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
 	if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
@@ -653,11 +653,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -665,7 +665,7 @@
 	idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 	ib_destroy_cq(cq);
 
 err:
@@ -701,7 +701,7 @@
 		goto out_wc;
 	}
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
 	if (!cq || cq->uobject->context != file->ucontext) {
 		ret = -EINVAL;
@@ -731,7 +731,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 	kfree(resp);
 
 out_wc:
@@ -750,14 +750,14 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
 	if (cq && cq->uobject->context == file->ucontext) {
 		ib_req_notify_cq(cq, cmd.solicited_only ?
 					IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
 		ret = in_len;
 	}
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret;
 }
@@ -779,7 +779,7 @@
 
 	memset(&resp, 0, sizeof resp);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
 	if (!cq || cq->uobject->context != file->ucontext)
@@ -795,9 +795,9 @@
 
 	idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&uobj->uobject.list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	ib_uverbs_release_ucq(file, ev_file, uobj);
 
@@ -811,7 +811,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -845,7 +845,7 @@
 	if (!uobj)
 		return -ENOMEM;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 	scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
@@ -930,11 +930,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -950,7 +950,7 @@
 		atomic_dec(&attr.srq->usecnt);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	kfree(uobj);
 	return ret;
@@ -972,7 +972,7 @@
 	if (!attr)
 		return -ENOMEM;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext) {
@@ -1033,7 +1033,7 @@
 	ret = in_len;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 	kfree(attr);
 
 	return ret;
@@ -1054,7 +1054,7 @@
 
 	memset(&resp, 0, sizeof resp);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext)
@@ -1073,9 +1073,9 @@
 
 	idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&uobj->uevent.uobject.list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	ib_uverbs_release_uevent(file, &uobj->uevent);
 
@@ -1088,7 +1088,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -1119,7 +1119,7 @@
 	if (!user_wr)
 		return -ENOMEM;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext)
@@ -1224,7 +1224,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	while (wr) {
 		next = wr->next;
@@ -1341,7 +1341,7 @@
 	if (IS_ERR(wr))
 		return PTR_ERR(wr);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext)
@@ -1362,7 +1362,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	while (wr) {
 		next = wr->next;
@@ -1392,7 +1392,7 @@
 	if (IS_ERR(wr))
 		return PTR_ERR(wr);
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
 	if (!srq || srq->uobject->context != file->ucontext)
@@ -1413,7 +1413,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	while (wr) {
 		next = wr->next;
@@ -1446,7 +1446,7 @@
 	if (!uobj)
 		return -ENOMEM;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 	if (!pd || pd->uobject->context != file->ucontext) {
@@ -1498,11 +1498,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&uobj->list, &file->ucontext->ah_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -1513,7 +1513,7 @@
 	ib_destroy_ah(ah);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	kfree(uobj);
 	return ret;
@@ -1530,7 +1530,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle);
 	if (!ah || ah->uobject->context != file->ucontext)
@@ -1544,14 +1544,14 @@
 
 	idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&uobj->list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	kfree(uobj);
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -1569,7 +1569,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext)
@@ -1602,7 +1602,7 @@
 		kfree(mcast);
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -1620,7 +1620,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
 	if (!qp || qp->uobject->context != file->ucontext)
@@ -1641,7 +1641,7 @@
 		}
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -1673,7 +1673,7 @@
 	if (!uobj)
 		return -ENOMEM;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 
@@ -1730,11 +1730,11 @@
 		goto err_idr;
 	}
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return in_len;
 
@@ -1746,7 +1746,7 @@
 	atomic_dec(&pd->usecnt);
 
 err_up:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	kfree(uobj);
 	return ret;
@@ -1764,7 +1764,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
 	if (!srq || srq->uobject->context != file->ucontext) {
@@ -1778,7 +1778,7 @@
 	ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
@@ -1796,7 +1796,7 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	memset(&resp, 0, sizeof resp);
 
@@ -1812,9 +1812,9 @@
 
 	idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
 
-	down(&file->mutex);
+	mutex_lock(&file->mutex);
 	list_del(&uobj->uobject.list);
-	up(&file->mutex);
+	mutex_unlock(&file->mutex);
 
 	ib_uverbs_release_uevent(file, uobj);
 
@@ -1827,7 +1827,7 @@
 		ret = -EFAULT;
 
 out:
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return ret ? ret : in_len;
 }
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 81737bd..96ea79b 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -66,7 +66,7 @@
 
 static struct class *uverbs_class;
 
-DECLARE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_MUTEX(ib_uverbs_idr_mutex);
 DEFINE_IDR(ib_uverbs_pd_idr);
 DEFINE_IDR(ib_uverbs_mr_idr);
 DEFINE_IDR(ib_uverbs_mw_idr);
@@ -180,7 +180,7 @@
 	if (!context)
 		return 0;
 
-	down(&ib_uverbs_idr_mutex);
+	mutex_lock(&ib_uverbs_idr_mutex);
 
 	list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
 		struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id);
@@ -250,7 +250,7 @@
 		kfree(uobj);
 	}
 
-	up(&ib_uverbs_idr_mutex);
+	mutex_unlock(&ib_uverbs_idr_mutex);
 
 	return context->device->dealloc_ucontext(context);
 }
@@ -653,7 +653,7 @@
 	file->ucontext	 = NULL;
 	file->async_file = NULL;
 	kref_init(&file->ref);
-	init_MUTEX(&file->mutex);
+	mutex_init(&file->mutex);
 
 	filp->private_data = file;
 
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index 22fdc44..a14eed0 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -163,6 +163,11 @@
 	return 0;
 }
 
+int mthca_ah_grh_present(struct mthca_ah *ah)
+{
+	return !!(ah->av->g_slid & 0x80);
+}
+
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
 		  struct ib_ud_header *header)
 {
@@ -172,8 +177,7 @@
 	header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
 	header->lrh.destination_lid = ah->av->dlid;
 	header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
-	if (ah->av->g_slid & 0x80) {
-		header->grh_present = 1;
+	if (mthca_ah_grh_present(ah)) {
 		header->grh.traffic_class =
 			(be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
 		header->grh.flow_label    =
@@ -184,8 +188,6 @@
 				  &header->grh.source_gid);
 		memcpy(header->grh.destination_gid.raw,
 		       ah->av->dgid, 16);
-	} else {
-		header->grh_present = 0;
 	}
 
 	return 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 22ac72b..be1791b 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -606,7 +606,7 @@
 			err = -EINVAL;
 			goto out;
 		}
-		for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i) {
+		for (i = 0; i < mthca_icm_size(&iter) >> lg; ++i) {
 			if (virt != -1) {
 				pages[nent * 2] = cpu_to_be64(virt);
 				virt += 1 << lg;
@@ -727,8 +727,8 @@
 		 * system pages needed.
 		 */
 		dev->fw.arbel.fw_pages =
-			(dev->fw.arbel.fw_pages + (1 << (PAGE_SHIFT - 12)) - 1) >>
-			(PAGE_SHIFT - 12);
+			ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
+				(PAGE_SHIFT - 12);
 
 		mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
 			  (unsigned long long) dev->fw.arbel.clr_int_base,
@@ -1445,6 +1445,7 @@
 	 * pages needed.
 	 */
 	*aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
+	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
 
 	return 0;
 }
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 795b379..a104ab0 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -520,6 +520,7 @@
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah);
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
 		  struct ib_ud_header *header);
+int mthca_ah_grh_present(struct mthca_ah *ah);
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index e8a948f..2eabb27 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -45,6 +45,7 @@
 enum {
 	MTHCA_NUM_ASYNC_EQE = 0x80,
 	MTHCA_NUM_CMD_EQE   = 0x80,
+	MTHCA_NUM_SPARE_EQE = 0x80,
 	MTHCA_EQ_ENTRY_SIZE = 0x20
 };
 
@@ -277,11 +278,10 @@
 {
 	struct mthca_eqe *eqe;
 	int disarm_cqn;
-	int  eqes_found = 0;
+	int eqes_found = 0;
+	int set_ci = 0;
 
 	while ((eqe = next_eqe_sw(eq))) {
-		int set_ci = 0;
-
 		/*
 		 * Make sure we read EQ entry contents after we've
 		 * checked the ownership bit.
@@ -345,12 +345,6 @@
 					be16_to_cpu(eqe->event.cmd.token),
 					eqe->event.cmd.status,
 					be64_to_cpu(eqe->event.cmd.out_param));
-			/*
-			 * cmd_event() may add more commands.
-			 * The card will think the queue has overflowed if
-			 * we don't tell it we've been processing events.
-			 */
-			set_ci = 1;
 			break;
 
 		case MTHCA_EVENT_TYPE_PORT_CHANGE:
@@ -385,8 +379,16 @@
 		set_eqe_hw(eqe);
 		++eq->cons_index;
 		eqes_found = 1;
+		++set_ci;
 
-		if (unlikely(set_ci)) {
+		/*
+		 * The HCA will think the queue has overflowed if we
+		 * don't tell it we've been processing events.  We
+		 * create our EQs with MTHCA_NUM_SPARE_EQE extra
+		 * entries, so we must update our consumer index at
+		 * least that often.
+		 */
+		if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) {
 			/*
 			 * Conditional on hca_type is OK here because
 			 * this is a rare case, not the fast path.
@@ -862,19 +864,19 @@
 	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
 		128 : dev->eq_table.inta_pin;
 
-	err = mthca_create_eq(dev, dev->limits.num_cqs,
+	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
 			      &dev->eq_table.eq[MTHCA_EQ_COMP]);
 	if (err)
 		goto err_out_unmap;
 
-	err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE,
+	err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,
 			      &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
 	if (err)
 		goto err_out_comp;
 
-	err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE,
+	err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,
 			      &dev->eq_table.eq[MTHCA_EQ_CMD]);
 	if (err)
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 4cc7e28..484a7e6 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -33,7 +33,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mthca_provider.c 1397 2004-12-28 05:09:00Z roland $
+ * $Id: mthca_provider.c 4859 2006-01-09 21:55:10Z roland $
  */
 
 #include <rdma/ib_smi.h>
@@ -45,6 +45,14 @@
 #include "mthca_user.h"
 #include "mthca_memfree.h"
 
+static void init_query_mad(struct ib_smp *mad)
+{
+	mad->base_version  = 1;
+	mad->mgmt_class    = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+	mad->class_version = 1;
+	mad->method    	   = IB_MGMT_METHOD_GET;
+}
+
 static int mthca_query_device(struct ib_device *ibdev,
 			      struct ib_device_attr *props)
 {
@@ -55,7 +63,7 @@
 
 	u8 status;
 
-	in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
 	if (!in_mad || !out_mad)
 		goto out;
@@ -64,12 +72,8 @@
 
 	props->fw_ver              = mdev->fw_ver;
 
-	memset(in_mad, 0, sizeof *in_mad);
-	in_mad->base_version       = 1;
-	in_mad->mgmt_class     	   = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	in_mad->class_version  	   = 1;
-	in_mad->method         	   = IB_MGMT_METHOD_GET;
-	in_mad->attr_id   	   = IB_SMP_ATTR_NODE_INFO;
+	init_query_mad(in_mad);
+	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
 
 	err = mthca_MAD_IFC(mdev, 1, 1,
 			    1, NULL, NULL, in_mad, out_mad,
@@ -87,7 +91,6 @@
 	props->vendor_part_id      = be16_to_cpup((__be16 *) (out_mad->data + 30));
 	props->hw_ver              = be32_to_cpup((__be32 *) (out_mad->data + 32));
 	memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
-	memcpy(&props->node_guid,      out_mad->data + 12, 8);
 
 	props->max_mr_size         = ~0ull;
 	props->page_size_cap       = mdev->limits.page_size_cap;
@@ -128,20 +131,16 @@
 	int err = -ENOMEM;
 	u8 status;
 
-	in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
 	if (!in_mad || !out_mad)
 		goto out;
 
 	memset(props, 0, sizeof *props);
 
-	memset(in_mad, 0, sizeof *in_mad);
-	in_mad->base_version       = 1;
-	in_mad->mgmt_class     	   = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	in_mad->class_version  	   = 1;
-	in_mad->method         	   = IB_MGMT_METHOD_GET;
-	in_mad->attr_id   	   = IB_SMP_ATTR_PORT_INFO;
-	in_mad->attr_mod           = cpu_to_be32(port);
+	init_query_mad(in_mad);
+	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+	in_mad->attr_mod = cpu_to_be32(port);
 
 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
 			    port, NULL, NULL, in_mad, out_mad,
@@ -220,18 +219,14 @@
 	int err = -ENOMEM;
 	u8 status;
 
-	in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
 	if (!in_mad || !out_mad)
 		goto out;
 
-	memset(in_mad, 0, sizeof *in_mad);
-	in_mad->base_version       = 1;
-	in_mad->mgmt_class     	   = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	in_mad->class_version  	   = 1;
-	in_mad->method         	   = IB_MGMT_METHOD_GET;
-	in_mad->attr_id   	   = IB_SMP_ATTR_PKEY_TABLE;
-	in_mad->attr_mod           = cpu_to_be32(index / 32);
+	init_query_mad(in_mad);
+	in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
+	in_mad->attr_mod = cpu_to_be32(index / 32);
 
 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
 			    port, NULL, NULL, in_mad, out_mad,
@@ -259,18 +254,14 @@
 	int err = -ENOMEM;
 	u8 status;
 
-	in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
 	if (!in_mad || !out_mad)
 		goto out;
 
-	memset(in_mad, 0, sizeof *in_mad);
-	in_mad->base_version       = 1;
-	in_mad->mgmt_class     	   = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	in_mad->class_version  	   = 1;
-	in_mad->method         	   = IB_MGMT_METHOD_GET;
-	in_mad->attr_id   	   = IB_SMP_ATTR_PORT_INFO;
-	in_mad->attr_mod           = cpu_to_be32(port);
+	init_query_mad(in_mad);
+	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+	in_mad->attr_mod = cpu_to_be32(port);
 
 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
 			    port, NULL, NULL, in_mad, out_mad,
@@ -284,13 +275,9 @@
 
 	memcpy(gid->raw, out_mad->data + 8, 8);
 
-	memset(in_mad, 0, sizeof *in_mad);
-	in_mad->base_version       = 1;
-	in_mad->mgmt_class     	   = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-	in_mad->class_version  	   = 1;
-	in_mad->method         	   = IB_MGMT_METHOD_GET;
-	in_mad->attr_id   	   = IB_SMP_ATTR_GUID_INFO;
-	in_mad->attr_mod           = cpu_to_be32(index / 8);
+	init_query_mad(in_mad);
+	in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
+	in_mad->attr_mod = cpu_to_be32(index / 8);
 
 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
 			    port, NULL, NULL, in_mad, out_mad,
@@ -458,8 +445,10 @@
 	if (pd->uobject) {
 		context = to_mucontext(pd->uobject->context);
 
-		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
-			return ERR_PTR(-EFAULT);
+		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+			err = -EFAULT;
+			goto err_free;
+		}
 
 		err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
 					context->db_tab, ucmd.db_index,
@@ -535,8 +524,10 @@
 		if (pd->uobject) {
 			context = to_mucontext(pd->uobject->context);
 
-			if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+			if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+				kfree(qp);
 				return ERR_PTR(-EFAULT);
+			}
 
 			err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
 						context->db_tab,
@@ -783,24 +774,20 @@
 	if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK))
 		return ERR_PTR(-EINVAL);
 
-	if (num_phys_buf > 1 &&
-	    ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK))
-		return ERR_PTR(-EINVAL);
-
 	mask = 0;
 	total_size = 0;
 	for (i = 0; i < num_phys_buf; ++i) {
-		if (i != 0 && buffer_list[i].addr & ~PAGE_MASK)
-			return ERR_PTR(-EINVAL);
-		if (i != 0 && i != num_phys_buf - 1 &&
-		    (buffer_list[i].size & ~PAGE_MASK))
-			return ERR_PTR(-EINVAL);
+		if (i != 0)
+			mask |= buffer_list[i].addr;
+		if (i != num_phys_buf - 1)
+			mask |= buffer_list[i].addr + buffer_list[i].size;
 
 		total_size += buffer_list[i].size;
-		if (i > 0)
-			mask |= buffer_list[i].addr;
 	}
 
+	if (mask & ~PAGE_MASK)
+		return ERR_PTR(-EINVAL);
+
 	/* Find largest page shift we can use to cover buffers */
 	for (shift = PAGE_SHIFT; shift < 31; ++shift)
 		if (num_phys_buf > 1) {
@@ -1070,11 +1057,48 @@
 	&class_device_attr_board_id
 };
 
+static int mthca_init_node_data(struct mthca_dev *dev)
+{
+	struct ib_smp *in_mad  = NULL;
+	struct ib_smp *out_mad = NULL;
+	int err = -ENOMEM;
+	u8 status;
+
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+	if (!in_mad || !out_mad)
+		goto out;
+
+	init_query_mad(in_mad);
+	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+	err = mthca_MAD_IFC(dev, 1, 1,
+			    1, NULL, NULL, in_mad, out_mad,
+			    &status);
+	if (err)
+		goto out;
+	if (status) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+
+out:
+	kfree(in_mad);
+	kfree(out_mad);
+	return err;
+}
+
 int mthca_register_device(struct mthca_dev *dev)
 {
 	int ret;
 	int i;
 
+	ret = mthca_init_node_data(dev);
+	if (ret)
+		return ret;
+
 	strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
 	dev->ib_dev.owner                = THIS_MODULE;
 
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 564b6d5..fba608e 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1434,7 +1434,7 @@
 	u16 pkey;
 
 	ib_ud_header_init(256, /* assume a MAD */
-			  sqp->ud_header.grh_present,
+			  mthca_ah_grh_present(to_mah(wr->wr.ud.ah)),
 			  &sqp->ud_header);
 
 	err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 9923a15..e0a5412 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -45,11 +45,11 @@
 #include <linux/config.h>
 #include <linux/kref.h>
 #include <linux/if_infiniband.h>
+#include <linux/mutex.h>
 
 #include <net/neighbour.h>
 
 #include <asm/atomic.h>
-#include <asm/semaphore.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_pack.h>
@@ -123,8 +123,8 @@
 
 	unsigned long flags;
 
-	struct semaphore mcast_mutex;
-	struct semaphore vlan_mutex;
+	struct mutex mcast_mutex;
+	struct mutex vlan_mutex;
 
 	struct rb_root  path_tree;
 	struct list_head path_list;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 2388580..86bcdd7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -52,7 +52,7 @@
 
 #define	IPOIB_OP_RECV	(1ul << 31)
 
-static DECLARE_MUTEX(pkey_sem);
+static DEFINE_MUTEX(pkey_mutex);
 
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
 				 struct ib_pd *pd, struct ib_ah_attr *attr)
@@ -445,25 +445,16 @@
 
 	/* Shutdown the P_Key thread if still active */
 	if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
-		down(&pkey_sem);
+		mutex_lock(&pkey_mutex);
 		set_bit(IPOIB_PKEY_STOP, &priv->flags);
 		cancel_delayed_work(&priv->pkey_task);
-		up(&pkey_sem);
+		mutex_unlock(&pkey_mutex);
 		flush_workqueue(ipoib_workqueue);
 	}
 
 	ipoib_mcast_stop_thread(dev, 1);
-
-	/*
-	 * Flush the multicast groups first so we stop any multicast joins. The
-	 * completion thread may have already died and we may deadlock waiting
-	 * for the completion thread to finish some multicast joins.
-	 */
 	ipoib_mcast_dev_flush(dev);
 
-	/* Delete broadcast and local addresses since they will be recreated */
-	ipoib_mcast_dev_down(dev);
-
 	ipoib_flush_paths(dev);
 
 	return 0;
@@ -608,13 +599,13 @@
 	if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
 		ipoib_ib_dev_up(dev);
 
-	down(&priv->vlan_mutex);
+	mutex_lock(&priv->vlan_mutex);
 
 	/* Flush any child interfaces too */
 	list_for_each_entry(cpriv, &priv->child_intfs, list)
 		ipoib_ib_dev_flush(&cpriv->dev);
 
-	up(&priv->vlan_mutex);
+	mutex_unlock(&priv->vlan_mutex);
 }
 
 void ipoib_ib_dev_cleanup(struct net_device *dev)
@@ -624,9 +615,7 @@
 	ipoib_dbg(priv, "cleaning up ib_dev\n");
 
 	ipoib_mcast_stop_thread(dev, 1);
-
-	/* Delete the broadcast address and the local address */
-	ipoib_mcast_dev_down(dev);
+	ipoib_mcast_dev_flush(dev);
 
 	ipoib_transport_dev_cleanup(dev);
 }
@@ -662,12 +651,12 @@
 	if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
 		ipoib_open(dev);
 	else {
-		down(&pkey_sem);
+		mutex_lock(&pkey_mutex);
 		if (!test_bit(IPOIB_PKEY_STOP, &priv->flags))
 			queue_delayed_work(ipoib_workqueue,
 					   &priv->pkey_task,
 					   HZ);
-		up(&pkey_sem);
+		mutex_unlock(&pkey_mutex);
 	}
 }
 
@@ -681,12 +670,12 @@
 
 	/* P_Key value not assigned yet - start polling */
 	if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
-		down(&pkey_sem);
+		mutex_lock(&pkey_mutex);
 		clear_bit(IPOIB_PKEY_STOP, &priv->flags);
 		queue_delayed_work(ipoib_workqueue,
 				   &priv->pkey_task,
 				   HZ);
-		up(&pkey_sem);
+		mutex_unlock(&pkey_mutex);
 		return 1;
 	}
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 780009c..fd3f5c8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -105,7 +105,7 @@
 		struct ipoib_dev_priv *cpriv;
 
 		/* Bring up any child interfaces too */
-		down(&priv->vlan_mutex);
+		mutex_lock(&priv->vlan_mutex);
 		list_for_each_entry(cpriv, &priv->child_intfs, list) {
 			int flags;
 
@@ -115,7 +115,7 @@
 
 			dev_change_flags(cpriv->dev, flags | IFF_UP);
 		}
-		up(&priv->vlan_mutex);
+		mutex_unlock(&priv->vlan_mutex);
 	}
 
 	netif_start_queue(dev);
@@ -140,7 +140,7 @@
 		struct ipoib_dev_priv *cpriv;
 
 		/* Bring down any child interfaces too */
-		down(&priv->vlan_mutex);
+		mutex_lock(&priv->vlan_mutex);
 		list_for_each_entry(cpriv, &priv->child_intfs, list) {
 			int flags;
 
@@ -150,7 +150,7 @@
 
 			dev_change_flags(cpriv->dev, flags & ~IFF_UP);
 		}
-		up(&priv->vlan_mutex);
+		mutex_unlock(&priv->vlan_mutex);
 	}
 
 	return 0;
@@ -892,8 +892,8 @@
 	spin_lock_init(&priv->lock);
 	spin_lock_init(&priv->tx_lock);
 
-	init_MUTEX(&priv->mcast_mutex);
-	init_MUTEX(&priv->vlan_mutex);
+	mutex_init(&priv->mcast_mutex);
+	mutex_init(&priv->vlan_mutex);
 
 	INIT_LIST_HEAD(&priv->path_list);
 	INIT_LIST_HEAD(&priv->child_intfs);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index ed0c2ea..98039da 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -55,7 +55,7 @@
 		 "Enable multicast debug tracing if > 0");
 #endif
 
-static DECLARE_MUTEX(mcast_mutex);
+static DEFINE_MUTEX(mcast_mutex);
 
 /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
 struct ipoib_mcast {
@@ -97,8 +97,6 @@
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_neigh *neigh, *tmp;
 	unsigned long flags;
-	LIST_HEAD(ah_list);
-	struct ipoib_ah *ah, *tah;
 
 	ipoib_dbg_mcast(netdev_priv(dev),
 			"deleting multicast group " IPOIB_GID_FMT "\n",
@@ -107,8 +105,14 @@
 	spin_lock_irqsave(&priv->lock, flags);
 
 	list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
+		/*
+		 * It's safe to call ipoib_put_ah() inside priv->lock
+		 * here, because we know that mcast->ah will always
+		 * hold one more reference, so ipoib_put_ah() will
+		 * never do more than decrement the ref count.
+		 */
 		if (neigh->ah)
-			list_add_tail(&neigh->ah->list, &ah_list);
+			ipoib_put_ah(neigh->ah);
 		*to_ipoib_neigh(neigh->neighbour) = NULL;
 		neigh->neighbour->ops->destructor = NULL;
 		kfree(neigh);
@@ -116,9 +120,6 @@
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	list_for_each_entry_safe(ah, tah, &ah_list, list)
-		ipoib_put_ah(ah);
-
 	if (mcast->ah)
 		ipoib_put_ah(mcast->ah);
 
@@ -384,10 +385,10 @@
 
 	if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) {
 		mcast->backoff = 1;
-		down(&mcast_mutex);
+		mutex_lock(&mcast_mutex);
 		if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
 			queue_work(ipoib_workqueue, &priv->mcast_task);
-		up(&mcast_mutex);
+		mutex_unlock(&mcast_mutex);
 		complete(&mcast->done);
 		return;
 	}
@@ -417,7 +418,7 @@
 
 	mcast->query = NULL;
 
-	down(&mcast_mutex);
+	mutex_lock(&mcast_mutex);
 	if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
 		if (status == -ETIMEDOUT)
 			queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -426,7 +427,7 @@
 					   mcast->backoff * HZ);
 	} else
 		complete(&mcast->done);
-	up(&mcast_mutex);
+	mutex_unlock(&mcast_mutex);
 
 	return;
 }
@@ -481,12 +482,12 @@
 		if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
 			mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
 
-		down(&mcast_mutex);
+		mutex_lock(&mcast_mutex);
 		if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
 			queue_delayed_work(ipoib_workqueue,
 					   &priv->mcast_task,
 					   mcast->backoff * HZ);
-		up(&mcast_mutex);
+		mutex_unlock(&mcast_mutex);
 	} else
 		mcast->query_id = ret;
 }
@@ -519,11 +520,11 @@
 		priv->broadcast = ipoib_mcast_alloc(dev, 1);
 		if (!priv->broadcast) {
 			ipoib_warn(priv, "failed to allocate broadcast group\n");
-			down(&mcast_mutex);
+			mutex_lock(&mcast_mutex);
 			if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
 				queue_delayed_work(ipoib_workqueue,
 						   &priv->mcast_task, HZ);
-			up(&mcast_mutex);
+			mutex_unlock(&mcast_mutex);
 			return;
 		}
 
@@ -579,10 +580,10 @@
 
 	ipoib_dbg_mcast(priv, "starting multicast thread\n");
 
-	down(&mcast_mutex);
+	mutex_lock(&mcast_mutex);
 	if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags))
 		queue_work(ipoib_workqueue, &priv->mcast_task);
-	up(&mcast_mutex);
+	mutex_unlock(&mcast_mutex);
 
 	return 0;
 }
@@ -594,10 +595,10 @@
 
 	ipoib_dbg_mcast(priv, "stopping multicast thread\n");
 
-	down(&mcast_mutex);
+	mutex_lock(&mcast_mutex);
 	clear_bit(IPOIB_MCAST_RUN, &priv->flags);
 	cancel_delayed_work(&priv->mcast_task);
-	up(&mcast_mutex);
+	mutex_unlock(&mcast_mutex);
 
 	if (flush)
 		flush_workqueue(ipoib_workqueue);
@@ -741,48 +742,23 @@
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	LIST_HEAD(remove_list);
-	struct ipoib_mcast *mcast, *tmcast, *nmcast;
+	struct ipoib_mcast *mcast, *tmcast;
 	unsigned long flags;
 
 	ipoib_dbg_mcast(priv, "flushing multicast list\n");
 
 	spin_lock_irqsave(&priv->lock, flags);
+
 	list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) {
-		nmcast = ipoib_mcast_alloc(dev, 0);
-		if (nmcast) {
-			nmcast->flags =
-				mcast->flags & (1 << IPOIB_MCAST_FLAG_SENDONLY);
-
-			nmcast->mcmember.mgid = mcast->mcmember.mgid;
-
-			/* Add the new group in before the to-be-destroyed group */
-			list_add_tail(&nmcast->list, &mcast->list);
-			list_del_init(&mcast->list);
-
-			rb_replace_node(&mcast->rb_node, &nmcast->rb_node,
-					&priv->multicast_tree);
-
-			list_add_tail(&mcast->list, &remove_list);
-		} else {
-			ipoib_warn(priv, "could not reallocate multicast group "
-				   IPOIB_GID_FMT "\n",
-				   IPOIB_GID_ARG(mcast->mcmember.mgid));
-		}
+		list_del(&mcast->list);
+		rb_erase(&mcast->rb_node, &priv->multicast_tree);
+		list_add_tail(&mcast->list, &remove_list);
 	}
 
 	if (priv->broadcast) {
-		nmcast = ipoib_mcast_alloc(dev, 0);
-		if (nmcast) {
-			nmcast->mcmember.mgid = priv->broadcast->mcmember.mgid;
-
-			rb_replace_node(&priv->broadcast->rb_node,
-					&nmcast->rb_node,
-					&priv->multicast_tree);
-
-			list_add_tail(&priv->broadcast->list, &remove_list);
-		}
-
-		priv->broadcast = nmcast;
+ 		rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
+		list_add_tail(&priv->broadcast->list, &remove_list);
+		priv->broadcast = NULL;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -793,24 +769,6 @@
 	}
 }
 
-void ipoib_mcast_dev_down(struct net_device *dev)
-{
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	/* Delete broadcast since it will be recreated */
-	if (priv->broadcast) {
-		ipoib_dbg_mcast(priv, "deleting broadcast group\n");
-
-		spin_lock_irqsave(&priv->lock, flags);
-		rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
-		spin_unlock_irqrestore(&priv->lock, flags);
-		ipoib_mcast_leave(dev, priv->broadcast);
-		ipoib_mcast_free(priv->broadcast);
-		priv->broadcast = NULL;
-	}
-}
-
 void ipoib_mcast_restart_task(void *dev_ptr)
 {
 	struct net_device *dev = dev_ptr;
@@ -824,7 +782,8 @@
 
 	ipoib_mcast_stop_thread(dev, 0);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&dev->xmit_lock, flags);
+	spin_lock(&priv->lock);
 
 	/*
 	 * Unfortunately, the networking core only gives us a list of all of
@@ -896,7 +855,9 @@
 			list_add_tail(&mcast->list, &remove_list);
 		}
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);
+
+	spin_unlock(&priv->lock);
+	spin_unlock_irqrestore(&dev->xmit_lock, flags);
 
 	/* We have to cancel outside of the spinlock */
 	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index e829e10..faaf10e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -65,9 +65,9 @@
 	}
 
 	/* attach QP to multicast group */
-	down(&priv->mcast_mutex);
+	mutex_lock(&priv->mcast_mutex);
 	ret = ib_attach_mcast(priv->qp, mgid, mlid);
-	up(&priv->mcast_mutex);
+	mutex_unlock(&priv->mcast_mutex);
 	if (ret)
 		ipoib_warn(priv, "failed to attach to multicast group, ret = %d\n", ret);
 
@@ -81,9 +81,9 @@
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	int ret;
 
-	down(&priv->mcast_mutex);
+	mutex_lock(&priv->mcast_mutex);
 	ret = ib_detach_mcast(priv->qp, mgid, mlid);
-	up(&priv->mcast_mutex);
+	mutex_unlock(&priv->mcast_mutex);
 	if (ret)
 		ipoib_warn(priv, "ib_detach_mcast failed (result = %d)\n", ret);
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index d280b34..4ca1755 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -63,7 +63,7 @@
 
 	ppriv = netdev_priv(pdev);
 
-	down(&ppriv->vlan_mutex);
+	mutex_lock(&ppriv->vlan_mutex);
 
 	/*
 	 * First ensure this isn't a duplicate. We check the parent device and
@@ -124,7 +124,7 @@
 
 	list_add_tail(&priv->list, &ppriv->child_intfs);
 
-	up(&ppriv->vlan_mutex);
+	mutex_unlock(&ppriv->vlan_mutex);
 
 	return 0;
 
@@ -139,7 +139,7 @@
 	free_netdev(priv->dev);
 
 err:
-	up(&ppriv->vlan_mutex);
+	mutex_unlock(&ppriv->vlan_mutex);
 	return result;
 }
 
@@ -153,7 +153,7 @@
 
 	ppriv = netdev_priv(pdev);
 
-	down(&ppriv->vlan_mutex);
+	mutex_lock(&ppriv->vlan_mutex);
 	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
 		if (priv->pkey == pkey) {
 			unregister_netdev(priv->dev);
@@ -167,7 +167,7 @@
 			break;
 		}
 	}
-	up(&ppriv->vlan_mutex);
+	mutex_unlock(&ppriv->vlan_mutex);
 
 	return ret;
 }
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index dd488d3..31207e66 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1516,8 +1516,7 @@
 
 static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
 
-static struct srp_host *srp_add_port(struct ib_device *device,
-				     __be64 node_guid, u8 port)
+static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
 {
 	struct srp_host *host;
 
@@ -1532,7 +1531,7 @@
 	host->port = port;
 
 	host->initiator_port_id[7] = port;
-	memcpy(host->initiator_port_id + 8, &node_guid, 8);
+	memcpy(host->initiator_port_id + 8, &device->node_guid, 8);
 
 	host->pd   = ib_alloc_pd(device);
 	if (IS_ERR(host->pd))
@@ -1580,22 +1579,11 @@
 {
 	struct list_head *dev_list;
 	struct srp_host *host;
-	struct ib_device_attr *dev_attr;
 	int s, e, p;
 
-	dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
-	if (!dev_attr)
-		return;
-
-	if (ib_query_device(device, dev_attr)) {
-		printk(KERN_WARNING PFX "Couldn't query node GUID for %s.\n",
-		       device->name);
-		goto out;
-	}
-
 	dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
 	if (!dev_list)
-		goto out;
+		return;
 
 	INIT_LIST_HEAD(dev_list);
 
@@ -1608,15 +1596,12 @@
 	}
 
 	for (p = s; p <= e; ++p) {
-		host = srp_add_port(device, dev_attr->node_guid, p);
+		host = srp_add_port(device, p);
 		if (host)
 			list_add_tail(&host->list, dev_list);
 	}
 
 	ib_set_client_data(device, &srp_client, dev_list);
-
-out:
-	kfree(dev_attr);
 }
 
 static void srp_remove_one(struct ib_device *device)
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index caac6d6..b765a155 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -50,9 +50,7 @@
 
 static LIST_HEAD(gameport_list);
 
-static struct bus_type gameport_bus = {
-	.name =	"gameport",
-};
+static struct bus_type gameport_bus;
 
 static void gameport_add_port(struct gameport *gameport);
 static void gameport_destroy_port(struct gameport *gameport);
@@ -703,11 +701,15 @@
 	return 0;
 }
 
+static struct bus_type gameport_bus = {
+	.name =	"gameport",
+	.probe = gameport_driver_probe,
+	.remove = gameport_driver_remove,
+};
+
 void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
 {
 	drv->driver.bus = &gameport_bus;
-	drv->driver.probe = gameport_driver_probe;
-	drv->driver.remove = gameport_driver_remove;
 	gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
 }
 
diff --git a/drivers/input/input.c b/drivers/input/input.c
index fe33ff3..4fe3da3 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -528,40 +528,56 @@
 INPUT_DEV_STRING_ATTR_SHOW(phys);
 INPUT_DEV_STRING_ATTR_SHOW(uniq);
 
-static int print_modalias_bits(char *buf, char prefix, unsigned long *arr,
+static int print_modalias_bits(char *buf, int size, char prefix, unsigned long *arr,
 			       unsigned int min, unsigned int max)
 {
 	int len, i;
 
-	len = sprintf(buf, "%c", prefix);
+	len = snprintf(buf, size, "%c", prefix);
 	for (i = min; i < max; i++)
 		if (arr[LONG(i)] & BIT(i))
-			len += sprintf(buf+len, "%X,", i);
+			len += snprintf(buf + len, size - len, "%X,", i);
+	return len;
+}
+
+static int print_modalias(char *buf, int size, struct input_dev *id)
+{
+	int len;
+
+	len = snprintf(buf, size, "input:b%04Xv%04Xp%04Xe%04X-",
+		       id->id.bustype,
+		       id->id.vendor,
+		       id->id.product,
+		       id->id.version);
+
+	len += print_modalias_bits(buf + len, size - len, 'e', id->evbit,
+				   0, EV_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'k', id->keybit,
+				   KEY_MIN_INTERESTING, KEY_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'r', id->relbit,
+				   0, REL_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'a', id->absbit,
+				   0, ABS_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'm', id->mscbit,
+				   0, MSC_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'l', id->ledbit,
+				   0, LED_MAX);
+	len += print_modalias_bits(buf + len, size - len, 's', id->sndbit,
+				   0, SND_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'f', id->ffbit,
+				   0, FF_MAX);
+	len += print_modalias_bits(buf + len, size - len, 'w', id->swbit,
+				   0, SW_MAX);
 	return len;
 }
 
 static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
 {
 	struct input_dev *id = to_input_dev(dev);
-	ssize_t len = 0;
+	ssize_t len;
 
-	len += sprintf(buf+len, "input:b%04Xv%04Xp%04Xe%04X-",
-		       id->id.bustype,
-		       id->id.vendor,
-		       id->id.product,
-		       id->id.version);
-
-	len += print_modalias_bits(buf+len, 'e', id->evbit, 0, EV_MAX);
-	len += print_modalias_bits(buf+len, 'k', id->keybit,
-				   KEY_MIN_INTERESTING, KEY_MAX);
-	len += print_modalias_bits(buf+len, 'r', id->relbit, 0, REL_MAX);
-	len += print_modalias_bits(buf+len, 'a', id->absbit, 0, ABS_MAX);
-	len += print_modalias_bits(buf+len, 'm', id->mscbit, 0, MSC_MAX);
-	len += print_modalias_bits(buf+len, 'l', id->ledbit, 0, LED_MAX);
-	len += print_modalias_bits(buf+len, 's', id->sndbit, 0, SND_MAX);
-	len += print_modalias_bits(buf+len, 'f', id->ffbit, 0, FF_MAX);
-	len += print_modalias_bits(buf+len, 'w', id->swbit, 0, SW_MAX);
-	len += sprintf(buf+len, "\n");
+	len = print_modalias(buf, PAGE_SIZE, id);
+	len += snprintf(buf + len, PAGE_SIZE-len, "\n");
 	return len;
 }
 static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
@@ -728,8 +744,11 @@
 	if (test_bit(EV_SW, dev->evbit))
 		INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX);
 
-	envp[i] = NULL;
+	envp[i++] = buffer + len;
+	len += snprintf(buffer + len, buffer_size - len, "MODALIAS=");
+	len += print_modalias(buffer + len, buffer_size - len, dev) + 1;
 
+	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 2447433..2141501 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -348,6 +348,40 @@
 	return 0;
 }
 
+/*
+ * alps_poll() - poll the touchpad for current motion packet.
+ * Used in resync.
+ */
+static int alps_poll(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char buf[6];
+	int poll_failed;
+
+	if (priv->i->flags & ALPS_PASS)
+		alps_passthrough_mode(psmouse, 1);
+
+	poll_failed = ps2_command(&psmouse->ps2dev, buf,
+				  PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
+
+	if (priv->i->flags & ALPS_PASS)
+		alps_passthrough_mode(psmouse, 0);
+
+	if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
+		return -1;
+
+	if ((psmouse->badbyte & 0xc8) == 0x08) {
+/*
+ * Poll the track stick ...
+ */
+		if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8)))
+			return -1;
+	}
+
+	memcpy(psmouse->packet, buf, sizeof(buf));
+	return 0;
+}
+
 static int alps_reconnect(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
@@ -451,10 +485,14 @@
 	input_register_device(priv->dev2);
 
 	psmouse->protocol_handler = alps_process_byte;
+	psmouse->poll = alps_poll;
 	psmouse->disconnect = alps_disconnect;
 	psmouse->reconnect = alps_reconnect;
 	psmouse->pktsize = 6;
 
+	/* We are having trouble resyncing ALPS touchpads so disable it for now */
+	psmouse->resync_time = 0;
+
 	return 0;
 
 init_fail:
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 025a71d..c88520d 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -117,7 +117,7 @@
 	if (psmouse_sliced_command(psmouse, command))
 		return -1;
 
-	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
 		return -1;
 
 	return 0;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 4d5ecc0..7665fd9 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -54,10 +54,14 @@
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
-static unsigned int psmouse_resetafter;
+static unsigned int psmouse_resetafter = 5;
 module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+static unsigned int psmouse_resync_time = 5;
+module_param_named(resync_time, psmouse_resync_time, uint, 0644);
+MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never).");
+
 PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO,
 			NULL,
 			psmouse_attr_show_protocol, psmouse_attr_set_protocol);
@@ -70,12 +74,16 @@
 PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO,
 			(void *) offsetof(struct psmouse, resetafter),
 			psmouse_show_int_attr, psmouse_set_int_attr);
+PSMOUSE_DEFINE_ATTR(resync_time, S_IWUSR | S_IRUGO,
+			(void *) offsetof(struct psmouse, resync_time),
+			psmouse_show_int_attr, psmouse_set_int_attr);
 
 static struct attribute *psmouse_attributes[] = {
 	&psmouse_attr_protocol.dattr.attr,
 	&psmouse_attr_rate.dattr.attr,
 	&psmouse_attr_resolution.dattr.attr,
 	&psmouse_attr_resetafter.dattr.attr,
+	&psmouse_attr_resync_time.dattr.attr,
 	NULL
 };
 
@@ -98,6 +106,8 @@
  */
 static DECLARE_MUTEX(psmouse_sem);
 
+static struct workqueue_struct *kpsmoused_wq;
+
 struct psmouse_protocol {
 	enum psmouse_type type;
 	char *name;
@@ -178,15 +188,79 @@
 }
 
 /*
- * psmouse_interrupt() handles incoming characters, either gathering them into
- * packets or passing them to the command routine as command output.
+ * __psmouse_set_state() sets new psmouse state and resets all flags.
+ */
+
+static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+{
+	psmouse->state = new_state;
+	psmouse->pktcnt = psmouse->out_of_sync = 0;
+	psmouse->ps2dev.flags = 0;
+	psmouse->last = jiffies;
+}
+
+
+/*
+ * psmouse_set_state() sets new psmouse state and resets all flags and
+ * counters while holding serio lock so fighting with interrupt handler
+ * is not a concern.
+ */
+
+static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+{
+	serio_pause_rx(psmouse->ps2dev.serio);
+	__psmouse_set_state(psmouse, new_state);
+	serio_continue_rx(psmouse->ps2dev.serio);
+}
+
+/*
+ * psmouse_handle_byte() processes one byte of the input data stream
+ * by calling corresponding protocol handler.
+ */
+
+static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs);
+
+	switch (rc) {
+		case PSMOUSE_BAD_DATA:
+			if (psmouse->state == PSMOUSE_ACTIVATED) {
+				printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
+					psmouse->name, psmouse->phys, psmouse->pktcnt);
+				if (++psmouse->out_of_sync == psmouse->resetafter) {
+					__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+					printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
+					serio_reconnect(psmouse->ps2dev.serio);
+					return -1;
+				}
+			}
+			psmouse->pktcnt = 0;
+			break;
+
+		case PSMOUSE_FULL_PACKET:
+			psmouse->pktcnt = 0;
+			if (psmouse->out_of_sync) {
+				psmouse->out_of_sync = 0;
+				printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
+					psmouse->name, psmouse->phys);
+			}
+			break;
+
+		case PSMOUSE_GOOD_DATA:
+			break;
+	}
+	return 0;
+}
+
+/*
+ * psmouse_interrupt() handles incoming characters, either passing them
+ * for normal processing or gathering them as command response.
  */
 
 static irqreturn_t psmouse_interrupt(struct serio *serio,
 		unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
 	struct psmouse *psmouse = serio_get_drvdata(serio);
-	psmouse_ret_t rc;
 
 	if (psmouse->state == PSMOUSE_IGNORE)
 		goto out;
@@ -208,67 +282,58 @@
 		if  (ps2_handle_response(&psmouse->ps2dev, data))
 			goto out;
 
-	if (psmouse->state == PSMOUSE_INITIALIZING)
+	if (psmouse->state <= PSMOUSE_RESYNCING)
 		goto out;
 
 	if (psmouse->state == PSMOUSE_ACTIVATED &&
 	    psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
-		printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
+		printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
 		       psmouse->name, psmouse->phys, psmouse->pktcnt);
-		psmouse->pktcnt = 0;
+		psmouse->badbyte = psmouse->packet[0];
+		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+		queue_work(kpsmoused_wq, &psmouse->resync_work);
+		goto out;
 	}
 
-	psmouse->last = jiffies;
 	psmouse->packet[psmouse->pktcnt++] = data;
-
-	if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
+/*
+ * Check if this is a new device announcement (0xAA 0x00)
+ */
+	if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
 		if (psmouse->pktcnt == 1)
 			goto out;
 
-		if (psmouse->pktcnt == 2) {
-			if (psmouse->packet[1] == PSMOUSE_RET_ID) {
-				psmouse->state = PSMOUSE_IGNORE;
-				serio_reconnect(serio);
-				goto out;
-			}
-			if (psmouse->type == PSMOUSE_SYNAPTICS) {
-				/* neither 0xAA nor 0x00 are valid first bytes
-				 * for a packet in absolute mode
-				 */
-				psmouse->pktcnt = 0;
-				goto out;
-			}
+		if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+			__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+			serio_reconnect(serio);
+			goto out;
 		}
+/*
+ * Not a new device, try processing first byte normally
+ */
+		psmouse->pktcnt = 1;
+		if (psmouse_handle_byte(psmouse, regs))
+			goto out;
+
+		psmouse->packet[psmouse->pktcnt++] = data;
 	}
 
-	rc = psmouse->protocol_handler(psmouse, regs);
-
-	switch (rc) {
-		case PSMOUSE_BAD_DATA:
-			printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
-				psmouse->name, psmouse->phys, psmouse->pktcnt);
-			psmouse->pktcnt = 0;
-
-			if (++psmouse->out_of_sync == psmouse->resetafter) {
-				psmouse->state = PSMOUSE_IGNORE;
-				printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
-				serio_reconnect(psmouse->ps2dev.serio);
-			}
-			break;
-
-		case PSMOUSE_FULL_PACKET:
-			psmouse->pktcnt = 0;
-			if (psmouse->out_of_sync) {
-				psmouse->out_of_sync = 0;
-				printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
-					psmouse->name, psmouse->phys);
-			}
-			break;
-
-		case PSMOUSE_GOOD_DATA:
-			break;
+/*
+ * See if we need to force resync because mouse was idle for too long
+ */
+	if (psmouse->state == PSMOUSE_ACTIVATED &&
+	    psmouse->pktcnt == 1 && psmouse->resync_time &&
+	    time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
+		psmouse->badbyte = psmouse->packet[0];
+		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+		queue_work(kpsmoused_wq, &psmouse->resync_work);
+		goto out;
 	}
-out:
+
+	psmouse->last = jiffies;
+	psmouse_handle_byte(psmouse, regs);
+
+ out:
 	return IRQ_HANDLED;
 }
 
@@ -752,21 +817,6 @@
 }
 
 /*
- * psmouse_set_state() sets new psmouse state and resets all flags and
- * counters while holding serio lock so fighting with interrupt handler
- * is not a concern.
- */
-
-static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
-{
-	serio_pause_rx(psmouse->ps2dev.serio);
-	psmouse->state = new_state;
-	psmouse->pktcnt = psmouse->out_of_sync = 0;
-	psmouse->ps2dev.flags = 0;
-	serio_continue_rx(psmouse->ps2dev.serio);
-}
-
-/*
  * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
 
@@ -794,6 +844,111 @@
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 }
 
+/*
+ * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
+ */
+
+static int psmouse_poll(struct psmouse *psmouse)
+{
+	return ps2_command(&psmouse->ps2dev, psmouse->packet,
+			   PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
+}
+
+
+/*
+ * psmouse_resync() attempts to re-validate current protocol.
+ */
+
+static void psmouse_resync(void *p)
+{
+	struct psmouse *psmouse = p, *parent = NULL;
+	struct serio *serio = psmouse->ps2dev.serio;
+	psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
+	int failed = 0, enabled = 0;
+	int i;
+
+	down(&psmouse_sem);
+
+	if (psmouse->state != PSMOUSE_RESYNCING)
+		goto out;
+
+	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+		parent = serio_get_drvdata(serio->parent);
+		psmouse_deactivate(parent);
+	}
+
+/*
+ * Some mice don't ACK commands sent while they are in the middle of
+ * transmitting motion packet. To avoid delay we use ps2_sendbyte()
+ * instead of ps2_command() which would wait for 200ms for an ACK
+ * that may never come.
+ * As an additional quirk ALPS touchpads may not only forget to ACK
+ * disable command but will stop reporting taps, so if we see that
+ * mouse at least once ACKs disable we will do full reconnect if ACK
+ * is missing.
+ */
+	psmouse->num_resyncs++;
+
+	if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
+		if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
+			failed = 1;
+	} else
+		psmouse->acks_disable_command = 1;
+
+/*
+ * Poll the mouse. If it was reset the packet will be shorter than
+ * psmouse->pktsize and ps2_command will fail. We do not expect and
+ * do not handle scenario when mouse "upgrades" its protocol while
+ * disconnected since it would require additional delay. If we ever
+ * see a mouse that does it we'll adjust the code.
+ */
+	if (!failed) {
+		if (psmouse->poll(psmouse))
+			failed = 1;
+		else {
+			psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+			for (i = 0; i < psmouse->pktsize; i++) {
+				psmouse->pktcnt++;
+				rc = psmouse->protocol_handler(psmouse, NULL);
+				if (rc != PSMOUSE_GOOD_DATA)
+					break;
+			}
+			if (rc != PSMOUSE_FULL_PACKET)
+				failed = 1;
+			psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+		}
+	}
+/*
+ * Now try to enable mouse. We try to do that even if poll failed and also
+ * repeat our attempts 5 times, otherwise we may be left out with disabled
+ * mouse.
+ */
+	for (i = 0; i < 5; i++) {
+		if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
+			enabled = 1;
+			break;
+		}
+		msleep(200);
+	}
+
+	if (!enabled) {
+		printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
+			psmouse->ps2dev.serio->phys);
+		failed = 1;
+	}
+
+	if (failed) {
+		psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+		printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
+		serio_reconnect(serio);
+	} else
+		psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+
+	if (parent)
+		psmouse_activate(parent);
+ out:
+	up(&psmouse_sem);
+}
 
 /*
  * psmouse_cleanup() resets the mouse into power-on state.
@@ -822,6 +977,11 @@
 
 	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
+	/* make sure we don't have a resync in progress */
+	up(&psmouse_sem);
+	flush_workqueue(kpsmoused_wq);
+	down(&psmouse_sem);
+
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 		parent = serio_get_drvdata(serio->parent);
 		psmouse_deactivate(parent);
@@ -859,6 +1019,7 @@
 
 	psmouse->set_rate = psmouse_set_rate;
 	psmouse->set_resolution = psmouse_set_resolution;
+	psmouse->poll = psmouse_poll;
 	psmouse->protocol_handler = psmouse_process_byte;
 	psmouse->pktsize = 3;
 
@@ -874,6 +1035,23 @@
 	else
 		psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 
+	/*
+	 * If mouse's packet size is 3 there is no point in polling the
+	 * device in hopes to detect protocol reset - we won't get less
+	 * than 3 bytes response anyhow.
+	 */
+	if (psmouse->pktsize == 3)
+		psmouse->resync_time = 0;
+
+	/*
+	 * Some smart KVMs fake response to POLL command returning just
+	 * 3 bytes and messing up our resync logic, so if initial poll
+	 * fails we won't try polling the device anymore. Hopefully
+	 * such KVM will maintain initially selected protocol.
+	 */
+	if (psmouse->resync_time && psmouse->poll(psmouse))
+		psmouse->resync_time = 0;
+
 	sprintf(psmouse->devname, "%s %s %s",
 		psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
 
@@ -914,6 +1092,7 @@
 		goto out;
 
 	ps2_init(&psmouse->ps2dev, serio);
+	INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);
 	psmouse->dev = input_dev;
 	sprintf(psmouse->phys, "%s/input0", serio->phys);
 
@@ -934,6 +1113,7 @@
 	psmouse->rate = psmouse_rate;
 	psmouse->resolution = psmouse_resolution;
 	psmouse->resetafter = psmouse_resetafter;
+	psmouse->resync_time = parent ? 0 : psmouse_resync_time;
 	psmouse->smartscroll = psmouse_smartscroll;
 
 	psmouse_switch_protocol(psmouse, NULL);
@@ -1278,13 +1458,21 @@
 
 static int __init psmouse_init(void)
 {
+	kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
+	if (!kpsmoused_wq) {
+		printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
+		return -ENOMEM;
+	}
+
 	serio_register_driver(&psmouse_drv);
+
 	return 0;
 }
 
 static void __exit psmouse_exit(void)
 {
 	serio_unregister_driver(&psmouse_drv);
+	destroy_workqueue(kpsmoused_wq);
 }
 
 module_init(psmouse_init);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 7c4192b..4d9107f 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -7,7 +7,7 @@
 #define PSMOUSE_CMD_GETINFO	0x03e9
 #define PSMOUSE_CMD_SETSTREAM	0x00ea
 #define PSMOUSE_CMD_SETPOLL	0x00f0
-#define PSMOUSE_CMD_POLL	0x03eb
+#define PSMOUSE_CMD_POLL	0x00eb	/* caller sets number of bytes to receive */
 #define PSMOUSE_CMD_GETID	0x02f2
 #define PSMOUSE_CMD_SETRATE	0x10f3
 #define PSMOUSE_CMD_ENABLE	0x00f4
@@ -23,6 +23,7 @@
 enum psmouse_state {
 	PSMOUSE_IGNORE,
 	PSMOUSE_INITIALIZING,
+	PSMOUSE_RESYNCING,
 	PSMOUSE_CMD_MODE,
 	PSMOUSE_ACTIVATED,
 };
@@ -38,15 +39,19 @@
 	void *private;
 	struct input_dev *dev;
 	struct ps2dev ps2dev;
+	struct work_struct resync_work;
 	char *vendor;
 	char *name;
 	unsigned char packet[8];
+	unsigned char badbyte;
 	unsigned char pktcnt;
 	unsigned char pktsize;
 	unsigned char type;
+	unsigned char acks_disable_command;
 	unsigned int model;
 	unsigned long last;
 	unsigned long out_of_sync;
+	unsigned long num_resyncs;
 	enum psmouse_state state;
 	char devname[64];
 	char phys[32];
@@ -54,6 +59,7 @@
 	unsigned int rate;
 	unsigned int resolution;
 	unsigned int resetafter;
+	unsigned int resync_time;
 	unsigned int smartscroll;	/* Logitech only */
 
 	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
@@ -62,6 +68,7 @@
 
 	int (*reconnect)(struct psmouse *psmouse);
 	void (*disconnect)(struct psmouse *psmouse);
+	int (*poll)(struct psmouse *psmouse);
 
 	void (*pt_activate)(struct psmouse *psmouse);
 	void (*pt_deactivate)(struct psmouse *psmouse);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 97cdfd6..2051bec 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -652,6 +652,8 @@
 	psmouse->disconnect = synaptics_disconnect;
 	psmouse->reconnect = synaptics_reconnect;
 	psmouse->pktsize = 6;
+	/* Synaptics can usually stay in sync without extra help */
+	psmouse->resync_time = 0;
 
 	if (SYN_CAP_PASS_THROUGH(priv->capabilities))
 		synaptics_pt_create(psmouse);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 2d2f9fb..a4c6f35 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -173,6 +173,13 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
 		},
 	},
+	{
+		.ident = "Sony Vaio FS-115b",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
+		},
+	},
 	{ }
 };
 
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 8e530cc..2f76813 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -59,9 +59,7 @@
 
 static LIST_HEAD(serio_list);
 
-static struct bus_type serio_bus = {
-	.name =	"serio",
-};
+static struct bus_type serio_bus;
 
 static void serio_add_port(struct serio *serio);
 static void serio_destroy_port(struct serio *serio);
@@ -750,11 +748,15 @@
 	return 0;
 }
 
+static struct bus_type serio_bus = {
+	.name =	"serio",
+	.probe = serio_driver_probe,
+	.remove = serio_driver_remove,
+};
+
 void __serio_register_driver(struct serio_driver *drv, struct module *owner)
 {
 	drv->driver.bus = &serio_bus;
-	drv->driver.probe = serio_driver_probe;
-	drv->driver.remove = serio_driver_remove;
 
 	serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
 }
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 21d55ed..2c67402 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -11,6 +11,19 @@
 
 if INPUT_TOUCHSCREEN
 
+config TOUCHSCREEN_ADS7846
+	tristate "ADS 7846 based touchscreens"
+	depends on SPI_MASTER
+	help
+	  Say Y here if you have a touchscreen interface using the
+	  ADS7846 controller, and your board-specific initialization
+	  code includes that in its table of SPI devices.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ads7846.
+
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
 	depends on SA1100_BITSY
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6842869..5e5557c 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -4,6 +4,7 @@
 
 # Each configuration option enables a list of files.
 
+obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)	+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_CORGI)	+= corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
new file mode 100644
index 0000000..dd8c6a9
--- /dev/null
+++ b/drivers/input/touchscreen/ads7846.c
@@ -0,0 +1,625 @@
+/*
+ * ADS7846 based touchscreen and sensor driver
+ *
+ * Copyright (c) 2005 David Brownell
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ *
+ *  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/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#ifdef	CONFIG_ARM
+#include <asm/mach-types.h>
+#ifdef	CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#else
+#define	set_irq_type(irq,type)	do{}while(0)
+#endif
+
+
+/*
+ * This code has been lightly tested on an ads7846.
+ * Support for ads7843 and ads7845 has only been stubbed in.
+ *
+ * Not yet done:  investigate the values reported.  Are x/y/pressure
+ * event values sane enough for X11?  How accurate are the temperature
+ * and voltage readings?  (System-specific calibration should support
+ * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.)
+ *
+ * app note sbaa036 talks in more detail about accurate sampling...
+ * that ought to help in situations like LCDs inducing noise (which
+ * can also be helped by using synch signals) and more generally.
+ */
+
+#define	TS_POLL_PERIOD	msecs_to_jiffies(10)
+
+struct ts_event {
+	/* For portability, we can't read 12 bit values using SPI (which
+	 * would make the controller deliver them as native byteorder u16
+	 * with msbs zeroed).  Instead, we read them as two 8-byte values,
+	 * which need byteswapping then range adjustment.
+	 */
+	__be16 x;
+	__be16 y;
+	__be16 z1, z2;
+};
+
+struct ads7846 {
+	struct input_dev	input;
+	char			phys[32];
+
+	struct spi_device	*spi;
+	u16			model;
+	u16			vref_delay_usecs;
+	u16			x_plate_ohms;
+
+	struct ts_event		tc;
+
+	struct spi_transfer	xfer[8];
+	struct spi_message	msg;
+
+	spinlock_t		lock;
+	struct timer_list	timer;		/* P: lock */
+	unsigned		pendown:1;	/* P: lock */
+	unsigned		pending:1;	/* P: lock */
+// FIXME remove "irq_disabled"
+	unsigned		irq_disabled:1;	/* P: lock */
+};
+
+/* leave chip selected when we're done, for quicker re-select? */
+#if	0
+#define	CS_CHANGE(xfer)	((xfer).cs_change = 1)
+#else
+#define	CS_CHANGE(xfer)	((xfer).cs_change = 0)
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/* The ADS7846 has touchscreen and other sensors.
+ * Earlier ads784x chips are somewhat compatible.
+ */
+#define	ADS_START		(1 << 7)
+#define	ADS_A2A1A0_d_y		(1 << 4)	/* differential */
+#define	ADS_A2A1A0_d_z1		(3 << 4)	/* differential */
+#define	ADS_A2A1A0_d_z2		(4 << 4)	/* differential */
+#define	ADS_A2A1A0_d_x		(5 << 4)	/* differential */
+#define	ADS_A2A1A0_temp0	(0 << 4)	/* non-differential */
+#define	ADS_A2A1A0_vbatt	(2 << 4)	/* non-differential */
+#define	ADS_A2A1A0_vaux		(6 << 4)	/* non-differential */
+#define	ADS_A2A1A0_temp1	(7 << 4)	/* non-differential */
+#define	ADS_8_BIT		(1 << 3)
+#define	ADS_12_BIT		(0 << 3)
+#define	ADS_SER			(1 << 2)	/* non-differential */
+#define	ADS_DFR			(0 << 2)	/* differential */
+#define	ADS_PD10_PDOWN		(0 << 0)	/* lowpower mode + penirq */
+#define	ADS_PD10_ADC_ON		(1 << 0)	/* ADC on */
+#define	ADS_PD10_REF_ON		(2 << 0)	/* vREF on + penirq */
+#define	ADS_PD10_ALL_ON		(3 << 0)	/* ADC + vREF on */
+
+#define	MAX_12BIT	((1<<12)-1)
+
+/* leave ADC powered up (disables penirq) between differential samples */
+#define	READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
+	| ADS_12_BIT | ADS_DFR)
+
+static const u8	read_y  = READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON;
+static const u8	read_z1 = READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON;
+static const u8	read_z2 = READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON;
+static const u8	read_x  = READ_12BIT_DFR(x)  | ADS_PD10_PDOWN;	/* LAST */
+
+/* single-ended samples need to first power up reference voltage;
+ * we leave both ADC and VREF powered
+ */
+#define	READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
+	| ADS_12_BIT | ADS_SER)
+
+static const u8	ref_on = READ_12BIT_DFR(x) | ADS_PD10_ALL_ON;
+static const u8	ref_off = READ_12BIT_DFR(y) | ADS_PD10_PDOWN;
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Non-touchscreen sensors only use single-ended conversions.
+ */
+
+struct ser_req {
+	u8			command;
+	u16			scratch;
+	__be16			sample;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[6];
+};
+
+static int ads7846_read12_ser(struct device *dev, unsigned command)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct ads7846		*ts = dev_get_drvdata(dev);
+	struct ser_req		*req = kzalloc(sizeof *req, SLAB_KERNEL);
+	int			status;
+	int			sample;
+	int 			i;
+
+	if (!req)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&req->msg.transfers);
+
+	/* activate reference, so it has time to settle; */
+	req->xfer[0].tx_buf = &ref_on;
+	req->xfer[0].len = 1;
+	req->xfer[1].rx_buf = &req->scratch;
+	req->xfer[1].len = 2;
+
+	/*
+	 * for external VREF, 0 usec (and assume it's always on);
+	 * for 1uF, use 800 usec;
+	 * no cap, 100 usec.
+	 */
+	req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+
+	/* take sample */
+	req->command = (u8) command;
+	req->xfer[2].tx_buf = &req->command;
+	req->xfer[2].len = 1;
+	req->xfer[3].rx_buf = &req->sample;
+	req->xfer[3].len = 2;
+
+	/* REVISIT:  take a few more samples, and compare ... */
+
+	/* turn off reference */
+	req->xfer[4].tx_buf = &ref_off;
+	req->xfer[4].len = 1;
+	req->xfer[5].rx_buf = &req->scratch;
+	req->xfer[5].len = 2;
+
+	CS_CHANGE(req->xfer[5]);
+
+	/* group all the transfers together, so we can't interfere with
+	 * reading touchscreen state; disable penirq while sampling
+	 */
+	for (i = 0; i < 6; i++)
+		spi_message_add_tail(&req->xfer[i], &req->msg);
+
+	disable_irq(spi->irq);
+	status = spi_sync(spi, &req->msg);
+	enable_irq(spi->irq);
+
+	if (req->msg.status)
+		status = req->msg.status;
+	sample = be16_to_cpu(req->sample);
+	sample = sample >> 4;
+	kfree(req);
+
+	return status ? status : sample;
+}
+
+#define SHOW(name) static ssize_t \
+name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+	ssize_t v = ads7846_read12_ser(dev, \
+			READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+	if (v < 0) \
+		return v; \
+	return sprintf(buf, "%u\n", (unsigned) v); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
+
+SHOW(temp0)
+SHOW(temp1)
+SHOW(vaux)
+SHOW(vbatt)
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
+ * to retrieve touchscreen status.
+ *
+ * The SPI transfer completion callback does the real work.  It reports
+ * touchscreen events and reactivates the timer (or IRQ) as appropriate.
+ */
+
+static void ads7846_rx(void *ads)
+{
+	struct ads7846	*ts = ads;
+	unsigned	Rt;
+	unsigned	sync = 0;
+	u16		x, y, z1, z2;
+	unsigned long	flags;
+
+	/* adjust:  12 bit samples (left aligned), built from
+	 * two 8 bit values writen msb-first.
+	 */
+	x = be16_to_cpu(ts->tc.x) >> 4;
+	y = be16_to_cpu(ts->tc.y) >> 4;
+	z1 = be16_to_cpu(ts->tc.z1) >> 4;
+	z2 = be16_to_cpu(ts->tc.z2) >> 4;
+
+	/* range filtering */
+	if (x == MAX_12BIT)
+		x = 0;
+
+	if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
+		/* compute touch pressure resistance using equation #2 */
+		Rt = z2;
+		Rt -= z1;
+		Rt *= x;
+		Rt *= ts->x_plate_ohms;
+		Rt /= z1;
+		Rt = (Rt + 2047) >> 12;
+	} else
+		Rt = 0;
+
+	/* NOTE:  "pendown" is inferred from pressure; we don't rely on
+	 * being able to check nPENIRQ status, or "friendly" trigger modes
+	 * (both-edges is much better than just-falling or low-level).
+	 *
+	 * REVISIT:  some boards may require reading nPENIRQ; it's
+	 * needed on 7843.  and 7845 reads pressure differently...
+	 *
+	 * REVISIT:  the touchscreen might not be connected; this code
+	 * won't notice that, even if nPENIRQ never fires ...
+	 */
+	if (!ts->pendown && Rt != 0) {
+		input_report_key(&ts->input, BTN_TOUCH, 1);
+		sync = 1;
+	} else if (ts->pendown && Rt == 0) {
+		input_report_key(&ts->input, BTN_TOUCH, 0);
+		sync = 1;
+	}
+
+	if (Rt) {
+		input_report_abs(&ts->input, ABS_X, x);
+		input_report_abs(&ts->input, ABS_Y, y);
+		input_report_abs(&ts->input, ABS_PRESSURE, Rt);
+		sync = 1;
+	}
+	if (sync)
+		input_sync(&ts->input);
+
+#ifdef	VERBOSE
+	if (Rt || ts->pendown)
+		pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
+			x, y, Rt, Rt ? "" : " UP");
+#endif
+
+	/* don't retrigger while we're suspended */
+	spin_lock_irqsave(&ts->lock, flags);
+
+	ts->pendown = (Rt != 0);
+	ts->pending = 0;
+
+	if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
+		if (ts->pendown)
+			mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+		else if (ts->irq_disabled) {
+			ts->irq_disabled = 0;
+			enable_irq(ts->spi->irq);
+		}
+	}
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void ads7846_timer(unsigned long handle)
+{
+	struct ads7846	*ts = (void *)handle;
+	int		status = 0;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	if (!ts->pending) {
+		ts->pending = 1;
+		if (!ts->irq_disabled) {
+			ts->irq_disabled = 1;
+			disable_irq(ts->spi->irq);
+		}
+		status = spi_async(ts->spi, &ts->msg);
+		if (status)
+			dev_err(&ts->spi->dev, "spi_async --> %d\n",
+					status);
+	}
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+{
+	ads7846_timer((unsigned long) handle);
+	return IRQ_HANDLED;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int
+ads7846_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+
+	spi->dev.power.power_state = message;
+
+	/* are we waiting for IRQ, or polling? */
+	if (!ts->pendown) {
+		if (!ts->irq_disabled) {
+			ts->irq_disabled = 1;
+			disable_irq(ts->spi->irq);
+		}
+	} else {
+		/* polling; force a final SPI completion;
+		 * that will clean things up neatly
+		 */
+		if (!ts->pending)
+			mod_timer(&ts->timer, jiffies);
+
+		while (ts->pendown || ts->pending) {
+			spin_unlock_irqrestore(&ts->lock, flags);
+			udelay(10);
+			spin_lock_irqsave(&ts->lock, flags);
+		}
+	}
+
+	/* we know the chip's in lowpower mode since we always
+	 * leave it that way after every request
+	 */
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+	return 0;
+}
+
+static int ads7846_resume(struct spi_device *spi)
+{
+	struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+
+	ts->irq_disabled = 0;
+	enable_irq(ts->spi->irq);
+	spi->dev.power.power_state = PMSG_ON;
+	return 0;
+}
+
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+	struct ads7846			*ts;
+	struct ads7846_platform_data	*pdata = spi->dev.platform_data;
+	struct spi_transfer		*x;
+	int				i;
+
+	if (!spi->irq) {
+		dev_dbg(&spi->dev, "no IRQ?\n");
+		return -ENODEV;
+	}
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	/* don't exceed max specified sample rate */
+	if (spi->max_speed_hz > (125000 * 16)) {
+		dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+				(spi->max_speed_hz/16)/1000);
+		return -EINVAL;
+	}
+
+	/* We'd set the wordsize to 12 bits ... except that some controllers
+	 * will then treat the 8 bit command words as 12 bits (and drop the
+	 * four MSBs of the 12 bit result).  Result: inputs must be shifted
+	 * to discard the four garbage LSBs.
+	 */
+
+	if (!(ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL)))
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, ts);
+
+	ts->spi = spi;
+	spi->dev.power.power_state = PMSG_ON;
+
+	init_timer(&ts->timer);
+	ts->timer.data = (unsigned long) ts;
+	ts->timer.function = ads7846_timer;
+
+	ts->model = pdata->model ? : 7846;
+	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+
+	init_input_dev(&ts->input);
+
+	ts->input.dev = &spi->dev;
+	ts->input.name = "ADS784x Touchscreen";
+	snprintf(ts->phys, sizeof ts->phys, "%s/input0", spi->dev.bus_id);
+	ts->input.phys = ts->phys;
+
+	ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_set_abs_params(&ts->input, ABS_X,
+			pdata->x_min ? : 0,
+			pdata->x_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(&ts->input, ABS_Y,
+			pdata->y_min ? : 0,
+			pdata->y_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(&ts->input, ABS_PRESSURE,
+			pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+	input_register_device(&ts->input);
+
+	/* set up the transfers to read touchscreen state; this assumes we
+	 * use formula #2 for pressure, not #3.
+	 */
+	x = ts->xfer;
+
+	/* y- still on; turn on only y+ (and ADC) */
+	x->tx_buf = &read_y;
+	x->len = 1;
+	x++;
+	x->rx_buf = &ts->tc.y;
+	x->len = 2;
+	x++;
+
+	/* turn y+ off, x- on; we'll use formula #2 */
+	if (ts->model == 7846) {
+		x->tx_buf = &read_z1;
+		x->len = 1;
+		x++;
+		x->rx_buf = &ts->tc.z1;
+		x->len = 2;
+		x++;
+
+		x->tx_buf = &read_z2;
+		x->len = 1;
+		x++;
+		x->rx_buf = &ts->tc.z2;
+		x->len = 2;
+		x++;
+	}
+
+	/* turn y- off, x+ on, then leave in lowpower */
+	x->tx_buf = &read_x;
+	x->len = 1;
+	x++;
+	x->rx_buf = &ts->tc.x;
+	x->len = 2;
+	x++;
+
+	CS_CHANGE(x[-1]);
+
+	for (i = 0; i < x - ts->xfer; i++)
+		spi_message_add_tail(&ts->xfer[i], &ts->msg);
+	ts->msg.complete = ads7846_rx;
+	ts->msg.context = ts;
+
+	if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM,
+				spi->dev.bus_id, ts)) {
+		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+		input_unregister_device(&ts->input);
+		kfree(ts);
+		return -EBUSY;
+	}
+	set_irq_type(spi->irq, IRQT_FALLING);
+
+	dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
+
+	/* take a first sample, leaving nPENIRQ active; avoid
+	 * the touchscreen, in case it's not connected.
+	 */
+	(void) ads7846_read12_ser(&spi->dev,
+			  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+
+	/* ads7843/7845 don't have temperature sensors, and
+	 * use the other sensors a bit differently too
+	 */
+	if (ts->model == 7846) {
+		device_create_file(&spi->dev, &dev_attr_temp0);
+		device_create_file(&spi->dev, &dev_attr_temp1);
+	}
+	if (ts->model != 7845)
+		device_create_file(&spi->dev, &dev_attr_vbatt);
+	device_create_file(&spi->dev, &dev_attr_vaux);
+
+	return 0;
+}
+
+static int __devexit ads7846_remove(struct spi_device *spi)
+{
+	struct ads7846		*ts = dev_get_drvdata(&spi->dev);
+
+	ads7846_suspend(spi, PMSG_SUSPEND);
+	free_irq(ts->spi->irq, ts);
+	if (ts->irq_disabled)
+		enable_irq(ts->spi->irq);
+
+	if (ts->model == 7846) {
+		device_remove_file(&spi->dev, &dev_attr_temp0);
+		device_remove_file(&spi->dev, &dev_attr_temp1);
+	}
+	if (ts->model != 7845)
+		device_remove_file(&spi->dev, &dev_attr_vbatt);
+	device_remove_file(&spi->dev, &dev_attr_vaux);
+
+	input_unregister_device(&ts->input);
+	kfree(ts);
+
+	dev_dbg(&spi->dev, "unregistered touchscreen\n");
+	return 0;
+}
+
+static struct spi_driver ads7846_driver = {
+	.driver = {
+		.name	= "ads7846",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ads7846_probe,
+	.remove		= __devexit_p(ads7846_remove),
+	.suspend	= ads7846_suspend,
+	.resume		= ads7846_resume,
+};
+
+static int __init ads7846_init(void)
+{
+	/* grr, board-specific init should stay out of drivers!! */
+
+#ifdef	CONFIG_ARCH_OMAP
+	if (machine_is_omap_osk()) {
+		/* GPIO4 = PENIRQ; GPIO6 = BUSY */
+		omap_request_gpio(4);
+		omap_set_gpio_direction(4, 1);
+		omap_request_gpio(6);
+		omap_set_gpio_direction(6, 1);
+	}
+	// also TI 1510 Innovator, bitbanging through FPGA
+	// also Nokia 770
+	// also Palm Tungsten T2
+#endif
+
+	// PXA:
+	// also Dell Axim X50
+	// also HP iPaq H191x/H192x/H415x/H435x
+	// also Intel Lubbock (additional to UCB1400; as temperature sensor)
+	// also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)
+
+	// Atmel at91sam9261-EK uses ads7843
+
+	// also various AMD Au1x00 devel boards
+
+	return spi_register_driver(&ads7846_driver);
+}
+module_init(ads7846_init);
+
+static void __exit ads7846_exit(void)
+{
+	spi_unregister_driver(&ads7846_driver);
+
+#ifdef	CONFIG_ARCH_OMAP
+	if (machine_is_omap_osk()) {
+		omap_free_gpio(4);
+		omap_free_gpio(6);
+	}
+#endif
+
+}
+module_exit(ads7846_exit);
+
+MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 5d8ee73..4abe5ff 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -358,7 +358,7 @@
 	}
 }
 
-static inline void
+static void
 HDLC_irq(struct BCState *bcs, u_int stat) {
 	int len;
 	struct sk_buff *skb;
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index b62d6b3..b0ff1cc 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -476,7 +476,7 @@
 	}
 }
 
-static inline void
+static void
 Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
 	u_char r;
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
index 5fe9d42..7b1ad5e 100644
--- a/drivers/isdn/hisax/hscx_irq.c
+++ b/drivers/isdn/hisax/hscx_irq.c
@@ -119,7 +119,7 @@
 	}
 }
 
-static inline void
+static void
 hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
 	u_char r;
@@ -221,7 +221,7 @@
 	}
 }
 
-static inline void
+static void
 hscx_int_main(struct IsdnCardState *cs, u_char val)
 {
 
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
index 0856340..1f201af 100644
--- a/drivers/isdn/hisax/jade_irq.c
+++ b/drivers/isdn/hisax/jade_irq.c
@@ -110,7 +110,7 @@
 }
 
 
-static inline void
+static void
 jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
 {
 	u_char r;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index cf6a6f2..314fc08 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -17,6 +17,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 
 struct preg {
 	unsigned char r;
@@ -88,24 +89,26 @@
 int macio_init(void)
 {
 	struct device_node *adbs;
+	struct resource r;
 
 	adbs = find_compatible_devices("adb", "chrp,adb0");
 	if (adbs == 0)
 		return -ENXIO;
 
 #if 0
-	{ int i;
+	{ int i = 0;
 
 	printk("macio_adb_init: node = %p, addrs =", adbs->node);
-	for (i = 0; i < adbs->n_addrs; ++i)
-		printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size);
+	while(!of_address_to_resource(adbs, i, &r))
+		printk(" %x(%x)", r.start, r.end - r.start);
 	printk(", intrs =");
 	for (i = 0; i < adbs->n_intrs; ++i)
 		printk(" %x", adbs->intrs[i].line);
 	printk("\n"); }
 #endif
-	
-	adb = ioremap(adbs->addrs->address, sizeof(struct adb_regs));
+	if (of_address_to_resource(adbs, 0, &r))
+		return -ENXIO;
+	adb = ioremap(r.start, sizeof(struct adb_regs));
 
 	out_8(&adb->ctrl.r, 0);
 	out_8(&adb->intr.r, 0);
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 2a545ce..ed6d317 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -211,6 +211,9 @@
        .name	= "macio",
        .match	= macio_bus_match,
        .uevent = macio_uevent,
+       .probe	= macio_device_probe,
+       .remove	= macio_device_remove,
+       .shutdown = macio_device_shutdown,
        .suspend	= macio_device_suspend,
        .resume	= macio_device_resume,
        .dev_attrs = macio_dev_attrs,
@@ -528,9 +531,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &macio_bus_type;
-	drv->driver.probe = macio_device_probe;
-	drv->driver.remove = macio_device_remove;
-	drv->driver.shutdown = macio_device_shutdown;
 
 	/* register with core */
 	count = driver_register(&drv->driver);
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 76a189c..eae4473 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -200,7 +200,7 @@
 /* if page is completely empty, put it back on the free list, or dealloc it */
 /* if page was hijacked, unmark the flag so it might get alloced next time */
 /* Note: lock should be held when calling this */
-static inline void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
 {
 	char *ptr;
 
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index a601a42..e7a650f 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -228,7 +228,7 @@
 };
 
 
-static inline int
+static int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
                           int write, sector_t sector)
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 561bda5..1235135 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -598,7 +598,7 @@
 /*
  * Always use UUID for lookups if it's present, otherwise use name or dev.
  */
-static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
+static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
 {
 	if (*param->uuid)
 		return __get_uuid_cell(param->uuid);
@@ -608,7 +608,7 @@
 		return dm_get_mdptr(huge_decode_dev(param->dev));
 }
 
-static inline struct mapped_device *find_device(struct dm_ioctl *param)
+static struct mapped_device *find_device(struct dm_ioctl *param)
 {
 	struct hash_cell *hc;
 	struct mapped_device *md = NULL;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 4b9dd8f..87727d8 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -691,7 +691,7 @@
 /*
  * Dispatches the copy operation to kcopyd.
  */
-static inline void start_copy(struct pending_exception *pe)
+static void start_copy(struct pending_exception *pe)
 {
 	struct dm_snapshot *s = pe->snap;
 	struct io_region src, dest;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 097d1e54..8c16359 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -293,7 +293,7 @@
  * Decrements the number of outstanding ios that a bio has been
  * cloned into, completing the original io if necc.
  */
-static inline void dec_pending(struct dm_io *io, int error)
+static void dec_pending(struct dm_io *io, int error)
 {
 	if (error)
 		io->error = error;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index a06ff91..d39f584 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -176,7 +176,7 @@
 	}
 }
 
-static inline void free_r1bio(r1bio_t *r1_bio)
+static void free_r1bio(r1bio_t *r1_bio)
 {
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
@@ -190,7 +190,7 @@
 	mempool_free(r1_bio, conf->r1bio_pool);
 }
 
-static inline void put_buf(r1bio_t *r1_bio)
+static void put_buf(r1bio_t *r1_bio)
 {
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 	int i;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9e658e5..9130d05 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -176,7 +176,7 @@
 	}
 }
 
-static inline void free_r10bio(r10bio_t *r10_bio)
+static void free_r10bio(r10bio_t *r10_bio)
 {
 	conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
@@ -190,7 +190,7 @@
 	mempool_free(r10_bio, conf->r10bio_pool);
 }
 
-static inline void put_buf(r10bio_t *r10_bio)
+static void put_buf(r10bio_t *r10_bio)
 {
 	conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 54f4a98..25976bf 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -69,7 +69,7 @@
 
 static void print_raid5_conf (raid5_conf_t *conf);
 
-static inline void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
 {
 	if (atomic_dec_and_test(&sh->count)) {
 		if (!list_empty(&sh->lru))
@@ -118,7 +118,7 @@
 	hlist_del_init(&sh->hash);
 }
 
-static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
+static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
 {
 	struct hlist_head *hp = stripe_hash(conf, sh->sector);
 
@@ -178,7 +178,7 @@
 
 static void raid5_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = conf->raid_disks, i;
@@ -1415,7 +1415,7 @@
 	}
 }
 
-static inline void raid5_activate_delayed(raid5_conf_t *conf)
+static void raid5_activate_delayed(raid5_conf_t *conf)
 {
 	if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
 		while (!list_empty(&conf->delayed_list)) {
@@ -1431,7 +1431,7 @@
 	}
 }
 
-static inline void activate_bit_delay(raid5_conf_t *conf)
+static void activate_bit_delay(raid5_conf_t *conf)
 {
 	/* device_lock is held */
 	struct list_head head;
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index 8c823d6..f618a53 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -88,7 +88,7 @@
 
 static void print_raid6_conf (raid6_conf_t *conf);
 
-static inline void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
 {
 	if (atomic_dec_and_test(&sh->count)) {
 		if (!list_empty(&sh->lru))
@@ -197,7 +197,7 @@
 
 static void raid6_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
 	raid6_conf_t *conf = sh->raid_conf;
 	int disks = conf->raid_disks, i;
@@ -1577,7 +1577,7 @@
 	}
 }
 
-static inline void raid6_activate_delayed(raid6_conf_t *conf)
+static void raid6_activate_delayed(raid6_conf_t *conf)
 {
 	if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
 		while (!list_empty(&conf->delayed_list)) {
@@ -1593,7 +1593,7 @@
 	}
 }
 
-static inline void activate_bit_delay(raid6_conf_t *conf)
+static void activate_bit_delay(raid6_conf_t *conf)
 {
 	/* device_lock is held */
 	struct list_head head;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index f65f64b..44fcbe7 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -779,9 +779,8 @@
 	return 0;
 }
 
-static int dvb_bt8xx_probe(struct device *dev)
+static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
 {
-	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
 	struct dvb_bt8xx_card *card;
 	struct pci_dev* bttv_pci_dev;
 	int ret;
@@ -890,13 +889,13 @@
 		return ret;
 	}
 
-	dev_set_drvdata(dev, card);
+	dev_set_drvdata(&sub->dev, card);
 	return 0;
 }
 
-static int dvb_bt8xx_remove(struct device *dev)
+static int dvb_bt8xx_remove(struct bttv_sub_device *sub)
 {
-	struct dvb_bt8xx_card *card = dev_get_drvdata(dev);
+	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
 
 	dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
 
@@ -919,14 +918,14 @@
 static struct bttv_sub_driver driver = {
 	.drv = {
 		.name		= "dvb-bt8xx",
-		.probe		= dvb_bt8xx_probe,
-		.remove		= dvb_bt8xx_remove,
-		/* FIXME:
-		 * .shutdown	= dvb_bt8xx_shutdown,
-		 * .suspend	= dvb_bt8xx_suspend,
-		 * .resume	= dvb_bt8xx_resume,
-		 */
 	},
+	.probe		= dvb_bt8xx_probe,
+	.remove		= dvb_bt8xx_remove,
+	/* FIXME:
+	 * .shutdown	= dvb_bt8xx_shutdown,
+	 * .suspend	= dvb_bt8xx_suspend,
+	 * .resume	= dvb_bt8xx_resume,
+	 */
 };
 
 static int __init dvb_bt8xx_init(void)
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index d64accc..c4d5e2b 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -47,9 +47,29 @@
 	return 0;
 }
 
+static int bttv_sub_probe(struct device *dev)
+{
+	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+	return sub->probe ? sub->probe(sdev) : -ENODEV;
+}
+
+static int bttv_sub_remove(struct device *dev)
+{
+	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+	if (sub->remove)
+		sub->remove(sdev);
+	return 0;
+}
+
 struct bus_type bttv_sub_bus_type = {
-	.name  = "bttv-sub",
-	.match = &bttv_sub_bus_match,
+	.name   = "bttv-sub",
+	.match  = &bttv_sub_bus_match,
+	.probe  = bttv_sub_probe,
+	.remove = bttv_sub_remove,
 };
 EXPORT_SYMBOL(bttv_sub_bus_type);
 
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index e370d74..9908c8e 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -365,6 +365,8 @@
 struct bttv_sub_driver {
 	struct device_driver   drv;
 	char                   wanted[BUS_ID_SIZE];
+	int                    (*probe)(struct bttv_sub_device *sub);
+	void                   (*remove)(struct bttv_sub_device *sub);
 	void                   (*gpio_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index e86b522..9094fa9 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -93,7 +93,7 @@
 	int sat;
 };
 
-static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+static int tvp5150_read(struct i2c_client *c, unsigned char addr)
 {
 	unsigned char buffer[1];
 	int rc;
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index 1883d22..e67cf15 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -23,6 +23,7 @@
 	tristate "Fusion MPT ScsiHost drivers for FC"
 	depends on PCI && SCSI
 	select FUSION
+	select SCSI_FC_ATTRS
 	---help---
 	  SCSI HOST support for a Fiber Channel host adapters.
 
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index b61e3d1..02cdc84 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    mpi.h Version:  01.05.08
+ *    mpi.h Version:  01.05.10
  *
  *  Version History
  *  ---------------
@@ -74,6 +74,8 @@
  *  06-24-05  01.05.08  Added function codes for SCSI IO 32 and
  *                      TargetAssistExtended requests.
  *                      Added EEDP IOCStatus codes.
+ *  08-03-05  01.05.09  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-30-05  01.05.10  Added 2 new IOCStatus codes for Target.
  *  --------------------------------------------------------------------------
  */
 
@@ -104,7 +106,7 @@
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x0A)
+#define MPI_HEADER_VERSION_UNIT             (0x0C)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
@@ -711,6 +713,8 @@
 #define MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR   (0x006D)
 #define MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
 #define MPI_IOCSTATUS_TARGET_IU_TOO_SHORT        (0x006F)
+#define MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT     (0x0070)
+#define MPI_IOCSTATUS_TARGET_NAK_RECEIVED        (0x0071)
 
 /****************************************************************************/
 /*  Additional FCP target values (obsolete)                                 */
@@ -745,7 +749,7 @@
 #define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
 
 /****************************************************************************/
-/*  Serial Attached SCSI values                                                              */
+/*  Serial Attached SCSI values                                             */
 /****************************************************************************/
 
 #define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED    (0x0090)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index d833989..b1becec 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    mpi_cnfg.h Version:  01.05.09
+ *    mpi_cnfg.h Version:  01.05.11
  *
  *  Version History
  *  ---------------
@@ -249,6 +249,23 @@
  *                      Added OwnerDevHandle and Flags field to SAS PHY Page 0.
  *                      Added IOC GPIO Flags define to SAS Enclosure Page 0.
  *                      Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
+ *  08-03-05  01.05.10  Removed ISDataScrubRate and ISResyncRate from
+ *                      Manufacturing Page 4.
+ *                      Added MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE bit.
+ *                      Added NumDevsPerEnclosure field to SAS IO Unit page 2.
+ *                      Added MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP
+ *                      define.
+ *                      Added EnclosureHandle field to SAS Expander page 0.
+ *                      Removed redundant NumTableEntriesProg field from SAS
+ *                      Expander Page 1.
+ *  08-30-05  01.05.11  Added DeviceID for FC949E and changed the DeviceID for
+ *                      SAS1078.
+ *                      Added more defines for Manufacturing Page 4 Flags field.
+ *                      Added more defines for IOCSettings and added
+ *                      ExpanderSpinup field to Bios Page 1.
+ *                      Added postpone SATA Init bit to SAS IO Unit Page 1
+ *                      ControlFlags.
+ *                      Changed LogEntry format for Log Page 0.
  *  --------------------------------------------------------------------------
  */
 
@@ -494,7 +511,7 @@
 #define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
 #define MPI_MANUFACTPAGE_DEVICEID_FC939X            (0x0642)
 #define MPI_MANUFACTPAGE_DEVICEID_FC949X            (0x0640)
-#define MPI_MANUFACTPAGE_DEVICEID_FC949ES           (0x0646)
+#define MPI_MANUFACTPAGE_DEVICEID_FC949E            (0x0646)
 /* SCSI */
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
@@ -510,7 +527,7 @@
 #define MPI_MANUFACTPAGE_DEVID_SAS1066E             (0x005A)
 #define MPI_MANUFACTPAGE_DEVID_SAS1068              (0x0054)
 #define MPI_MANUFACTPAGE_DEVID_SAS1068E             (0x0058)
-#define MPI_MANUFACTPAGE_DEVID_SAS1078              (0x0060)
+#define MPI_MANUFACTPAGE_DEVID_SAS1078              (0x0062)
 
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
@@ -602,9 +619,7 @@
     U32                             IMVolumeSettings;   /* 50h */
     U32                             Reserved3;          /* 54h */
     U32                             Reserved4;          /* 58h */
-    U8                              ISDataScrubRate;    /* 5Ch */
-    U8                              ISResyncRate;       /* 5Dh */
-    U16                             Reserved5;          /* 5Eh */
+    U32                             Reserved5;          /* 5Ch */
     U8                              IMEDataScrubRate;   /* 60h */
     U8                              IMEResyncRate;      /* 61h */
     U16                             Reserved6;          /* 62h */
@@ -616,9 +631,14 @@
 } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
   ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
 
-#define MPI_MANUFACTURING4_PAGEVERSION                  (0x02)
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x03)
 
 /* defines for the Flags field */
+#define MPI_MANPAGE4_IME_DISABLE                        (0x20)
+#define MPI_MANPAGE4_IM_DISABLE                         (0x10)
+#define MPI_MANPAGE4_IS_DISABLE                         (0x08)
+#define MPI_MANPAGE4_IR_MODEPAGE8_DISABLE               (0x04)
+#define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE             (0x02)
 #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA                 (0x01)
 
 
@@ -669,7 +689,7 @@
 } CONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
   IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
 
-#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x01)
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x02)
 
 /* IO Unit Page 1 Flags defines */
 #define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
@@ -681,7 +701,7 @@
 #define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
 #define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE        (0x00000100)
-
+#define MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE        (0x00000200)
 
 typedef struct _MPI_ADAPTER_INFO
 {
@@ -968,7 +988,8 @@
     U32                     Reserved1;                  /* 0Ch */
     U32                     DeviceSettings;             /* 10h */
     U16                     NumberOfDevices;            /* 14h */
-    U16                     Reserved2;                  /* 16h */
+    U8                      ExpanderSpinup;             /* 16h */
+    U8                      Reserved2;                  /* 17h */
     U16                     IOTimeoutBlockDevicesNonRM; /* 18h */
     U16                     IOTimeoutSequential;        /* 1Ah */
     U16                     IOTimeoutOther;             /* 1Ch */
@@ -976,7 +997,7 @@
 } CONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1,
   BIOSPage1_t, MPI_POINTER pBIOSPage1_t;
 
-#define MPI_BIOSPAGE1_PAGEVERSION                       (0x02)
+#define MPI_BIOSPAGE1_PAGEVERSION                       (0x03)
 
 /* values for the BiosOptions field */
 #define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE                (0x00000400)
@@ -985,8 +1006,15 @@
 #define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS              (0x00000001)
 
 /* values for the IOCSettings field */
+#define MPI_BIOSPAGE1_IOCSET_MASK_INITIAL_SPINUP_DELAY  (0x0F000000)
+#define MPI_BIOSPAGE1_IOCSET_SHIFT_INITIAL_SPINUP_DELAY (24)
+
 #define MPI_BIOSPAGE1_IOCSET_MASK_PORT_ENABLE_DELAY     (0x00F00000)
 #define MPI_BIOSPAGE1_IOCSET_SHIFT_PORT_ENABLE_DELAY    (20)
+
+#define MPI_BIOSPAGE1_IOCSET_AUTO_PORT_ENABLE           (0x00080000)
+#define MPI_BIOSPAGE1_IOCSET_DIRECT_ATTACH_SPINUP_MODE  (0x00040000)
+
 #define MPI_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE       (0x00030000)
 #define MPI_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT        (0x00000000)
 #define MPI_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT           (0x00010000)
@@ -1016,6 +1044,11 @@
 #define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN         (0x00000002)
 #define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN          (0x00000001)
 
+/* defines for the ExpanderSpinup field */
+#define MPI_BIOSPAGE1_EXPSPINUP_MASK_MAX_TARGET         (0xF0)
+#define MPI_BIOSPAGE1_EXPSPINUP_SHIFT_MAX_TARGET        (4)
+#define MPI_BIOSPAGE1_EXPSPINUP_MASK_DELAY              (0x0F)
+
 typedef struct _MPI_BOOT_DEVICE_ADAPTER_ORDER
 {
     U32         Reserved1;                              /* 00h */
@@ -1233,13 +1266,13 @@
 
 #define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD     (8)
 #define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap)      \
-    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK) \
     >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD          \
     )
 #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
 #define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET     (16)
 #define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap)      \
-    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK) \
     >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET          \
     )
 #define MPI_SCSIPORTPAGE0_CAP_IDP                       (0x08000000)
@@ -2370,47 +2403,48 @@
 } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1,
   SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t;
 
-#define MPI_SASIOUNITPAGE1_PAGEVERSION      (0x04)
+#define MPI_SASIOUNITPAGE1_PAGEVERSION      (0x05)
 
 /* values for SAS IO Unit Page 1 ControlFlags */
-#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST        (0x8000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX            (0x4000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX            (0x2000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE        (0x1000)
-#define MPI_SAS_IOUNIT1_CONTROL_DISABLE_SAS_HASH        (0x0800)
+#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST            (0x8000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX                (0x4000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX                (0x2000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE            (0x1000)
+#define MPI_SAS_IOUNIT1_CONTROL_DISABLE_SAS_HASH            (0x0800)
 
-#define MPI_SAS_IOUNIT1_CONTROL_MASK_DEV_SUPPORT        (0x0600)
-#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT       (9)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH        (0x00)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT         (0x01)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT        (0x02)
+#define MPI_SAS_IOUNIT1_CONTROL_MASK_DEV_SUPPORT            (0x0600)
+#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT           (9)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH            (0x00)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT             (0x01)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT            (0x02)
 
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED     (0x0040)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED       (0x0020)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_FUA_REQUIRED       (0x0010)
-#define MPI_SAS_IOUNIT1_CONTROL_PHY_ENABLE_ORDER_HIGH   (0x0008)
-#define MPI_SAS_IOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL     (0x0004)
-#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY     (0x0002)
-#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION       (0x0001)
+#define MPI_SAS_IOUNIT1_CONTROL_POSTPONE_SATA_INIT          (0x0100)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED     (0x0080)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED         (0x0040)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED           (0x0020)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_FUA_REQUIRED           (0x0010)
+#define MPI_SAS_IOUNIT1_CONTROL_PHY_ENABLE_ORDER_HIGH       (0x0008)
+#define MPI_SAS_IOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL         (0x0004)
+#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY         (0x0002)
+#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION           (0x0001)
 
 /* values for SAS IO Unit Page 1 PortFlags */
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM     (0x00)
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM     (0x04)
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG     (0x01)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM         (0x00)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM         (0x04)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG         (0x01)
 
 /* values for SAS IO Unit Page 0 PhyFlags */
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE           (0x04)
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT             (0x02)
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT             (0x01)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE               (0x04)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT                 (0x02)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT                 (0x01)
 
 /* values for SAS IO Unit Page 0 MaxMinLinkRate */
-#define MPI_SAS_IOUNIT1_MAX_RATE_MASK                   (0xF0)
-#define MPI_SAS_IOUNIT1_MAX_RATE_1_5                    (0x80)
-#define MPI_SAS_IOUNIT1_MAX_RATE_3_0                    (0x90)
-#define MPI_SAS_IOUNIT1_MIN_RATE_MASK                   (0x0F)
-#define MPI_SAS_IOUNIT1_MIN_RATE_1_5                    (0x08)
-#define MPI_SAS_IOUNIT1_MIN_RATE_3_0                    (0x09)
+#define MPI_SAS_IOUNIT1_MAX_RATE_MASK                       (0xF0)
+#define MPI_SAS_IOUNIT1_MAX_RATE_1_5                        (0x80)
+#define MPI_SAS_IOUNIT1_MAX_RATE_3_0                        (0x90)
+#define MPI_SAS_IOUNIT1_MIN_RATE_MASK                       (0x0F)
+#define MPI_SAS_IOUNIT1_MIN_RATE_1_5                        (0x08)
+#define MPI_SAS_IOUNIT1_MIN_RATE_3_0                        (0x09)
 
 /* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
 
@@ -2418,16 +2452,18 @@
 typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2
 {
     CONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
-    U32                                 Reserved1;              /* 08h */
+    U8                                  NumDevsPerEnclosure;    /* 08h */
+    U8                                  Reserved1;              /* 09h */
+    U16                                 Reserved2;              /* 0Ah */
     U16                                 MaxPersistentIDs;       /* 0Ch */
     U16                                 NumPersistentIDsUsed;   /* 0Eh */
     U8                                  Status;                 /* 10h */
     U8                                  Flags;                  /* 11h */
-    U16                                 MaxNumPhysicalMappedIDs;/* 12h */              /* 12h */
+    U16                                 MaxNumPhysicalMappedIDs;/* 12h */
 } CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2,
   SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t;
 
-#define MPI_SASIOUNITPAGE2_PAGEVERSION      (0x04)
+#define MPI_SASIOUNITPAGE2_PAGEVERSION      (0x05)
 
 /* values for SAS IO Unit Page 2 Status field */
 #define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02)
@@ -2441,6 +2477,7 @@
 #define MPI_SAS_IOUNIT2_FLAGS_NO_PHYS_MAP                   (0x00)
 #define MPI_SAS_IOUNIT2_FLAGS_DIRECT_ATTACH_PHYS_MAP        (0x01)
 #define MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP       (0x02)
+#define MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP        (0x07)
 
 #define MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT         (0x10)
 #define MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT              (0x20)
@@ -2473,7 +2510,7 @@
     CONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
     U8                                  PhysicalPort;           /* 08h */
     U8                                  Reserved1;              /* 09h */
-    U16                                 Reserved2;              /* 0Ah */
+    U16                                 EnclosureHandle;        /* 0Ah */
     U64                                 SASAddress;             /* 0Ch */
     U32                                 DiscoveryStatus;        /* 14h */
     U16                                 DevHandle;              /* 18h */
@@ -2487,7 +2524,7 @@
 } CONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0,
   SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t;
 
-#define MPI_SASEXPANDER0_PAGEVERSION        (0x02)
+#define MPI_SASEXPANDER0_PAGEVERSION        (0x03)
 
 /* values for SAS Expander Page 0 DiscoveryStatus field */
 #define MPI_SAS_EXPANDER0_DS_LOOP_DETECTED              (0x00000001)
@@ -2527,9 +2564,9 @@
     U8                          NegotiatedLinkRate;     /* 1Fh */
     U8                          PhyIdentifier;          /* 20h */
     U8                          AttachedPhyIdentifier;  /* 21h */
-    U8                          NumTableEntriesProg;    /* 22h */
+    U8                          Reserved3;              /* 22h */
     U8                          DiscoveryInfo;          /* 23h */
-    U32                         Reserved3;              /* 24h */
+    U32                         Reserved4;              /* 24h */
 } CONFIG_PAGE_SAS_EXPANDER_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_1,
   SasExpanderPage1_t, MPI_POINTER pSasExpanderPage1_t;
 
@@ -2766,16 +2803,15 @@
 #define MPI_LOG_0_NUM_LOG_ENTRIES        (1)
 #endif
 
-#define MPI_LOG_0_LOG_DATA_LENGTH        (20)
+#define MPI_LOG_0_LOG_DATA_LENGTH        (0x1C)
 
 typedef struct _MPI_LOG_0_ENTRY
 {
-    U64         WWID;                               /* 00h */
-    U32         TimeStamp;                          /* 08h */
-    U32         Reserved1;                          /* 0Ch */
-    U16         LogSequence;                        /* 10h */
-    U16         LogEntryQualifier;                  /* 12h */
-    U8          LogData[MPI_LOG_0_LOG_DATA_LENGTH]; /* 14h */
+    U32         TimeStamp;                          /* 00h */
+    U32         Reserved1;                          /* 04h */
+    U16         LogSequence;                        /* 08h */
+    U16         LogEntryQualifier;                  /* 0Ah */
+    U8          LogData[MPI_LOG_0_LOG_DATA_LENGTH]; /* 0Ch */
 } MPI_LOG_0_ENTRY, MPI_POINTER PTR_MPI_LOG_0_ENTRY,
   MpiLog0Entry_t, MPI_POINTER pMpiLog0Entry_t;
 
@@ -2794,7 +2830,7 @@
 } CONFIG_PAGE_LOG_0, MPI_POINTER PTR_CONFIG_PAGE_LOG_0,
   LogPage0_t, MPI_POINTER pLogPage0_t;
 
-#define MPI_LOG_0_PAGEVERSION               (0x00)
+#define MPI_LOG_0_PAGEVERSION               (0x01)
 
 
 #endif
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index 1a30ef1..4a5f8dd 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -6,25 +6,25 @@
  Copyright (c) 2000-2005 LSI Logic Corporation.
 
  ---------------------------------------
- Header Set Release Version:    01.05.10
- Header Set Release Date:       03-11-05
+ Header Set Release Version:    01.05.12
+ Header Set Release Date:       08-30-05
  ---------------------------------------
 
  Filename               Current version     Prior version
  ----------             ---------------     -------------
- mpi.h                  01.05.08            01.05.07
- mpi_ioc.h              01.05.09            01.05.08
- mpi_cnfg.h             01.05.09            01.05.08
- mpi_init.h             01.05.05            01.05.04
- mpi_targ.h             01.05.05            01.05.04
+ mpi.h                  01.05.10            01.05.09
+ mpi_ioc.h              01.05.10            01.05.09
+ mpi_cnfg.h             01.05.11            01.05.10
+ mpi_init.h             01.05.06            01.05.06
+ mpi_targ.h             01.05.05            01.05.05
  mpi_fc.h               01.05.01            01.05.01
  mpi_lan.h              01.05.01            01.05.01
  mpi_raid.h             01.05.02            01.05.02
  mpi_tool.h             01.05.03            01.05.03
  mpi_inb.h              01.05.01            01.05.01
- mpi_sas.h              01.05.01            01.05.01
- mpi_type.h             01.05.01            01.05.01
- mpi_history.txt        01.05.09            01.05.09
+ mpi_sas.h              01.05.02            01.05.01
+ mpi_type.h             01.05.02            01.05.01
+ mpi_history.txt        01.05.12            01.05.11
 
 
  *  Date      Version   Description
@@ -91,6 +91,8 @@
  *  06-24-05  01.05.08  Added function codes for SCSI IO 32 and
  *                      TargetAssistExtended requests.
  *                      Added EEDP IOCStatus codes.
+ *  08-03-05  01.05.09  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-30-05  01.05.10  Added 2 new IOCStatus codes for Target.
  *  --------------------------------------------------------------------------
 
 mpi_ioc.h
@@ -164,6 +166,10 @@
  *                      Removed IOCFacts Reply EEDP Capability bit.
  *  06-24-05  01.05.09  Added 5 new IOCFacts Reply IOCCapabilities bits.
  *                      Added Max SATA Targets to SAS Discovery Error event.
+ *  08-30-05  01.05.10  Added 4 new events and their event data structures.
+ *                      Added new ReasonCode value for SAS Device Status Change
+ *                      event.
+ *                      Added new family code for FC949E.
  *  --------------------------------------------------------------------------
 
 mpi_cnfg.h
@@ -402,6 +408,23 @@
  *                      Added OwnerDevHandle and Flags field to SAS PHY Page 0.
  *                      Added IOC GPIO Flags define to SAS Enclosure Page 0.
  *                      Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
+ *  08-03-05  01.05.10  Removed ISDataScrubRate and ISResyncRate from
+ *                      Manufacturing Page 4.
+ *                      Added MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE bit.
+ *                      Added NumDevsPerEnclosure field to SAS IO Unit page 2.
+ *                      Added MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP
+ *                      define.
+ *                      Added EnclosureHandle field to SAS Expander page 0.
+ *                      Removed redundant NumTableEntriesProg field from SAS
+ *                      Expander Page 1.
+ *  08-30-05  01.05.11  Added DeviceID for FC949E and changed the DeviceID for
+ *                      SAS1078.
+ *                      Added more defines for Manufacturing Page 4 Flags field.
+ *                      Added more defines for IOCSettings and added
+ *                      ExpanderSpinup field to Bios Page 1.
+ *                      Added postpone SATA Init bit to SAS IO Unit Page 1
+ *                      ControlFlags.
+ *                      Changed LogEntry format for Log Page 0.
  *  --------------------------------------------------------------------------
 
 mpi_init.h
@@ -442,6 +465,8 @@
  *                      addressing.
  *  06-24-05  01.05.05  Added SCSI IO 32 structures and defines.
  *                      Added four new defines for SEP SlotStatus.
+ *  08-03-05  01.05.06  Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
+ *                      unique in the first 32 characters.
  *  --------------------------------------------------------------------------
 
 mpi_targ.h
@@ -582,6 +607,9 @@
 
 mpi_sas.h
  *  08-19-04  01.05.01  Original release.
+ *  08-30-05  01.05.02  Added DeviceInfo bit for SEP.
+ *                      Added PrimFlags and Primitive field to SAS IO Unit
+ *                      Control request, and added a new operation code.
  *  --------------------------------------------------------------------------
 
 mpi_type.h
@@ -592,24 +620,25 @@
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *  05-11-04  01.03.01  Original release for MPI v1.3.
  *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  08-30-05  01.05.02  Added PowerPC option to #ifdef's.
  *  --------------------------------------------------------------------------
 
 mpi_history.txt         Parts list history
 
-Filename    01.05.10  01.05.09
-----------  --------  --------
-mpi.h       01.05.08  01.05.07
-mpi_ioc.h   01.05.09  01.05.08
-mpi_cnfg.h  01.05.09  01.05.08
-mpi_init.h  01.05.05  01.05.04
-mpi_targ.h  01.05.05  01.05.04
-mpi_fc.h    01.05.01  01.05.01
-mpi_lan.h   01.05.01  01.05.01
-mpi_raid.h  01.05.02  01.05.02
-mpi_tool.h  01.05.03  01.05.03
-mpi_inb.h   01.05.01  01.05.01
-mpi_sas.h   01.05.01  01.05.01
-mpi_type.h  01.05.01  01.05.01
+Filename    01.05.12  01.05.11  01.05.10  01.05.09
+----------  --------  --------  --------  --------
+mpi.h       01.05.10  01.05.09  01.05.08  01.05.07
+mpi_ioc.h   01.05.10  01.05.09  01.05.09  01.05.08
+mpi_cnfg.h  01.05.11  01.05.10  01.05.09  01.05.08
+mpi_init.h  01.05.06  01.05.06  01.05.05  01.05.04
+mpi_targ.h  01.05.05  01.05.05  01.05.05  01.05.04
+mpi_fc.h    01.05.01  01.05.01  01.05.01  01.05.01
+mpi_lan.h   01.05.01  01.05.01  01.05.01  01.05.01
+mpi_raid.h  01.05.02  01.05.02  01.05.02  01.05.02
+mpi_tool.h  01.05.03  01.05.03  01.05.03  01.05.03
+mpi_inb.h   01.05.01  01.05.01  01.05.01  01.05.01
+mpi_sas.h   01.05.02  01.05.01  01.05.01  01.05.01
+mpi_type.h  01.05.02  01.05.01  01.05.01  01.05.01
 
 Filename    01.05.08   01.05.07   01.05.06   01.05.05   01.05.04   01.05.03
 ----------  --------   --------   --------   --------   --------   --------
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index d5af75a..68941f4 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -6,7 +6,7 @@
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    mpi_init.h Version:  01.05.05
+ *    mpi_init.h Version:  01.05.06
  *
  *  Version History
  *  ---------------
@@ -50,6 +50,8 @@
  *                      addressing.
  *  06-24-05  01.05.05  Added SCSI IO 32 structures and defines.
  *                      Added four new defines for SEP SlotStatus.
+ *  08-03-05  01.05.06  Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
+ *                      unique in the first 32 characters.
  *  --------------------------------------------------------------------------
  */
 
@@ -290,8 +292,8 @@
 
 /* SCSI IO 32 MsgFlags bits */
 #define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH                (0x01)
-#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_32             (0x00)
-#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_64             (0x01)
+#define MPI_SCSIIO32_MSGFLGS_32_SENSE_WIDTH             (0x00)
+#define MPI_SCSIIO32_MSGFLGS_64_SENSE_WIDTH             (0x01)
 
 #define MPI_SCSIIO32_MSGFLGS_SENSE_LOCATION             (0x02)
 #define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_HOST             (0x00)
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 93b70e2..2c5f43f 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    mpi_ioc.h Version:  01.05.09
+ *    mpi_ioc.h Version:  01.05.10
  *
  *  Version History
  *  ---------------
@@ -83,6 +83,10 @@
  *                      Removed IOCFacts Reply EEDP Capability bit.
  *  06-24-05  01.05.09  Added 5 new IOCFacts Reply IOCCapabilities bits.
  *                      Added Max SATA Targets to SAS Discovery Error event.
+ *  08-30-05  01.05.10  Added 4 new events and their event data structures.
+ *                      Added new ReasonCode value for SAS Device Status Change
+ *                      event.
+ *                      Added new family code for FC949E.
  *  --------------------------------------------------------------------------
  */
 
@@ -464,6 +468,10 @@
 #define MPI_EVENT_PERSISTENT_TABLE_FULL     (0x00000011)
 #define MPI_EVENT_SAS_PHY_LINK_STATUS       (0x00000012)
 #define MPI_EVENT_SAS_DISCOVERY_ERROR       (0x00000013)
+#define MPI_EVENT_IR_RESYNC_UPDATE          (0x00000014)
+#define MPI_EVENT_IR2                       (0x00000015)
+#define MPI_EVENT_SAS_DISCOVERY             (0x00000016)
+#define MPI_EVENT_LOG_ENTRY_ADDED           (0x00000021)
 
 /* AckRequired field values */
 
@@ -480,6 +488,29 @@
 } EVENT_DATA_EVENT_CHANGE, MPI_POINTER PTR_EVENT_DATA_EVENT_CHANGE,
   EventDataEventChange_t, MPI_POINTER pEventDataEventChange_t;
 
+/* LogEntryAdded Event data */
+
+/* this structure matches MPI_LOG_0_ENTRY in mpi_cnfg.h */
+#define MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH    (0x1C)
+typedef struct _EVENT_DATA_LOG_ENTRY
+{
+    U32         TimeStamp;                          /* 00h */
+    U32         Reserved1;                          /* 04h */
+    U16         LogSequence;                        /* 08h */
+    U16         LogEntryQualifier;                  /* 0Ah */
+    U8          LogData[MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH]; /* 0Ch */
+} EVENT_DATA_LOG_ENTRY, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY,
+  MpiEventDataLogEntry_t, MPI_POINTER pMpiEventDataLogEntry_t;
+
+typedef struct _EVENT_DATA_LOG_ENTRY_ADDED
+{
+    U16                     LogSequence;            /* 00h */
+    U16                     Reserved1;              /* 02h */
+    U32                     Reserved2;              /* 04h */
+    EVENT_DATA_LOG_ENTRY    LogEntry;               /* 08h */
+} EVENT_DATA_LOG_ENTRY_ADDED, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY_ADDED,
+  MpiEventDataLogEntryAdded_t, MPI_POINTER pMpiEventDataLogEntryAdded_t;
+
 /* SCSI Event data for Port, Bus and Device forms */
 
 typedef struct _EVENT_DATA_SCSI
@@ -538,6 +569,7 @@
 #define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA            (0x05)
 #define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED      (0x06)
 #define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED           (0x07)
+#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
 
 
 /* SCSI Event data for Queue Full event */
@@ -579,6 +611,79 @@
 #define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
 #define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
 
+
+/* MPI Integrated RAID Resync Update Event data */
+
+typedef struct _MPI_EVENT_DATA_IR_RESYNC_UPDATE
+{
+    U8                      VolumeID;                   /* 00h */
+    U8                      VolumeBus;                  /* 01h */
+    U8                      ResyncComplete;             /* 02h */
+    U8                      Reserved1;                  /* 03h */
+    U32                     Reserved2;                  /* 04h */
+} MPI_EVENT_DATA_IR_RESYNC_UPDATE,
+  MPI_POINTER PTR_MPI_EVENT_DATA_IR_RESYNC_UPDATE,
+  MpiEventDataIrResyncUpdate_t, MPI_POINTER pMpiEventDataIrResyncUpdate_t;
+
+/* MPI IR2 Event data */
+
+/* MPI_LD_STATE or MPI_PD_STATE */
+typedef struct _IR2_STATE_CHANGED
+{
+    U16                 PreviousState;  /* 00h */
+    U16                 NewState;       /* 02h */
+} IR2_STATE_CHANGED, MPI_POINTER PTR_IR2_STATE_CHANGED;
+
+typedef struct _IR2_PD_INFO
+{
+    U16                 DeviceHandle;           /* 00h */
+    U8                  TruncEnclosureHandle;   /* 02h */
+    U8                  TruncatedSlot;          /* 03h */
+} IR2_PD_INFO, MPI_POINTER PTR_IR2_PD_INFO;
+
+typedef union _MPI_IR2_RC_EVENT_DATA
+{
+    IR2_STATE_CHANGED   StateChanged;
+    U32                 Lba;
+    IR2_PD_INFO         PdInfo;
+} MPI_IR2_RC_EVENT_DATA, MPI_POINTER PTR_MPI_IR2_RC_EVENT_DATA;
+
+typedef struct _MPI_EVENT_DATA_IR2
+{
+    U8                      TargetID;             /* 00h */
+    U8                      Bus;                  /* 01h */
+    U8                      ReasonCode;           /* 02h */
+    U8                      PhysDiskNum;          /* 03h */
+    MPI_IR2_RC_EVENT_DATA   IR2EventData;         /* 04h */
+} MPI_EVENT_DATA_IR2, MPI_POINTER PTR_MPI_EVENT_DATA_IR2,
+  MpiEventDataIR2_t, MPI_POINTER pMpiEventDataIR2_t;
+
+/* MPI IR2 Event data ReasonCode values */
+#define MPI_EVENT_IR2_RC_LD_STATE_CHANGED           (0x01)
+#define MPI_EVENT_IR2_RC_PD_STATE_CHANGED           (0x02)
+#define MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL       (0x03)
+#define MPI_EVENT_IR2_RC_PD_INSERTED                (0x04)
+#define MPI_EVENT_IR2_RC_PD_REMOVED                 (0x05)
+#define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED       (0x06)
+#define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR       (0x07)
+
+/* defines for logical disk states */
+#define MPI_LD_STATE_OPTIMAL                        (0x00)
+#define MPI_LD_STATE_DEGRADED                       (0x01)
+#define MPI_LD_STATE_FAILED                         (0x02)
+#define MPI_LD_STATE_MISSING                        (0x03)
+#define MPI_LD_STATE_OFFLINE                        (0x04)
+
+/* defines for physical disk states */
+#define MPI_PD_STATE_ONLINE                         (0x00)
+#define MPI_PD_STATE_MISSING                        (0x01)
+#define MPI_PD_STATE_NOT_COMPATIBLE                 (0x02)
+#define MPI_PD_STATE_FAILED                         (0x03)
+#define MPI_PD_STATE_INITIALIZING                   (0x04)
+#define MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST        (0x05)
+#define MPI_PD_STATE_FAILED_AT_HOST_REQUEST         (0x06)
+#define MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON     (0xFF)
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -660,6 +765,20 @@
 #define MPI_EVENT_SAS_PLS_LR_RATE_1_5                       (0x08)
 #define MPI_EVENT_SAS_PLS_LR_RATE_3_0                       (0x09)
 
+/* SAS Discovery Event data */
+
+typedef struct _EVENT_DATA_SAS_DISCOVERY
+{
+    U32                     DiscoveryStatus;            /* 00h */
+    U32                     Reserved1;                  /* 04h */
+} EVENT_DATA_SAS_DISCOVERY, MPI_POINTER PTR_EVENT_DATA_SAS_DISCOVERY,
+  EventDataSasDiscovery_t, MPI_POINTER pEventDataSasDiscovery_t;
+
+#define MPI_EVENT_SAS_DSCVRY_COMPLETE                       (0x00000000)
+#define MPI_EVENT_SAS_DSCVRY_IN_PROGRESS                    (0x00000001)
+#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_MASK                  (0xFFFF0000)
+#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_SHIFT                 (16)
+
 /* SAS Discovery Errror Event data */
 
 typedef struct _EVENT_DATA_DISCOVERY_ERROR
@@ -869,6 +988,7 @@
 #define MPI_FW_HEADER_PID_FAMILY_919XL_FC       (0x0003) /* 919XL and 929XL */
 #define MPI_FW_HEADER_PID_FAMILY_939X_FC        (0x0004) /* 939X and 949X   */
 #define MPI_FW_HEADER_PID_FAMILY_959_FC         (0x0005)
+#define MPI_FW_HEADER_PID_FAMILY_949E_FC        (0x0006)
 /* SAS */
 #define MPI_FW_HEADER_PID_FAMILY_1064_SAS       (0x0001)
 #define MPI_FW_HEADER_PID_FAMILY_1068_SAS       (0x0002)
diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h
new file mode 100644
index 0000000..dc98d46
--- /dev/null
+++ b/drivers/message/fusion/lsi/mpi_log_fc.h
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ *  NAME:           fc_log.h
+ *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
+ *  DESCRIPTION:    Contains the enumerated list of values that may be returned
+ *                  in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ *  CREATION DATE:  6/02/2000
+ *  ID:             $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ *          a = The type of log info as per the MPI spec. Since these codes are
+ *              all for Fibre Channel this value will always be 2.
+ *          b = Specifies a subclass of the firmware where
+ *                  0 = FCP Initiator
+ *                  1 = FCP Target
+ *                  2 = LAN
+ *                  3 = MPI Message Layer
+ *                  4 = FC Link
+ *                  5 = Context Manager
+ *                  6 = Invalid Field Offset
+ *                  7 = State Change Info
+ *                  all others are reserved for future use
+ *          c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ *       codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+    MPI_IOCLOGINFO_FC_INIT_BASE                     = 0x20000000,
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME   = 0x20000003, /* Bad Rx Frame, bad end of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN           = 0x20000004, /* Bad Rx Frame, overrun */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER           = 0x20000005, /* Other errors caught by IOC which require retries */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD       = 0x20000006, /* Main processor could not initialize sub-processor */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN         = 0x20000007, /* Scatter Gather overrun  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS      = 0x20000008, /* Receiver detected context mismatch via invalid header */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE       = 0x2000000A, /* Link failure occurred  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT         = 0x2000000B, /* Transmitter timeout error */
+
+    MPI_IOCLOGINFO_FC_TARGET_BASE                   = 0x21000000,
+    MPI_IOCLOGINFO_FC_TARGET_NO_PDISC               = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+    MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN               = 0x21000002, /* not sent because we are not logged in to the remote node */
+    MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP     = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP     = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA      = 0x21000005, /* Data In, Auto Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP     = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP     = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP     = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA      = 0x21000009, /* Data In, No Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
+    MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound queue after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
+
+    MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
+    MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING         = 0x22000001, /* Transaction Context Sgl Missing */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE         = 0x22000002, /* Transaction Context found before an EOB */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET        = 0x22000003, /* Transaction Context value has reserved bits set */
+    MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG            = 0x22000004, /* Invalid SGL Flags */
+
+    MPI_IOCLOGINFO_FC_MSG_BASE                      = 0x23000000,
+
+    MPI_IOCLOGINFO_FC_LINK_BASE                     = 0x24000000,
+    MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT        = 0x24000001, /* Loop initialization timed out */
+    MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED      = 0x24000002, /* Another system controller already initialized the loop */
+    MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED     = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+    MPI_IOCLOGINFO_FC_LINK_CRC_ERROR                = 0x24000004, /* CRC check detected error on received frame */
+
+    MPI_IOCLOGINFO_FC_CTX_BASE                      = 0x25000000,
+
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET     = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET      = 0x26ffffff,
+
+    MPI_IOCLOGINFO_FC_STATE_CHANGE                  = 0x27000000  /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
new file mode 100644
index 0000000..9259d1a
--- /dev/null
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -0,0 +1,162 @@
+
+/***************************************************************************
+ *                                                                         *
+ *  Copyright 2003 LSI Logic Corporation.  All rights reserved.            *
+ *                                                                         *
+ *  This file is confidential and a trade secret of LSI Logic.  The        *
+ *  receipt of or possession of this file does not convey any rights to    *
+ *  reproduce or disclose its contents or to manufacture, use, or sell     *
+ *  anything it may describe, in whole, or in part, without the specific   *
+ *  written consent of LSI Logic Corporation.                              *
+ *                                                                         *
+ ***************************************************************************
+ *
+ *           Name:  iopiIocLogInfo.h
+ *          Title:  SAS Firmware IOP Interface IOC Log Info Definitions
+ *     Programmer:  Guy Kendall
+ *  Creation Date:  September 24, 2003
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Last Updated
+ *  -------------
+ *  Version         %version: 22 %
+ *  Date Updated    %date_modified: %
+ *  Programmer      %created_by: nperucca %
+ *
+ *  Date      Who   Description
+ *  --------  ---   -------------------------------------------------------
+ *  09/24/03  GWK   Initial version
+ *
+ *
+ * Description
+ * ------------
+ * This include file contains SAS firmware interface IOC Log Info codes
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef IOPI_IOCLOGINFO_H_INCLUDED
+#define IOPI_IOCLOGINFO_H_INCLUDED
+
+
+/****************************************************************************/
+/*  IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF                            */
+/*  Format:                                                                 */
+/*      Bits 31-28: MPI_IOCLOGINFO_TYPE_SAS (3)                             */
+/*      Bits 27-24: IOC_LOGINFO_ORIGINATOR: 0=IOP, 1=PL, 2=IR               */
+/*      Bits 23-16: LOGINFO_CODE                                            */
+/*      Bits 15-0:  LOGINFO_CODE Specific                                   */
+/****************************************************************************/
+
+/****************************************************************************/
+/* IOC_LOGINFO_ORIGINATOR defines                                           */
+/****************************************************************************/
+#define IOC_LOGINFO_ORIGINATOR_IOP                      (0x00000000)
+#define IOC_LOGINFO_ORIGINATOR_PL                       (0x01000000)
+#define IOC_LOGINFO_ORIGINATOR_IR                       (0x02000000)
+
+/****************************************************************************/
+/* LOGINFO_CODE defines                                                     */
+/****************************************************************************/
+#define IOC_LOGINFO_CODE_MASK                           (0x00FF0000)
+#define IOC_LOGINFO_CODE_SHIFT                          (16)
+
+/****************************************************************************/
+/* IOP LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IOP          */
+/****************************************************************************/
+#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS            (0x00010000)
+#define IOP_LOGINFO_CODE_UNUSED2                        (0x00020000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE            (0x00030000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT         (0x00030100) /* Route Table Entry not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN         (0x00030200) /* Invalid Page Number */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM       (0x00030300) /* Invalid FORM */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT         (0x00030400) /* Invalid Page Type */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM        (0x00030500) /* Device Not Mapped */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST    (0x00030600) /* Persistent Page not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT    (0x00030700) /* Default Page not found */
+#define IOP_LOGINFO_CODE_TASK_TERMINATED                (0x00050000)
+
+
+/****************************************************************************/
+/* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL            */
+/****************************************************************************/
+#define PL_LOGINFO_CODE_OPEN_FAILURE                        (0x00010000)
+#define PL_LOGINFO_CODE_INVALID_SGL                         (0x00020000)
+#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH       (0x00030000)
+#define PL_LOGINFO_CODE_FRAME_XFER_ERROR                    (0x00040000)
+#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW                 (0x00050000)
+#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET         (0x00060000)
+#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR      (0x00070000)
+#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR     (0x00080000)
+#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS     (0x00090000)
+#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE               (0x000A0000)
+#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR          (0x000B0000)
+#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR           (0x000C0000)
+#define PL_LOGINFO_CODE_SATA_LINK_DOWN                      (0x000D0000)
+#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS           (0x000E0000)
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE                 (0x000F0000)
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT              (0x000F0100) /* Invalid Page Type */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS        (0x000F0200) /* Invalid Number of Phys */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP         (0x000F0300) /* Case Not Handled */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV          (0x000F0400) /* No Device Found */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM            (0x000F0500) /* Invalid FORM */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY             (0x000F0600) /* Invalid Phy */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER        (0x000F0700) /* No Owner Found */
+#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT            (0x00100000)
+#define PL_LOGINFO_CODE_RESET                               (0x00110000)
+#define PL_LOGINFO_CODE_ABORT                               (0x00120000)
+#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED                 (0x00130000)
+#define PL_LOGINFO_CODE_IO_EXECUTED                         (0x00140000)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE                    (0x00000100)
+#define PL_LOGINFO_SUB_CODE_INVALID_SGL                     (0x00000200)
+#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH   (0x00000300)
+#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR                (0x00000400)
+#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW             (0x00000500)
+#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET     (0x00000600)
+#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR  (0x00000700)
+#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800)
+#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900)
+#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE           (0x00000A00)
+#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR      (0x00000B00)
+#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR       (0x00000C00)
+#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN                  (0x00000D00)
+#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS       (0x00000E00)
+#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT        (0x00001000)
+
+
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE         (0x00200000) /* Can't get SMP Frame */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR            (0x00200001) /* Error occured on SMP Read */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR           (0x00200002) /* Error occured on SMP Write */
+#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL     (0x00200004) /* Encl Mgmt services not available for this WWID */
+#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED   (0x00200005) /* Address Mode not suppored */
+#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM              (0x00200006) /* Invalid Slot Number in SEP Msg */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT         (0x00200007) /* SGPIO not present/enabled */
+
+#define PL_LOGINFO_DA_SEP_NOT_PRESENT                       (0x00200100) /* SEP not present when msg received */
+#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR               (0x00200101) /* Can only accept 1 msg at a time */
+#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE          (0x00200102) /* ISTWI interrupt recvd. while IDLE */
+#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE          (0x00200103) /* SEP NACK'd, it is busy */
+#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM             (0x00200104) /* SEP stopped or sent bad chksum in Hdr */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1         (0x00200105) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2         (0x00200106) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP           (0x00200107) /* SEP returned bad chksum after STOP */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA   (0x00200108) /* SEP returned bad chksum after STOP while gettin data*/
+
+
+/****************************************************************************/
+/* IR LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IR            */
+/****************************************************************************/
+#define IR_LOGINFO_CODE_UNUSED1                         (0x00010000)
+#define IR_LOGINFO_CODE_UNUSED2                         (0x00020000)
+
+/****************************************************************************/
+/* Defines for convienence                                                  */
+/****************************************************************************/
+#define IOC_LOGINFO_PREFIX_IOP                          ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IOP)
+#define IOC_LOGINFO_PREFIX_PL                           ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_PL)
+#define IOC_LOGINFO_PREFIX_IR                           ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IR)
+
+#endif /* end of file */
+
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 230fa69..7051486 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -6,7 +6,7 @@
  *          Title:  MPI Serial Attached SCSI structures and definitions
  *  Creation Date:  August 19, 2004
  *
- *    mpi_sas.h Version:  01.05.01
+ *    mpi_sas.h Version:  01.05.02
  *
  *  Version History
  *  ---------------
@@ -14,6 +14,9 @@
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
  *  08-19-04  01.05.01  Original release.
+ *  08-30-05  01.05.02  Added DeviceInfo bit for SEP.
+ *                      Added PrimFlags and Primitive field to SAS IO Unit
+ *                      Control request, and added a new operation code.
  *  --------------------------------------------------------------------------
  */
 
@@ -51,6 +54,7 @@
  * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
  * data and SAS IO Unit Configuration pages.
  */
+#define MPI_SAS_DEVICE_INFO_SEP                 (0x00004000)
 #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE        (0x00002000)
 #define MPI_SAS_DEVICE_INFO_LSI_DEVICE          (0x00001000)
 #define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH       (0x00000800)
@@ -212,20 +216,26 @@
     U8                      TargetID;           /* 0Ch */
     U8                      Bus;                /* 0Dh */
     U8                      PhyNum;             /* 0Eh */
-    U8                      Reserved4;          /* 0Fh */
-    U32                     Reserved5;          /* 10h */
+    U8                      PrimFlags;          /* 0Fh */
+    U32                     Primitive;          /* 10h */
     U64                     SASAddress;         /* 14h */
-    U32                     Reserved6;          /* 1Ch */
+    U32                     Reserved4;          /* 1Ch */
 } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
   SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
 
 /* values for the Operation field */
-#define MPI_SAS_OP_CLEAR_NOT_PRESENT             (0x01)
-#define MPI_SAS_OP_CLEAR_ALL_PERSISTENT          (0x02)
-#define MPI_SAS_OP_PHY_LINK_RESET                (0x06)
-#define MPI_SAS_OP_PHY_HARD_RESET                (0x07)
-#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG           (0x08)
-#define MPI_SAS_OP_MAP_CURRENT                   (0x09)
+#define MPI_SAS_OP_CLEAR_NOT_PRESENT            (0x01)
+#define MPI_SAS_OP_CLEAR_ALL_PERSISTENT         (0x02)
+#define MPI_SAS_OP_PHY_LINK_RESET               (0x06)
+#define MPI_SAS_OP_PHY_HARD_RESET               (0x07)
+#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG          (0x08)
+#define MPI_SAS_OP_MAP_CURRENT                  (0x09)
+#define MPI_SAS_OP_SEND_PRIMITIVE               (0x0A)
+
+/* values for the PrimFlags field */
+#define MPI_SAS_PRIMFLAGS_SINGLE                (0x08)
+#define MPI_SAS_PRIMFLAGS_TRIPLE                (0x02)
+#define MPI_SAS_PRIMFLAGS_REDUNDANT             (0x01)
 
 
 /* SAS IO Unit Control Reply */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5378360..d890b2b 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -148,7 +148,6 @@
 static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int	GetLanConfigPages(MPT_ADAPTER *ioc);
-static int	GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 static int	GetIoUnitPage2(MPT_ADAPTER *ioc);
 int		mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
@@ -1232,12 +1231,11 @@
 		dprintk((KERN_INFO MYNAM
 			": Not using 64 bit consistent mask\n"));
 
-	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+	ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
 	if (ioc == NULL) {
 		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
 		return -ENOMEM;
 	}
-	memset(ioc, 0, sizeof(MPT_ADAPTER));
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
 	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
@@ -1245,6 +1243,8 @@
 	ioc->pcidev = pdev;
 	ioc->diagPending = 0;
 	spin_lock_init(&ioc->diagLock);
+	spin_lock_init(&ioc->fc_rescan_work_lock);
+	spin_lock_init(&ioc->fc_rport_lock);
 	spin_lock_init(&ioc->initializing_hba_lock);
 
 	/* Initialize the event logging.
@@ -1268,6 +1268,10 @@
 	 */
 	INIT_LIST_HEAD(&ioc->configQ);
 
+	/* Initialize the fc rport list head.
+	 */
+	INIT_LIST_HEAD(&ioc->fc_rports);
+
 	/* Find lookup slot. */
 	INIT_LIST_HEAD(&ioc->list);
 	ioc->id = mpt_ids++;
@@ -1374,6 +1378,10 @@
 		ioc->bus_type = FC;
 		ioc->errata_flag_1064 = 1;
 	}
+	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
+		ioc->prod_name = "LSIFC949E";
+		ioc->bus_type = FC;
+	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->prod_name = "LSI53C1030";
 		ioc->bus_type = SPI;
@@ -1622,7 +1630,7 @@
 	pci_enable_device(pdev);
 
 	/* enable interrupts */
-	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+	CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
 	ioc->active = 1;
 
 	/* F/W not running */
@@ -1715,7 +1723,7 @@
 				/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
 				dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 						ioc->alt_ioc->name));
-				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
 				ioc->alt_ioc->active = 1;
 			}
 
@@ -1831,7 +1839,7 @@
 
 	if (ret == 0) {
 		/* Enable! (reply interrupt) */
-		CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+		CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
 		ioc->active = 1;
 	}
 
@@ -1839,7 +1847,7 @@
 		/* (re)Enable alt-IOC! (reply interrupt) */
 		dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 				ioc->alt_ioc->name));
-		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
 		ioc->alt_ioc->active = 1;
 	}
 
@@ -1880,7 +1888,7 @@
 			 *  (FCPortPage0_t stuff)
 			 */
 			for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
-				(void) GetFcPortPage0(ioc, ii);
+				(void) mptbase_GetFcPortPage0(ioc, ii);
 			}
 
 			if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
@@ -4199,7 +4207,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	GetFcPortPage0 - Fetch FCPort config Page0.
+ *	mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: IOC Port number
  *
@@ -4209,8 +4217,8 @@
  *		-EAGAIN if no msg frames currently available
  *		-EFAULT for non-successful reply or no reply (timeout)
  */
-static int
-GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+int
+mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
 {
 	ConfigPageHeader_t	 hdr;
 	CONFIGPARMS		 cfg;
@@ -4220,6 +4228,8 @@
 	int			 data_sz;
 	int			 copy_sz;
 	int			 rc;
+	int			 count = 400;
+
 
 	/* Get FCPort Page 0 header */
 	hdr.PageVersion = 0;
@@ -4243,6 +4253,8 @@
 	rc = -ENOMEM;
 	ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
 	if (ppage0_alloc) {
+
+ try_again:
 		memset((u8 *)ppage0_alloc, 0, data_sz);
 		cfg.physAddr = page0_dma;
 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -4274,6 +4286,19 @@
 			pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
 			pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
 
+			/*
+			 * if still doing discovery,
+			 * hang loose a while until finished
+			 */
+			if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+				if (count-- > 0) {
+					msleep_interruptible(100);
+					goto try_again;
+				}
+				printk(MYIOC_s_INFO_FMT "Firmware discovery not"
+							" complete.\n",
+						ioc->name);
+			}
 		}
 
 		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -6358,6 +6383,7 @@
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 6c48d1f..47053ac 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.03.05"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.05"
+#define MPT_LINUX_VERSION_COMMON	"3.03.06"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.06"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -413,7 +413,7 @@
 	u8			 status;	/* current command status */
 	u8			 reset;		/* 1 if bus reset allowed */
 	u8			 target;	/* target for reset */
-	struct semaphore	 sem_ioc;
+	struct mutex		 ioctl_mutex;
 } MPT_IOCTL;
 
 #define MPT_SAS_MGMT_STATUS_RF_VALID	0x02	/* The Reply Frame is VALID */
@@ -421,7 +421,7 @@
 #define MPT_SAS_MGMT_STATUS_TM_FAILED	0x40	/* User TM request failed */
 
 typedef struct _MPT_SAS_MGMT {
-	struct semaphore	 mutex;
+	struct mutex		 mutex;
 	struct completion	 done;
 	u8			 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
 	u8			 status;	/* current command status */
@@ -499,6 +499,22 @@
 	int		 isRaid;		/* bit field, 1 if RAID */
 }RaidCfgData;
 
+#define MPT_RPORT_INFO_FLAGS_REGISTERED	0x01	/* rport registered */
+#define MPT_RPORT_INFO_FLAGS_MISSING	0x02	/* missing from DevPage0 scan */
+#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04	/* target mapped in vdev */
+
+/*
+ * data allocated for each fc rport device
+ */
+struct mptfc_rport_info
+{
+	struct list_head list;
+	struct fc_rport *rport;
+	VirtDevice	*vdev;
+	FCDevicePage0_t pg0;
+	u8		flags;
+};
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -612,7 +628,16 @@
 	struct list_head	 list;
 	struct net_device	*netdev;
 	struct list_head	 sas_topology;
+	struct mutex		 sas_topology_mutex;
 	MPT_SAS_MGMT		 sas_mgmt;
+	int			 num_ports;
+
+	struct list_head	 fc_rports;
+	spinlock_t		 fc_rport_lock; /* list and ri flags */
+	spinlock_t		 fc_rescan_work_lock;
+	int			 fc_rescan_work_count;
+	struct work_struct	 fc_rescan_work;
+
 } MPT_ADAPTER;
 
 /*
@@ -999,6 +1024,7 @@
 extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int	 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+extern int	 mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 extern int	 mpt_alt_ioc_wait(MPT_ADAPTER *ioc);
 
 /*
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 7c34024..bdf7099 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -177,10 +177,10 @@
 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
 	if (nonblock) {
-		if (down_trylock(&ioc->ioctl->sem_ioc))
+		if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
 			rc = -EAGAIN;
 	} else {
-		if (down_interruptible(&ioc->ioctl->sem_ioc))
+		if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
 			rc = -ERESTARTSYS;
 	}
 	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
@@ -557,7 +557,7 @@
 	else
 		ret = -EINVAL;
 
-	up(&iocp->ioctl->sem_ioc);
+	mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
 	return ret;
 }
@@ -2619,7 +2619,7 @@
 
 	ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
 
-	up(&iocp->ioctl->sem_ioc);
+	mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
 	return ret;
 }
@@ -2673,7 +2673,7 @@
 	 */
 	ret = mptctl_do_mpt_command (karg, &uarg->MF);
 
-	up(&iocp->ioctl->sem_ioc);
+	mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
 	return ret;
 }
@@ -2743,7 +2743,7 @@
 	memset(mem, 0, sz);
 	ioc->ioctl = (MPT_IOCTL *) mem;
 	ioc->ioctl->ioc = ioc;
-	sema_init(&ioc->ioctl->sem_ioc, 1);
+	mutex_init(&ioc->ioctl->ioctl_mutex);
 	return 0;
 
 out_fail:
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index ba61e18..b102c76 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -55,12 +55,14 @@
 #include <linux/reboot.h>	/* notifier code */
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/sort.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include "mptbase.h"
 #include "mptscsih.h"
@@ -79,19 +81,34 @@
 module_param(mpt_pq_filter, int, 0);
 MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
 
+#define MPTFC_DEV_LOSS_TMO (60)
+static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;	/* reasonable default */
+module_param(mptfc_dev_loss_tmo, int, 0);
+MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
+    				     " transport to wait for an rport to "
+				     " return following a device loss event."
+				     "  Default=60.");
+
 static int	mptfcDoneCtx = -1;
 static int	mptfcTaskCtx = -1;
 static int	mptfcInternalCtx = -1; /* Used only for internal commands */
 
+int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
+    void (*done)(struct scsi_cmnd *));
+
+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+static void __devexit mptfc_remove(struct pci_dev *pdev);
+
 static struct scsi_host_template mptfc_driver_template = {
 	.module				= THIS_MODULE,
 	.proc_name			= "mptfc",
 	.proc_info			= mptscsih_proc_info,
 	.name				= "MPT FC Host",
 	.info				= mptscsih_info,
-	.queuecommand			= mptscsih_qcmd,
+	.queuecommand			= mptfc_qcmd,
 	.target_alloc			= mptscsih_target_alloc,
-	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_alloc			= mptfc_slave_alloc,
 	.slave_configure		= mptscsih_slave_configure,
 	.target_destroy			= mptscsih_target_destroy,
 	.slave_destroy			= mptscsih_slave_destroy,
@@ -128,19 +145,478 @@
 		PCI_ANY_ID, PCI_ANY_ID },
 	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
 		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
+		PCI_ANY_ID, PCI_ANY_ID },
 	{0}	/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	mptfc_probe - Installs scsi devices per bus.
- *	@pdev: Pointer to pci_dev structure
- *
- *	Returns 0 for success, non-zero for failure.
- *
+static struct scsi_transport_template *mptfc_transport_template = NULL;
+
+struct fc_function_template mptfc_transport_functions = {
+	.dd_fcrport_size = 8,
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+	.show_host_port_id = 1,
+	.show_rport_supported_classes = 1,
+	.show_starget_node_name = 1,
+	.show_starget_port_name = 1,
+	.show_starget_port_id = 1,
+	.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+};
+
+/* FIXME! values controlling firmware RESCAN event
+ * need to be set low to allow dev_loss_tmo to
+ * work as expected.  Currently, firmware doesn't
+ * notify driver of RESCAN event until some number
+ * of seconds elapse.  This value can be set via
+ * lsiutil.
  */
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	if (timeout > 0)
+		rport->dev_loss_tmo = timeout;
+	else
+		rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}
+
+static int
+mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
+{
+	FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
+	FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
+
+	if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
+		if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
+			return 0;
+		if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
+			return -1;
+		return 1;
+	}
+	if ((*aa)->CurrentBus < (*bb)->CurrentBus)
+		return -1;
+	return 1;
+}
+
+static int
+mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
+	void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	FCDevicePage0_t		*ppage0_alloc, *fc;
+	dma_addr_t		 page0_dma;
+	int			 data_sz;
+	int			 ii;
+
+	FCDevicePage0_t		*p0_array=NULL, *p_p0;
+	FCDevicePage0_t		**pp0_array=NULL, **p_pp0;
+
+	int			 rc = -ENOMEM;
+	U32			 port_id = 0xffffff;
+	int			 num_targ = 0;
+	int			 max_bus = ioc->facts.MaxBuses;
+	int			 max_targ = ioc->facts.MaxDevices;
+
+	if (max_bus == 0 || max_targ == 0)
+		goto out;
+
+	data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
+	p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);
+	if (!p0_array)
+		goto out;
+
+	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
+	p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
+	if (!pp0_array)
+		goto out;
+
+	do {
+		/* Get FC Device Page 0 header */
+		hdr.PageVersion = 0;
+		hdr.PageLength = 0;
+		hdr.PageNumber = 0;
+		hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
+		cfg.cfghdr.hdr = &hdr;
+		cfg.physAddr = -1;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+		cfg.dir = 0;
+		cfg.pageAddr = port_id;
+		cfg.timeout = 0;
+
+		if ((rc = mpt_config(ioc, &cfg)) != 0)
+			break;
+
+		if (hdr.PageLength <= 0)
+			break;
+
+		data_sz = hdr.PageLength * 4;
+		ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
+		    					&page0_dma);
+		rc = -ENOMEM;
+		if (!ppage0_alloc)
+			break;
+
+		cfg.physAddr = page0_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			ppage0_alloc->PortIdentifier =
+				le32_to_cpu(ppage0_alloc->PortIdentifier);
+
+			ppage0_alloc->WWNN.Low =
+				le32_to_cpu(ppage0_alloc->WWNN.Low);
+
+			ppage0_alloc->WWNN.High =
+				le32_to_cpu(ppage0_alloc->WWNN.High);
+
+			ppage0_alloc->WWPN.Low =
+				le32_to_cpu(ppage0_alloc->WWPN.Low);
+
+			ppage0_alloc->WWPN.High =
+				le32_to_cpu(ppage0_alloc->WWPN.High);
+
+			ppage0_alloc->BBCredit =
+				le16_to_cpu(ppage0_alloc->BBCredit);
+
+			ppage0_alloc->MaxRxFrameSize =
+				le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
+
+			port_id = ppage0_alloc->PortIdentifier;
+			num_targ++;
+			*p_p0 = *ppage0_alloc;	/* save data */
+			*p_pp0++ = p_p0++;	/* save addr */
+		}
+		pci_free_consistent(ioc->pcidev, data_sz,
+		    			(u8 *) ppage0_alloc, page0_dma);
+		if (rc != 0)
+			break;
+
+	} while (port_id <= 0xff0000);
+
+	if (num_targ) {
+		/* sort array */
+		if (num_targ > 1)
+			sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
+				mptfc_FcDevPage0_cmp_func, NULL);
+		/* call caller's func for each targ */
+		for (ii = 0; ii < num_targ;  ii++) {
+			fc = *(pp0_array+ii);
+			func(ioc, ioc_port, fc);
+		}
+	}
+
+ out:
+	if (pp0_array)
+		kfree(pp0_array);
+	if (p0_array)
+		kfree(p0_array);
+	return rc;
+}
+
+static int
+mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
+{
+	/* not currently usable */
+	if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
+			  MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
+		return -1;
+
+	if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
+		return -1;
+
+	if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
+		return -1;
+
+	/*
+	 * board data structure already normalized to platform endianness
+	 * shifted to avoid unaligned access on 64 bit architecture
+	 */
+	rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
+	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
+	rid->port_id =   pg0->PortIdentifier;
+	rid->roles = FC_RPORT_ROLE_UNKNOWN;
+	rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+		rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+	return 0;
+}
+
+static void
+mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
+{
+	struct fc_rport_identifiers rport_ids;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info	*ri;
+	int			match = 0;
+	u64			port_name;
+	unsigned long		flags;
+
+	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
+		return;
+
+	/* scan list looking for a match */
+	spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+	list_for_each_entry(ri, &ioc->fc_rports, list) {
+		port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+		if (port_name == rport_ids.port_name) {	/* match */
+			list_move_tail(&ri->list, &ioc->fc_rports);
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {	/* allocate one */
+		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
+		if (!ri)
+			return;
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		list_add_tail(&ri->list, &ioc->fc_rports);
+	}
+
+	ri->pg0 = *pg0;	/* add/update pg0 data */
+	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
+
+	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
+		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
+		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+		rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		if (rport) {
+			if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
+				ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+				ri->vdev = NULL;
+				ri->rport = rport;
+				*((struct mptfc_rport_info **)rport->dd_data) = ri;
+			}
+			rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+			/*
+			 * if already mapped, remap here.  If not mapped,
+			 * slave_alloc will allocate vdev and map
+			 */
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
+				ri->vdev->target_id = ri->pg0.CurrentTargetID;
+				ri->vdev->bus_id = ri->pg0.CurrentBus;
+				ri->vdev->vtarget->target_id = ri->vdev->target_id;
+				ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+			}
+			#ifdef MPT_DEBUG
+			printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+				"rport tid %d, tmo %d\n",
+					ioc->sh->host_no,
+					pg0->PortIdentifier,
+					pg0->WWNN,
+					pg0->WWPN,
+					pg0->CurrentTargetID,
+					ri->rport->scsi_target_id,
+					ri->rport->dev_loss_tmo);
+			#endif
+		} else {
+			list_del(&ri->list);
+			kfree(ri);
+			ri = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+}
+
+/*
+ *	OS entry point to allow host driver to alloc memory
+ *	for each scsi device. Called once per device the bus scan.
+ *	Return non-zero if allocation fails.
+ *	Init memory once per LUN.
+ */
+int
+mptfc_slave_alloc(struct scsi_device *sdev)
+{
+	MPT_SCSI_HOST		*hd;
+	VirtTarget		*vtarget;
+	VirtDevice		*vdev;
+	struct scsi_target	*starget;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info *ri;
+	unsigned long		flags;
+
+
+	rport = starget_to_rport(scsi_target(sdev));
+
+	if (!rport || fc_remote_port_chkready(rport))
+		return -ENXIO;
+
+	hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+
+	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+	if (!vdev) {
+		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+				hd->ioc->name, sizeof(VirtDevice));
+		return -ENOMEM;
+	}
+	memset(vdev, 0, sizeof(VirtDevice));
+
+	spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
+
+	if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
+		spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+		kfree(vdev);
+		return -ENODEV;
+	}
+
+	sdev->hostdata = vdev;
+	starget = scsi_target(sdev);
+	vtarget = starget->hostdata;
+	if (vtarget->num_luns == 0) {
+		vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
+		    		  MPT_TARGET_FLAGS_VALID_INQUIRY;
+		hd->Targets[sdev->id] = vtarget;
+	}
+
+	vtarget->target_id = vdev->target_id;
+	vtarget->bus_id = vdev->bus_id;
+
+	vdev->vtarget = vtarget;
+	vdev->ioc_id = hd->ioc->id;
+	vdev->lun = sdev->lun;
+	vdev->target_id = ri->pg0.CurrentTargetID;
+	vdev->bus_id = ri->pg0.CurrentBus;
+
+	ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+	ri->vdev = vdev;
+
+	spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+
+	vtarget->num_luns++;
+
+#ifdef MPT_DEBUG
+	printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+	        "CurrentTargetID %d, %x %llx %llx\n",
+			sdev->host->host_no,
+			vtarget->num_luns,
+			sdev->id, ri->pg0.CurrentTargetID,
+			ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
+#endif
+
+	return 0;
+}
+
+static int
+mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	struct fc_rport	*rport = starget_to_rport(scsi_target(SCpnt->device));
+	int		err;
+
+	err = fc_remote_port_chkready(rport);
+	if (unlikely(err)) {
+		SCpnt->result = err;
+		done(SCpnt);
+		return 0;
+	}
+	return mptscsih_qcmd(SCpnt,done);
+}
+
+static void
+mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+{
+	unsigned class = 0, cos = 0;
+
+	/* don't know what to do as only one scsi (fc) host was allocated */
+	if (portnum != 0)
+		return;
+
+	class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+		cos |= FC_COS_CLASS1;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+		cos |= FC_COS_CLASS2;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+		cos |= FC_COS_CLASS3;
+
+	fc_host_node_name(ioc->sh) =
+	    	(u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+		    | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+
+	fc_host_port_name(ioc->sh) =
+	    	(u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+		    | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+
+	fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+
+	fc_host_supported_classes(ioc->sh) = cos;
+
+	fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+}
+
+static void
+mptfc_rescan_devices(void *arg)
+{
+	MPT_ADAPTER		*ioc = (MPT_ADAPTER *)arg;
+	int			ii;
+	int			work_to_do;
+	unsigned long		flags;
+	struct mptfc_rport_info *ri;
+
+	do {
+		/* start by tagging all ports as missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		list_for_each_entry(ri, &ioc->fc_rports, list) {
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+				ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/*
+		 * now rescan devices known to adapter,
+		 * will reregister existing rports
+		 */
+		for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+			(void) mptbase_GetFcPortPage0(ioc, ii);
+			mptfc_init_host_attr(ioc,ii);	/* refresh */
+			mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+		}
+
+		/* delete devices still missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		list_for_each_entry(ri, &ioc->fc_rports, list) {
+			/* if newly missing, delete it */
+			if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+					  MPT_RPORT_INFO_FLAGS_MISSING))
+			  == (MPT_RPORT_INFO_FLAGS_REGISTERED |
+			      MPT_RPORT_INFO_FLAGS_MISSING)) {
+
+				ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
+					       MPT_RPORT_INFO_FLAGS_MISSING);
+				fc_remote_port_delete(ri->rport);
+				/*
+				 * remote port not really deleted 'cause
+				 * binding is by WWPN and driver only
+				 * registers FCP_TARGETs
+				 */
+				#ifdef MPT_DEBUG
+				printk ("mptfc_rescan.%d: %llx deleted\n",
+					ioc->sh->host_no, ri->pg0.WWPN);
+				#endif
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/*
+		 * allow multiple passes as target state
+		 * might have changed during scan
+		 */
+		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+		if (ioc->fc_rescan_work_count > 2) 	/* only need one more */
+			ioc->fc_rescan_work_count = 2;
+		work_to_do = --ioc->fc_rescan_work_count;
+		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+	} while (work_to_do);
+}
+
 static int
 mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -148,17 +624,16 @@
 	MPT_SCSI_HOST		*hd;
 	MPT_ADAPTER 		*ioc;
 	unsigned long		 flags;
-	int			 sz, ii;
+	int			 ii;
 	int			 numSGE = 0;
 	int			 scale;
 	int			 ioc_cap;
-	u8			*mem;
 	int			error=0;
 	int			r;
-		
+
 	if ((r = mpt_attach(pdev,id)) != 0)
 		return r;
-	
+
 	ioc = pci_get_drvdata(pdev);
 	ioc->DoneCtx = mptfcDoneCtx;
 	ioc->TaskCtx = mptfcTaskCtx;
@@ -194,7 +669,7 @@
 		printk(MYIOC_s_WARN_FMT
 			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
 			ioc->name, ioc);
-		return 0;
+		return -ENODEV;
 	}
 
 	sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -207,6 +682,8 @@
 		goto out_mptfc_probe;
         }
 
+	INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
+
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 
 	/* Attach the SCSI Host to the IOC structure
@@ -268,36 +745,27 @@
 	/* SCSI needs scsi_cmnd lookup table!
 	 * (with size equal to req_depth*PtrSz!)
 	 */
-	sz = ioc->req_depth * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+	if (!hd->ScsiLookup) {
 		error = -ENOMEM;
 		goto out_mptfc_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-		 ioc->name, hd->ScsiLookup, sz));
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+		 ioc->name, hd->ScsiLookup));
 
 	/* Allocate memory for the device structures.
 	 * A non-Null pointer at an offset
 	 * indicates a device exists.
 	 * max_id = 1 + maximum id (hosts.h)
 	 */
-	sz = sh->max_id * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+	if (!hd->Targets) {
 		error = -ENOMEM;
 		goto out_mptfc_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->Targets = (VirtTarget **) mem;
-
-	dprintk((KERN_INFO
-	  "  vdev @ %p, sz=%d\n", hd->Targets, sz));
+	dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
 
 	/* Clear the TM flags
 	 */
@@ -332,6 +800,7 @@
 	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 
+	sh->transportt = mptfc_transport_template;
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
 		dprintk((KERN_ERR MYNAM
@@ -339,7 +808,11 @@
 		goto out_mptfc_probe;
 	}
 
-	scsi_scan_host(sh);
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		mptfc_init_host_attr(ioc,ii);
+		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+	}
+
 	return 0;
 
 out_mptfc_probe:
@@ -352,7 +825,7 @@
 	.name		= "mptfc",
 	.id_table	= mptfc_pci_table,
 	.probe		= mptfc_probe,
-	.remove		= __devexit_p(mptscsih_remove),
+	.remove		= __devexit_p(mptfc_remove),
 	.shutdown	= mptscsih_shutdown,
 #ifdef CONFIG_PM
 	.suspend	= mptscsih_suspend,
@@ -370,9 +843,20 @@
 static int __init
 mptfc_init(void)
 {
+	int error;
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 
+	/* sanity check module parameter */
+	if (mptfc_dev_loss_tmo == 0)
+		mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
+
+	mptfc_transport_template =
+		fc_attach_transport(&mptfc_transport_functions);
+
+	if (!mptfc_transport_template)
+		return -ENODEV;
+
 	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
 	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
 	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -387,7 +871,33 @@
 		  ": Registered for IOC reset notifications\n"));
 	}
 
-	return pci_register_driver(&mptfc_driver);
+	error = pci_register_driver(&mptfc_driver);
+	if (error) {
+		fc_release_transport(mptfc_transport_template);
+	}
+
+	return error;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptfc_remove - Removed fc infrastructure for devices
+ *	@pdev: Pointer to pci_dev structure
+ *
+ */
+static void __devexit mptfc_remove(struct pci_dev *pdev)
+{
+	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+	struct mptfc_rport_info *p, *n;
+
+	fc_remove_host(ioc->sh);
+
+	list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	mptscsih_remove(pdev);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -400,7 +910,8 @@
 mptfc_exit(void)
 {
 	pci_unregister_driver(&mptfc_driver);
-	
+	fc_release_transport(mptfc_transport_template);
+
 	mpt_reset_deregister(mptfcDoneCtx);
 	dprintk((KERN_INFO MYNAM
 	  ": Deregistered for IOC reset notifications\n"));
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 014085d..73f5952 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -411,14 +411,12 @@
 		goto out;
 	priv->mpt_txfidx_tail = -1;
 
-	priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+	priv->SendCtl = kcalloc(priv->tx_max_out, sizeof(struct BufferControl),
 				GFP_KERNEL);
 	if (priv->SendCtl == NULL)
 		goto out_mpt_txfidx;
-	for (i = 0; i < priv->tx_max_out; i++) {
-		memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+	for (i = 0; i < priv->tx_max_out; i++)
 		priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
-	}
 
 	dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
 
@@ -428,15 +426,13 @@
 		goto out_SendCtl;
 	priv->mpt_rxfidx_tail = -1;
 
-	priv->RcvCtl = kmalloc(priv->max_buckets_out *
-						sizeof(struct BufferControl),
+	priv->RcvCtl = kcalloc(priv->max_buckets_out,
+			       sizeof(struct BufferControl),
 			       GFP_KERNEL);
 	if (priv->RcvCtl == NULL)
 		goto out_mpt_rxfidx;
-	for (i = 0; i < priv->max_buckets_out; i++) {
-		memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+	for (i = 0; i < priv->max_buckets_out; i++)
 		priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
-	}
 
 /**/	dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
 /**/	for (i = 0; i < priv->tx_max_out; i++)
@@ -848,7 +844,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline void
+static void
 mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
 /*
  * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
@@ -870,7 +866,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline int
+static int
 mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
 {
 	struct mpt_lan_priv *priv = dev->priv;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 17e9757e..5a06d8d 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -5,7 +5,7 @@
  *
  *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
- *  Copyright (c) 2005 Dell
+ *  Copyright (c) 2005-2006 Dell
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -86,6 +86,24 @@
 static int	mptsasMgmtCtx = -1;
 
 
+enum mptsas_hotplug_action {
+	MPTSAS_ADD_DEVICE,
+	MPTSAS_DEL_DEVICE,
+};
+
+struct mptsas_hotplug_event {
+	struct work_struct	work;
+	MPT_ADAPTER		*ioc;
+	enum mptsas_hotplug_action event_type;
+	u64			sas_address;
+	u32			channel;
+	u32			id;
+	u32			device_info;
+	u16			handle;
+	u16			parent_handle;
+	u8			phy_id;
+};
+
 /*
  * SAS topology structures
  *
@@ -99,8 +117,8 @@
 	u8	phy_id;		/* phy number of parent device */
 	u8	port_id;	/* sas physical port this device
 				   is assoc'd with */
-	u8	target;		/* logical target id of this device */
-	u8	bus;		/* logical bus number of this device */
+	u8	id;		/* logical target id of this device */
+	u8	channel;	/* logical bus number of this device */
 	u64	sas_address;    /* WWN of this device,
 				   SATA is assigned by HBA,expander */
 	u32	device_info;	/* bitfield detailed info about this device */
@@ -114,6 +132,7 @@
 	u8	programmed_link_rate;	/* programmed max/min phy link rate */
 	struct mptsas_devinfo identify;	/* point to phy device info */
 	struct mptsas_devinfo attached;	/* point to attached device info */
+	struct sas_phy *phy;
 	struct sas_rphy *rphy;
 };
 
@@ -239,13 +258,12 @@
 	struct scsi_target 	*starget;
 	int i;
 
-	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+	vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
 	if (!vdev) {
 		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
 				hd->ioc->name, sizeof(VirtDevice));
 		return -ENOMEM;
 	}
-	memset(vdev, 0, sizeof(VirtDevice));
 	vdev->ioc_id = hd->ioc->id;
 	sdev->hostdata = vdev;
 	starget = scsi_target(sdev);
@@ -256,19 +274,32 @@
 		hd->Targets[sdev->id] = vtarget;
 	}
 
+	/*
+	  RAID volumes placed beyond the last expected port.
+	*/
+	if (sdev->channel == hd->ioc->num_ports) {
+		vdev->target_id = sdev->id;
+		vdev->bus_id = 0;
+		vdev->lun = 0;
+		goto out;
+	}
+
 	rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
+	mutex_lock(&hd->ioc->sas_topology_mutex);
 	list_for_each_entry(p, &hd->ioc->sas_topology, list) {
 		for (i = 0; i < p->num_phys; i++) {
 			if (p->phy_info[i].attached.sas_address ==
 					rphy->identify.sas_address) {
 				vdev->target_id =
-					p->phy_info[i].attached.target;
-				vdev->bus_id = p->phy_info[i].attached.bus;
+					p->phy_info[i].attached.id;
+				vdev->bus_id = p->phy_info[i].attached.channel;
 				vdev->lun = sdev->lun;
+ 	mutex_unlock(&hd->ioc->sas_topology_mutex);
 				goto out;
 			}
 		}
 	}
+	mutex_unlock(&hd->ioc->sas_topology_mutex);
 
 	printk("No matching SAS device found!!\n");
 	kfree(vdev);
@@ -282,6 +313,42 @@
 	return 0;
 }
 
+static void
+mptsas_slave_destroy(struct scsi_device *sdev)
+{
+	struct Scsi_Host *host = sdev->host;
+	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+	struct sas_rphy *rphy;
+	struct mptsas_portinfo *p;
+	int i;
+
+	/*
+	 * Handle hotplug removal case.
+	 * We need to clear out attached data structure.
+	 */
+	rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
+
+	mutex_lock(&hd->ioc->sas_topology_mutex);
+	list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+		for (i = 0; i < p->num_phys; i++) {
+			if (p->phy_info[i].attached.sas_address ==
+					rphy->identify.sas_address) {
+				memset(&p->phy_info[i].attached, 0,
+				    sizeof(struct mptsas_devinfo));
+				p->phy_info[i].rphy = NULL;
+				goto out;
+			}
+		}
+	}
+
+ out:
+	mutex_unlock(&hd->ioc->sas_topology_mutex);
+	/*
+	 * TODO: Issue target reset to flush firmware outstanding commands.
+	 */
+	mptscsih_slave_destroy(sdev);
+}
+
 static struct scsi_host_template mptsas_driver_template = {
 	.module				= THIS_MODULE,
 	.proc_name			= "mptsas",
@@ -293,7 +360,7 @@
 	.slave_alloc			= mptsas_slave_alloc,
 	.slave_configure		= mptscsih_slave_configure,
 	.target_destroy			= mptscsih_target_destroy,
-	.slave_destroy			= mptscsih_slave_destroy,
+	.slave_destroy			= mptsas_slave_destroy,
 	.change_queue_depth 		= mptscsih_change_queue_depth,
 	.eh_abort_handler		= mptscsih_abort,
 	.eh_device_reset_handler	= mptscsih_dev_reset,
@@ -399,7 +466,7 @@
 	if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
 		return -ENXIO;
 
-	if (down_interruptible(&ioc->sas_mgmt.mutex))
+	if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
 		goto out;
 
 	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
@@ -450,7 +517,7 @@
 	error = 0;
 
  out_unlock:
-	up(&ioc->sas_mgmt.mutex);
+	mutex_unlock(&ioc->sas_mgmt.mutex);
  out:
 	return error;
 }
@@ -649,8 +716,8 @@
 	device_info->handle = le16_to_cpu(buffer->DevHandle);
 	device_info->phy_id = buffer->PhyNum;
 	device_info->port_id = buffer->PhysicalPort;
-	device_info->target = buffer->TargetID;
-	device_info->bus = buffer->Bus;
+	device_info->id = buffer->TargetID;
+	device_info->channel = buffer->Bus;
 	memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
 	device_info->sas_address = le64_to_cpu(sas_address);
 	device_info->device_info =
@@ -858,36 +925,36 @@
 static int mptsas_probe_one_phy(struct device *dev,
 		struct mptsas_phyinfo *phy_info, int index, int local)
 {
-	struct sas_phy *port;
+	struct sas_phy *phy;
 	int error;
 
-	port = sas_phy_alloc(dev, index);
-	if (!port)
+	phy = sas_phy_alloc(dev, index);
+	if (!phy)
 		return -ENOMEM;
 
-	port->port_identifier = phy_info->port_id;
-	mptsas_parse_device_info(&port->identify, &phy_info->identify);
+	phy->port_identifier = phy_info->port_id;
+	mptsas_parse_device_info(&phy->identify, &phy_info->identify);
 
 	/*
 	 * Set Negotiated link rate.
 	 */
 	switch (phy_info->negotiated_link_rate) {
 	case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
-		port->negotiated_linkrate = SAS_PHY_DISABLED;
+		phy->negotiated_linkrate = SAS_PHY_DISABLED;
 		break;
 	case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
-		port->negotiated_linkrate = SAS_LINK_RATE_FAILED;
+		phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
 		break;
 	case MPI_SAS_IOUNIT0_RATE_1_5:
-		port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+		phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
 		break;
 	case MPI_SAS_IOUNIT0_RATE_3_0:
-		port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+		phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
 		break;
 	case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
 	case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
 	default:
-		port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+		phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
 		break;
 	}
 
@@ -896,10 +963,10 @@
 	 */
 	switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
 	case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
-		port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+		phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
 		break;
 	case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
-		port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+		phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
 		break;
 	default:
 		break;
@@ -911,10 +978,10 @@
 	switch (phy_info->programmed_link_rate &
 			MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
 	case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
-		port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+		phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
 		break;
 	case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
-		port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+		phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
 		break;
 	default:
 		break;
@@ -925,10 +992,10 @@
 	 */
 	switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
 	case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
-		port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+		phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
 		break;
 	case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
-		port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+		phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
 		break;
 	default:
 		break;
@@ -940,28 +1007,29 @@
 	switch (phy_info->programmed_link_rate &
 			MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
 	case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
-		port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+		phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
 		break;
 	case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
-		port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+		phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
 		break;
 	default:
 		break;
 	}
 
 	if (local)
-		port->local_attached = 1;
+		phy->local_attached = 1;
 
-	error = sas_phy_add(port);
+	error = sas_phy_add(phy);
 	if (error) {
-		sas_phy_free(port);
+		sas_phy_free(phy);
 		return error;
 	}
+	phy_info->phy = phy;
 
 	if (phy_info->attached.handle) {
 		struct sas_rphy *rphy;
 
-		rphy = sas_rphy_alloc(port);
+		rphy = sas_rphy_alloc(phy);
 		if (!rphy)
 			return 0; /* non-fatal: an rphy can be added later */
 
@@ -985,16 +1053,19 @@
 	u32 handle = 0xFFFF;
 	int error = -ENOMEM, i;
 
-	port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
+	port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
 	if (!port_info)
 		goto out;
-	memset(port_info, 0, sizeof(*port_info));
 
 	error = mptsas_sas_io_unit_pg0(ioc, port_info);
 	if (error)
 		goto out_free_port_info;
 
+	ioc->num_ports = port_info->num_phys;
+	mutex_lock(&ioc->sas_topology_mutex);
 	list_add_tail(&port_info->list, &ioc->sas_topology);
+	mutex_unlock(&ioc->sas_topology_mutex);
+
 	for (i = 0; i < port_info->num_phys; i++) {
 		mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
 			(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
@@ -1034,10 +1105,9 @@
 	struct mptsas_portinfo *port_info, *p;
 	int error = -ENOMEM, i, j;
 
-	port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
+	port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
 	if (!port_info)
 		goto out;
-	memset(port_info, 0, sizeof(*port_info));
 
 	error = mptsas_sas_expander_pg0(ioc, port_info,
 		(MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
@@ -1047,7 +1117,10 @@
 
 	*handle = port_info->handle;
 
+	mutex_lock(&ioc->sas_topology_mutex);
 	list_add_tail(&port_info->list, &ioc->sas_topology);
+	mutex_unlock(&ioc->sas_topology_mutex);
+
 	for (i = 0; i < port_info->num_phys; i++) {
 		struct device *parent;
 
@@ -1079,6 +1152,7 @@
 		 * HBA phys.
 		 */
 		parent = &ioc->sh->shost_gendev;
+		mutex_lock(&ioc->sas_topology_mutex);
 		list_for_each_entry(p, &ioc->sas_topology, list) {
 			for (j = 0; j < p->num_phys; j++) {
 				if (port_info->phy_info[i].identify.handle ==
@@ -1086,6 +1160,7 @@
 					parent = &p->phy_info[j].rphy->dev;
 			}
 		}
+		mutex_unlock(&ioc->sas_topology_mutex);
 
 		mptsas_probe_one_phy(parent, &port_info->phy_info[i],
 				     *index, 0);
@@ -1111,6 +1186,211 @@
 		;
 }
 
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
+{
+	struct mptsas_portinfo *port_info;
+	struct mptsas_devinfo device_info;
+	struct mptsas_phyinfo *phy_info = NULL;
+	int i, error;
+
+	/*
+	 * Retrieve the parent sas_address
+	 */
+	error = mptsas_sas_device_pg0(ioc, &device_info,
+		(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+		 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+		parent_handle);
+	if (error) {
+		printk("mptsas: failed to retrieve device page\n");
+		return NULL;
+	}
+
+	/*
+	 * The phy_info structures are never deallocated during lifetime of
+	 * a host, so the code below is safe without additional refcounting.
+	 */
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_for_each_entry(port_info, &ioc->sas_topology, list) {
+		for (i = 0; i < port_info->num_phys; i++) {
+			if (port_info->phy_info[i].identify.sas_address ==
+			    device_info.sas_address &&
+			    port_info->phy_info[i].phy_id == phy_id) {
+				phy_info = &port_info->phy_info[i];
+				break;
+			}
+		}
+	}
+	mutex_unlock(&ioc->sas_topology_mutex);
+
+	return phy_info;
+}
+
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
+{
+	struct mptsas_portinfo *port_info;
+	struct mptsas_phyinfo *phy_info = NULL;
+	int i;
+
+	/*
+	 * The phy_info structures are never deallocated during lifetime of
+	 * a host, so the code below is safe without additional refcounting.
+	 */
+	mutex_lock(&ioc->sas_topology_mutex);
+	list_for_each_entry(port_info, &ioc->sas_topology, list) {
+		for (i = 0; i < port_info->num_phys; i++) {
+			if (port_info->phy_info[i].attached.handle == handle) {
+				phy_info = &port_info->phy_info[i];
+				break;
+			}
+		}
+	}
+	mutex_unlock(&ioc->sas_topology_mutex);
+
+	return phy_info;
+}
+
+static void
+mptsas_hotplug_work(void *arg)
+{
+	struct mptsas_hotplug_event *ev = arg;
+	MPT_ADAPTER *ioc = ev->ioc;
+	struct mptsas_phyinfo *phy_info;
+	struct sas_rphy *rphy;
+	char *ds = NULL;
+
+	if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+		ds = "ssp";
+	if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+		ds = "stp";
+	if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+		ds = "sata";
+
+	switch (ev->event_type) {
+	case MPTSAS_DEL_DEVICE:
+		printk(MYIOC_s_INFO_FMT
+		       "removing %s device, channel %d, id %d, phy %d\n",
+		       ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+		phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle);
+		if (!phy_info) {
+			printk("mptsas: remove event for non-existant PHY.\n");
+			break;
+		}
+
+		if (phy_info->rphy) {
+			sas_rphy_delete(phy_info->rphy);
+			phy_info->rphy = NULL;
+		}
+		break;
+	case MPTSAS_ADD_DEVICE:
+		printk(MYIOC_s_INFO_FMT
+		       "attaching %s device, channel %d, id %d, phy %d\n",
+		       ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+		phy_info = mptsas_find_phyinfo_by_parent(ioc,
+				ev->parent_handle, ev->phy_id);
+		if (!phy_info) {
+			printk("mptsas: add event for non-existant PHY.\n");
+			break;
+		}
+
+		if (phy_info->rphy) {
+			printk("mptsas: trying to add existing device.\n");
+			break;
+		}
+
+		/* fill attached info */
+		phy_info->attached.handle = ev->handle;
+		phy_info->attached.phy_id = ev->phy_id;
+		phy_info->attached.port_id = phy_info->identify.port_id;
+		phy_info->attached.id = ev->id;
+		phy_info->attached.channel = ev->channel;
+		phy_info->attached.sas_address = ev->sas_address;
+		phy_info->attached.device_info = ev->device_info;
+
+		rphy = sas_rphy_alloc(phy_info->phy);
+		if (!rphy)
+			break; /* non-fatal: an rphy can be added later */
+
+		mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
+		if (sas_rphy_add(rphy)) {
+			sas_rphy_free(rphy);
+			break;
+		}
+
+		phy_info->rphy = rphy;
+		break;
+	}
+
+	kfree(ev);
+}
+
+static void
+mptscsih_send_sas_event(MPT_ADAPTER *ioc,
+		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+{
+	struct mptsas_hotplug_event *ev;
+	u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+	__le64 sas_address;
+
+	if ((device_info &
+	     (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+	      MPI_SAS_DEVICE_INFO_STP_TARGET |
+	      MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
+		return;
+
+	if ((sas_event_data->ReasonCode &
+	     (MPI_EVENT_SAS_DEV_STAT_RC_ADDED |
+	      MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING)) == 0)
+		return;
+
+	ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev) {
+		printk(KERN_WARNING "mptsas: lost hotplug event\n");
+		return;
+	}
+
+
+	INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
+	ev->ioc = ioc;
+	ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+	ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle);
+	ev->channel = sas_event_data->Bus;
+	ev->id = sas_event_data->TargetID;
+	ev->phy_id = sas_event_data->PhyNum;
+	memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64));
+	ev->sas_address = le64_to_cpu(sas_address);
+	ev->device_info = device_info;
+
+	if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
+		ev->event_type = MPTSAS_ADD_DEVICE;
+	else
+		ev->event_type = MPTSAS_DEL_DEVICE;
+
+	schedule_work(&ev->work);
+}
+
+static int
+mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
+{
+	u8 event = le32_to_cpu(reply->Event) & 0xFF;
+
+	if (!ioc->sh)
+		return 1;
+
+	switch (event) {
+	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+		mptscsih_send_sas_event(ioc,
+			(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
+		return 1;		/* currently means nothing really */
+
+	default:
+		return mptscsih_event_process(ioc, reply);
+	}
+}
+
 static int
 mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -1118,11 +1398,10 @@
 	MPT_SCSI_HOST		*hd;
 	MPT_ADAPTER 		*ioc;
 	unsigned long		 flags;
-	int			 sz, ii;
+	int			 ii;
 	int			 numSGE = 0;
 	int			 scale;
 	int			 ioc_cap;
-	u8			*mem;
 	int			error=0;
 	int			r;
 
@@ -1203,7 +1482,9 @@
 	sh->unique_id = ioc->id;
 
 	INIT_LIST_HEAD(&ioc->sas_topology);
-	init_MUTEX(&ioc->sas_mgmt.mutex);
+	mutex_init(&ioc->sas_topology_mutex);
+
+	mutex_init(&ioc->sas_mgmt.mutex);
 	init_completion(&ioc->sas_mgmt.done);
 
 	/* Verify that we won't exceed the maximum
@@ -1244,36 +1525,27 @@
 	/* SCSI needs scsi_cmnd lookup table!
 	 * (with size equal to req_depth*PtrSz!)
 	 */
-	sz = ioc->req_depth * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+	if (!hd->ScsiLookup) {
 		error = -ENOMEM;
 		goto out_mptsas_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-		 ioc->name, hd->ScsiLookup, sz));
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+		 ioc->name, hd->ScsiLookup));
 
 	/* Allocate memory for the device structures.
 	 * A non-Null pointer at an offset
 	 * indicates a device exists.
 	 * max_id = 1 + maximum id (hosts.h)
 	 */
-	sz = sh->max_id * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+	if (!hd->Targets) {
 		error = -ENOMEM;
 		goto out_mptsas_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->Targets = (VirtTarget **) mem;
-
-	dprintk((KERN_INFO
-	  "  vtarget @ %p, sz=%d\n", hd->Targets, sz));
+	dprintk((KERN_INFO "  vtarget @ %p\n", hd->Targets));
 
 	/* Clear the TM flags
 	 */
@@ -1324,6 +1596,20 @@
 
 	mptsas_scan_sas_topology(ioc);
 
+	/*
+	  Reporting RAID volumes.
+	*/
+	if (!ioc->raid_data.pIocPg2)
+		return 0;
+	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
+		return 0;
+	for (ii=0;ii<ioc->raid_data.pIocPg2->NumActiveVolumes;ii++) {
+		scsi_add_device(sh,
+			ioc->num_ports,
+			ioc->raid_data.pIocPg2->RaidVolume[ii].VolumeID,
+			0);
+	}
+
 	return 0;
 
 out_mptsas_probe:
@@ -1339,10 +1625,12 @@
 
 	sas_remove_host(ioc->sh);
 
+	mutex_lock(&ioc->sas_topology_mutex);
 	list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
 		list_del(&p->list);
 		kfree(p);
 	}
+	mutex_unlock(&ioc->sas_topology_mutex);
 
 	mptscsih_remove(pdev);
 }
@@ -1393,7 +1681,7 @@
 		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
 	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
 
-	if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
+	if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
 		devtprintk((KERN_INFO MYNAM
 		  ": Registered for IOC event notifications\n"));
 	}
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 93a16fa..cdac557 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -893,6 +893,7 @@
  *		when a lun is disable by mid-layer.
  *		Do NOT access the referenced scsi_cmnd structure or
  *		members. Will cause either a paging or NULL ptr error.
+ *		(BUT, BUT, BUT, the code does reference it! - mdr)
  *      @hd: Pointer to a SCSI HOST structure
  *	@vdevice: per device private data
  *
@@ -2162,10 +2163,9 @@
 {
 	VirtTarget		*vtarget;
 
-	vtarget = kmalloc(sizeof(VirtTarget), GFP_KERNEL);
+	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
 	if (!vtarget)
 		return -ENOMEM;
-	memset(vtarget, 0, sizeof(VirtTarget));
 	starget->hostdata = vtarget;
 	return 0;
 }
@@ -2185,14 +2185,13 @@
 	VirtDevice		*vdev;
 	struct scsi_target 	*starget;
 
-	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+	vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
 	if (!vdev) {
 		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
 				hd->ioc->name, sizeof(VirtDevice));
 		return -ENOMEM;
 	}
 
-	memset(vdev, 0, sizeof(VirtDevice));
 	vdev->ioc_id = hd->ioc->id;
 	vdev->target_id = sdev->id;
 	vdev->bus_id = sdev->channel;
@@ -2559,13 +2558,25 @@
 			hd->cmdPtr = NULL;
 		}
 
-		/* 7. Set flag to force DV and re-read IOC Page 3
+		/* 7. SPI: Set flag to force DV and re-read IOC Page 3
 		 */
 		if (ioc->bus_type == SPI) {
 			ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
 			ddvtprintk(("Set reload IOC Pg3 Flag\n"));
 		}
 
+		/* 7. FC: Rescan for blocked rports which might have returned.
+		 */
+		else if (ioc->bus_type == FC) {
+			int work_count;
+			unsigned long flags;
+
+			spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+			work_count = ++ioc->fc_rescan_work_count;
+			spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+			if (work_count == 1)
+				schedule_work(&ioc->fc_rescan_work);
+		}
 		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
 	}
@@ -2589,6 +2600,8 @@
 {
 	MPT_SCSI_HOST *hd;
 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+	int work_count;
+	unsigned long flags;
 
 	devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 			ioc->name, event));
@@ -2610,11 +2623,18 @@
 		/* FIXME! */
 		break;
 
+	case MPI_EVENT_RESCAN:				/* 06 */
+		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+		work_count = ++ioc->fc_rescan_work_count;
+		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+		if (work_count == 1)
+			schedule_work(&ioc->fc_rescan_work);
+		break;
+
 		/*
 		 *  CHECKME! Don't think we need to do
 		 *  anything for these, but...
 		 */
-	case MPI_EVENT_RESCAN:				/* 06 */
 	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
 	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
 		/*
@@ -3954,8 +3974,6 @@
 
 /* Search IOC page 3 to determine if this is hidden physical disk
  */
-/* Search IOC page 3 to determine if this is hidden physical disk
- */
 static int
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
 {
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index ce332a6..7dce292 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -158,11 +158,10 @@
 	MPT_SCSI_HOST		*hd;
 	MPT_ADAPTER 		*ioc;
 	unsigned long		 flags;
-	int			 sz, ii;
+	int			 ii;
 	int			 numSGE = 0;
 	int			 scale;
 	int			 ioc_cap;
-	u8			*mem;
 	int			error=0;
 	int			r;
 
@@ -288,36 +287,27 @@
 	/* SCSI needs scsi_cmnd lookup table!
 	 * (with size equal to req_depth*PtrSz!)
 	 */
-	sz = ioc->req_depth * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+	if (!hd->ScsiLookup) {
 		error = -ENOMEM;
 		goto out_mptspi_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-		 ioc->name, hd->ScsiLookup, sz));
+	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+		 ioc->name, hd->ScsiLookup));
 
 	/* Allocate memory for the device structures.
 	 * A non-Null pointer at an offset
 	 * indicates a device exists.
 	 * max_id = 1 + maximum id (hosts.h)
 	 */
-	sz = sh->max_id * sizeof(void *);
-	mem = kmalloc(sz, GFP_ATOMIC);
-	if (mem == NULL) {
+	hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+	if (!hd->Targets) {
 		error = -ENOMEM;
 		goto out_mptspi_probe;
 	}
 
-	memset(mem, 0, sz);
-	hd->Targets = (VirtTarget **) mem;
-
-	dprintk((KERN_INFO
-	  "  vdev @ %p, sz=%d\n", hd->Targets, sz));
+	dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
 
 	/* Clear the TM flags
 	 */
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index c5b656c..d698d77 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -88,11 +88,6 @@
 	struct device *dev = &pdev->dev;
 	int i;
 
-	if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
-		printk(KERN_ERR "%s: device already claimed\n", c->name);
-		return -ENODEV;
-	}
-
 	for (i = 0; i < 6; i++) {
 		/* Skip I/O spaces */
 		if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
@@ -319,6 +314,11 @@
 		return rc;
 	}
 
+	if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+		printk(KERN_ERR "i2o: device already claimed\n");
+		return -ENODEV;
+	}
+
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
 		       pci_name(pdev));
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 55ba230..75f401d 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -77,6 +77,8 @@
 static struct bus_type mcp_bus_type = {
 	.name		= "mcp",
 	.match		= mcp_bus_match,
+	.probe		= mcp_bus_probe,
+	.remove		= mcp_bus_remove,
 	.suspend	= mcp_bus_suspend,
 	.resume		= mcp_bus_resume,
 };
@@ -227,8 +229,6 @@
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
 	mcpdrv->drv.bus = &mcp_bus_type;
-	mcpdrv->drv.probe = mcp_bus_probe;
-	mcpdrv->drv.remove = mcp_bus_remove;
 	return driver_register(&mcpdrv->drv);
 }
 EXPORT_SYMBOL(mcp_driver_register);
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 9b7c37e..5b014c3 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -462,9 +462,10 @@
 	if (err)
 		goto out;
 
-	printk(KERN_INFO "%s: %s %s %luKiB %s\n",
+	printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		get_capacity(md->disk) >> 1, md->read_only ? "(ro)" : "");
+		(unsigned long long)(get_capacity(md->disk) >> 1),
+		md->read_only ? "(ro)" : "");
 
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index ec70166..a2a35fd 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -136,17 +136,7 @@
 	return ret;
 }
 
-static struct bus_type mmc_bus_type = {
-	.name		= "mmc",
-	.dev_attrs	= mmc_dev_attrs,
-	.match		= mmc_bus_match,
-	.uevent		= mmc_bus_uevent,
-	.suspend	= mmc_bus_suspend,
-	.resume		= mmc_bus_resume,
-};
-
-
-static int mmc_drv_probe(struct device *dev)
+static int mmc_bus_probe(struct device *dev)
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = dev_to_mmc_card(dev);
@@ -154,7 +144,7 @@
 	return drv->probe(card);
 }
 
-static int mmc_drv_remove(struct device *dev)
+static int mmc_bus_remove(struct device *dev)
 {
 	struct mmc_driver *drv = to_mmc_driver(dev->driver);
 	struct mmc_card *card = dev_to_mmc_card(dev);
@@ -164,6 +154,16 @@
 	return 0;
 }
 
+static struct bus_type mmc_bus_type = {
+	.name		= "mmc",
+	.dev_attrs	= mmc_dev_attrs,
+	.match		= mmc_bus_match,
+	.uevent		= mmc_bus_uevent,
+	.probe		= mmc_bus_probe,
+	.remove		= mmc_bus_remove,
+	.suspend	= mmc_bus_suspend,
+	.resume		= mmc_bus_resume,
+};
 
 /**
  *	mmc_register_driver - register a media driver
@@ -172,8 +172,6 @@
 int mmc_register_driver(struct mmc_driver *drv)
 {
 	drv->drv.bus = &mmc_bus_type;
-	drv->drv.probe = mmc_drv_probe;
-	drv->drv.remove = mmc_drv_remove;
 	return driver_register(&drv->drv);
 }
 
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 9a2aa40..5038e90 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -47,6 +47,22 @@
 	  accelerator.  Say Y here if you have a DECstation 5000/2x0 or a
 	  DECsystem 5900 equipped with such a module.
 
+config MTD_DATAFLASH
+	tristate "Support for AT45xxx DataFlash"
+	depends on MTD && SPI_MASTER && EXPERIMENTAL
+	help
+	  This enables access to AT45xxx DataFlash chips, using SPI.
+	  Sometimes DataFlash chips are packaged inside MMC-format
+	  cards; at this writing, the MMC stack won't handle those.
+
+config MTD_M25P80
+	tristate "Support for M25 SPI Flash"
+	depends on MTD && SPI_MASTER && EXPERIMENTAL
+	help
+	  This enables access to ST M25P80 and similar SPI flash chips,
+	  used for program and data storage.  Set up your spi devices
+	  with the right board-specific platform data.
+
 config MTD_SLRAM
 	tristate "Uncached system RAM"
 	depends on MTD
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index e38db34..7c5ed21 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -23,3 +23,5 @@
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLKMTD)	+= blkmtd.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
+obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
+obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index be5e88b..e4345cf 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -138,7 +138,7 @@
    bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+static int DoC_Command(struct DiskOnChip *doc, unsigned char command,
 			      unsigned char xtraflags)
 {
 	void __iomem *docptr = doc->virtadr;
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index fcb28a6..681a9c7 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -103,7 +103,7 @@
    with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-static inline void DoC_Command(void __iomem * docptr, unsigned char command,
+static void DoC_Command(void __iomem * docptr, unsigned char command,
 			       unsigned char xtraflags)
 {
 	/* Assert the CLE (Command Latch Enable) line to the flash chip */
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 0595cc7..5f57f29 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -118,7 +118,7 @@
 /* DoC_Command: Send a flash command to the flash chip through the Flash
  * command register. Need 2 Write Pipeline Terminates to complete send.
  */
-static inline void DoC_Command(void __iomem * docptr, unsigned char command,
+static void DoC_Command(void __iomem * docptr, unsigned char command,
 			       unsigned char xtraflags)
 {
 	WriteDOC(command, docptr, Mplus_FlashCmd);
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
new file mode 100644
index 0000000..d5f2408
--- /dev/null
+++ b/drivers/mtd/devices/m25p80.c
@@ -0,0 +1,582 @@
+/*
+ * MTD SPI driver for ST M25Pxx flash chips
+ *
+ * Author: Mike Lavender, mike@steroidmicros.com
+ *
+ * Copyright (c) 2005, Intec Automation Inc.
+ *
+ * Some parts are based on lart.c by Abraham Van Der Merwe
+ *
+ * Cleaned up and generalized based on mtd_dataflash.c
+ *
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <asm/semaphore.h>
+
+
+/* NOTE: AT 25F and SST 25LF series are very similar,
+ * but commands for sector erase and chip id differ...
+ */
+
+#define FLASH_PAGESIZE		256
+
+/* Flash opcodes. */
+#define	OPCODE_WREN		6	/* Write enable */
+#define	OPCODE_RDSR		5	/* Read status register */
+#define	OPCODE_READ		3	/* Read data bytes */
+#define	OPCODE_PP		2	/* Page program */
+#define	OPCODE_SE		0xd8	/* Sector erase */
+#define	OPCODE_RES		0xab	/* Read Electronic Signature */
+#define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
+
+/* Status Register bits. */
+#define	SR_WIP			1	/* Write in progress */
+#define	SR_WEL			2	/* Write enable latch */
+#define	SR_BP0			4	/* Block protect 0 */
+#define	SR_BP1			8	/* Block protect 1 */
+#define	SR_BP2			0x10	/* Block protect 2 */
+#define	SR_SRWD			0x80	/* SR write protect */
+
+/* Define max times to check status register before we give up. */
+#define	MAX_READY_WAIT_COUNT	100000
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+#define	mtd_has_partitions()	(1)
+#else
+#define	mtd_has_partitions()	(0)
+#endif
+
+/****************************************************************************/
+
+struct m25p {
+	struct spi_device	*spi;
+	struct semaphore	lock;
+	struct mtd_info		mtd;
+	unsigned		partitioned;
+	u8			command[4];
+};
+
+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct m25p, mtd);
+}
+
+/****************************************************************************/
+
+/*
+ * Internal helper functions
+ */
+
+/*
+ * Read the status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+ */
+static int read_sr(struct m25p *flash)
+{
+	ssize_t retval;
+	u8 code = OPCODE_RDSR;
+	u8 val;
+
+	retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+
+	if (retval < 0) {
+		dev_err(&flash->spi->dev, "error %d reading SR\n",
+				(int) retval);
+		return retval;
+	}
+
+	return val;
+}
+
+
+/*
+ * Set write enable latch with Write Enable command.
+ * Returns negative if error occurred.
+ */
+static inline int write_enable(struct m25p *flash)
+{
+	u8	code = OPCODE_WREN;
+
+	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+}
+
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+ */
+static int wait_till_ready(struct m25p *flash)
+{
+	int count;
+	int sr;
+
+	/* one chip guarantees max 5 msec wait here after page writes,
+	 * but potentially three seconds (!) after page erase.
+	 */
+	for (count = 0; count < MAX_READY_WAIT_COUNT; count++) {
+		if ((sr = read_sr(flash)) < 0)
+			break;
+		else if (!(sr & SR_WIP))
+			return 0;
+
+		/* REVISIT sometimes sleeping would be best */
+	}
+
+	return 1;
+}
+
+
+/*
+ * Erase one sector of flash memory at offset ``offset'' which is any
+ * address within the sector which should be erased.
+ *
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int erase_sector(struct m25p *flash, u32 offset)
+{
+	DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id,
+			__FUNCTION__, offset);
+
+	/* Wait until finished previous write command. */
+	if (wait_till_ready(flash))
+		return 1;
+
+	/* Send write enable, then erase commands. */
+	write_enable(flash);
+
+	/* Set up command buffer. */
+	flash->command[0] = OPCODE_SE;
+	flash->command[1] = offset >> 16;
+	flash->command[2] = offset >> 8;
+	flash->command[3] = offset;
+
+	spi_write(flash->spi, flash->command, sizeof(flash->command));
+
+	return 0;
+}
+
+/****************************************************************************/
+
+/*
+ * MTD implementation
+ */
+
+/*
+ * Erase an address range on the flash chip.  The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	u32 addr,len;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+			flash->spi->dev.bus_id, __FUNCTION__, "at",
+			(u32)instr->addr, instr->len);
+
+	/* sanity checks */
+	if (instr->addr + instr->len > flash->mtd.size)
+		return -EINVAL;
+	if ((instr->addr % mtd->erasesize) != 0
+			|| (instr->len % mtd->erasesize) != 0) {
+		return -EINVAL;
+	}
+
+	addr = instr->addr;
+	len = instr->len;
+
+  	down(&flash->lock);
+
+	/* now erase those sectors */
+	while (len) {
+		if (erase_sector(flash, addr)) {
+			instr->state = MTD_ERASE_FAILED;
+			up(&flash->lock);
+			return -EIO;
+		}
+
+		addr += mtd->erasesize;
+		len -= mtd->erasesize;
+	}
+
+  	up(&flash->lock);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return 0;
+}
+
+/*
+ * Read an address range from the flash chip.  The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	struct spi_transfer t[2];
+	struct spi_message m;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+			flash->spi->dev.bus_id, __FUNCTION__, "from",
+			(u32)from, len);
+
+	/* sanity checks */
+	if (!len)
+		return 0;
+
+	if (from + len > flash->mtd.size)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, (sizeof t));
+
+	t[0].tx_buf = flash->command;
+	t[0].len = sizeof(flash->command);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	t[1].len = len;
+	spi_message_add_tail(&t[1], &m);
+
+	/* Byte count starts at zero. */
+	if (retlen)
+		*retlen = 0;
+
+	down(&flash->lock);
+
+	/* Wait till previous write/erase is done. */
+	if (wait_till_ready(flash)) {
+		/* REVISIT status return?? */
+		up(&flash->lock);
+		return 1;
+	}
+
+	/* NOTE:  OPCODE_FAST_READ (if available) is faster... */
+
+	/* Set up the write data buffer. */
+	flash->command[0] = OPCODE_READ;
+	flash->command[1] = from >> 16;
+	flash->command[2] = from >> 8;
+	flash->command[3] = from;
+
+	spi_sync(flash->spi, &m);
+
+	*retlen = m.actual_length - sizeof(flash->command);
+
+  	up(&flash->lock);
+
+	return 0;
+}
+
+/*
+ * Write an address range to the flash chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
+	size_t *retlen, const u_char *buf)
+{
+	struct m25p *flash = mtd_to_m25p(mtd);
+	u32 page_offset, page_size;
+	struct spi_transfer t[2];
+	struct spi_message m;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+			flash->spi->dev.bus_id, __FUNCTION__, "to",
+			(u32)to, len);
+
+	if (retlen)
+		*retlen = 0;
+
+	/* sanity checks */
+	if (!len)
+		return(0);
+
+	if (to + len > flash->mtd.size)
+		return -EINVAL;
+
+	spi_message_init(&m);
+	memset(t, 0, (sizeof t));
+
+	t[0].tx_buf = flash->command;
+	t[0].len = sizeof(flash->command);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = buf;
+	spi_message_add_tail(&t[1], &m);
+
+  	down(&flash->lock);
+
+	/* Wait until finished previous write command. */
+	if (wait_till_ready(flash))
+		return 1;
+
+	write_enable(flash);
+
+	/* Set up the opcode in the write buffer. */
+	flash->command[0] = OPCODE_PP;
+	flash->command[1] = to >> 16;
+	flash->command[2] = to >> 8;
+	flash->command[3] = to;
+
+	/* what page do we start with? */
+	page_offset = to % FLASH_PAGESIZE;
+
+	/* do all the bytes fit onto one page? */
+	if (page_offset + len <= FLASH_PAGESIZE) {
+		t[1].len = len;
+
+		spi_sync(flash->spi, &m);
+
+		*retlen = m.actual_length - sizeof(flash->command);
+	} else {
+		u32 i;
+
+		/* the size of data remaining on the first page */
+		page_size = FLASH_PAGESIZE - page_offset;
+
+		t[1].len = page_size;
+		spi_sync(flash->spi, &m);
+
+		*retlen = m.actual_length - sizeof(flash->command);
+
+		/* write everything in PAGESIZE chunks */
+		for (i = page_size; i < len; i += page_size) {
+			page_size = len - i;
+			if (page_size > FLASH_PAGESIZE)
+				page_size = FLASH_PAGESIZE;
+
+			/* write the next page to flash */
+			flash->command[1] = (to + i) >> 16;
+			flash->command[2] = (to + i) >> 8;
+			flash->command[3] = (to + i);
+
+			t[1].tx_buf = buf + i;
+			t[1].len = page_size;
+
+			wait_till_ready(flash);
+
+			write_enable(flash);
+
+			spi_sync(flash->spi, &m);
+
+			if (retlen)
+				*retlen += m.actual_length
+					- sizeof(flash->command);
+	        }
+ 	}
+
+	up(&flash->lock);
+
+	return 0;
+}
+
+
+/****************************************************************************/
+
+/*
+ * SPI device driver setup and teardown
+ */
+
+struct flash_info {
+	char		*name;
+	u8		id;
+	u16		jedec_id;
+	unsigned	sector_size;
+	unsigned	n_sectors;
+};
+
+static struct flash_info __devinitdata m25p_data [] = {
+	/* REVISIT: fill in JEDEC ids, for parts that have them */
+	{ "m25p05", 0x05, 0x0000, 32 * 1024, 2 },
+	{ "m25p10", 0x10, 0x0000, 32 * 1024, 4 },
+	{ "m25p20", 0x11, 0x0000, 64 * 1024, 4 },
+	{ "m25p40", 0x12, 0x0000, 64 * 1024, 8 },
+	{ "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
+	{ "m25p16", 0x14, 0x0000, 64 * 1024, 32 },
+	{ "m25p32", 0x15, 0x0000, 64 * 1024, 64 },
+	{ "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
+};
+
+/*
+ * board specific setup should have ensured the SPI clock used here
+ * matches what the READ command supports, at least until this driver
+ * understands FAST_READ (for clocks over 25 MHz).
+ */
+static int __devinit m25p_probe(struct spi_device *spi)
+{
+	struct flash_platform_data	*data;
+	struct m25p			*flash;
+	struct flash_info		*info;
+	unsigned			i;
+
+	/* Platform data helps sort out which chip type we have, as
+	 * well as how this board partitions it.
+	 */
+	data = spi->dev.platform_data;
+	if (!data || !data->type) {
+		/* FIXME some chips can identify themselves with RES
+		 * or JEDEC get-id commands.  Try them ...
+		 */
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
+				flash->spi->dev.bus_id);
+		return -ENODEV;
+	}
+
+	for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) {
+		if (strcmp(data->type, info->name) == 0)
+			break;
+	}
+	if (i == ARRAY_SIZE(m25p_data)) {
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
+				flash->spi->dev.bus_id, data->type);
+		return -ENODEV;
+	}
+
+	flash = kzalloc(sizeof *flash, SLAB_KERNEL);
+	if (!flash)
+		return -ENOMEM;
+
+	flash->spi = spi;
+	init_MUTEX(&flash->lock);
+	dev_set_drvdata(&spi->dev, flash);
+
+	if (data->name)
+		flash->mtd.name = data->name;
+	else
+		flash->mtd.name = spi->dev.bus_id;
+
+	flash->mtd.type = MTD_NORFLASH;
+	flash->mtd.flags = MTD_CAP_NORFLASH;
+	flash->mtd.size = info->sector_size * info->n_sectors;
+	flash->mtd.erasesize = info->sector_size;
+	flash->mtd.erase = m25p80_erase;
+	flash->mtd.read = m25p80_read;
+	flash->mtd.write = m25p80_write;
+
+	dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
+			flash->mtd.size / 1024);
+
+	DEBUG(MTD_DEBUG_LEVEL2,
+		"mtd .name = %s, .size = 0x%.8x (%uM) "
+			".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n",
+		flash->mtd.name,
+		flash->mtd.size, flash->mtd.size / (1024*1024),
+		flash->mtd.erasesize, flash->mtd.erasesize / 1024,
+		flash->mtd.numeraseregions);
+
+	if (flash->mtd.numeraseregions)
+		for (i = 0; i < flash->mtd.numeraseregions; i++)
+			DEBUG(MTD_DEBUG_LEVEL2,
+				"mtd.eraseregions[%d] = { .offset = 0x%.8x, "
+				".erasesize = 0x%.8x (%uK), "
+				".numblocks = %d }\n",
+				i, flash->mtd.eraseregions[i].offset,
+				flash->mtd.eraseregions[i].erasesize,
+				flash->mtd.eraseregions[i].erasesize / 1024,
+				flash->mtd.eraseregions[i].numblocks);
+
+
+	/* partitions should match sector boundaries; and it may be good to
+	 * use readonly partitions for writeprotected sectors (BP2..BP0).
+	 */
+	if (mtd_has_partitions()) {
+		struct mtd_partition	*parts = NULL;
+		int			nr_parts = 0;
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+		nr_parts = parse_mtd_partitions(&flash->mtd,
+				part_probes, &parts, 0);
+#endif
+
+		if (nr_parts <= 0 && data && data->parts) {
+			parts = data->parts;
+			nr_parts = data->nr_parts;
+		}
+
+		if (nr_parts > 0) {
+			for (i = 0; i < data->nr_parts; i++) {
+				DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
+					"{.name = %s, .offset = 0x%.8x, "
+						".size = 0x%.8x (%uK) }\n",
+					i, data->parts[i].name,
+					data->parts[i].offset,
+					data->parts[i].size,
+					data->parts[i].size / 1024);
+			}
+			flash->partitioned = 1;
+			return add_mtd_partitions(&flash->mtd, parts, nr_parts);
+		}
+	} else if (data->nr_parts)
+		dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
+				data->nr_parts, data->name);
+
+	return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
+}
+
+
+static int __devexit m25p_remove(struct spi_device *spi)
+{
+	struct m25p	*flash = dev_get_drvdata(&spi->dev);
+	int		status;
+
+	/* Clean up MTD stuff. */
+	if (mtd_has_partitions() && flash->partitioned)
+		status = del_mtd_partitions(&flash->mtd);
+	else
+		status = del_mtd_device(&flash->mtd);
+	if (status == 0)
+		kfree(flash);
+	return 0;
+}
+
+
+static struct spi_driver m25p80_driver = {
+	.driver = {
+		.name	= "m25p80",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= m25p_probe,
+	.remove	= __devexit_p(m25p_remove),
+};
+
+
+static int m25p80_init(void)
+{
+	return spi_register_driver(&m25p80_driver);
+}
+
+
+static void m25p80_exit(void)
+{
+	spi_unregister_driver(&m25p80_driver);
+}
+
+
+module_init(m25p80_init);
+module_exit(m25p80_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Lavender");
+MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
new file mode 100644
index 0000000..155737e
--- /dev/null
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -0,0 +1,629 @@
+/*
+ * Atmel AT45xxx DataFlash MTD driver for lightweight SPI framework
+ *
+ * Largely derived from at91_dataflash.c:
+ *  Copyright (C) 2003-2005 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+
+/*
+ * DataFlash is a kind of SPI flash.  Most AT45 chips have two buffers in
+ * each chip, which may be used for double buffered I/O; but this driver
+ * doesn't (yet) use these for any kind of i/o overlap or prefetching.
+ *
+ * Sometimes DataFlash is packaged in MMC-format cards, although the
+ * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash
+ * protocols during enumeration.
+ */
+
+#define CONFIG_DATAFLASH_WRITE_VERIFY
+
+/* reads can bypass the buffers */
+#define OP_READ_CONTINUOUS	0xE8
+#define OP_READ_PAGE		0xD2
+
+/* group B requests can run even while status reports "busy" */
+#define OP_READ_STATUS		0xD7	/* group B */
+
+/* move data between host and buffer */
+#define OP_READ_BUFFER1		0xD4	/* group B */
+#define OP_READ_BUFFER2		0xD6	/* group B */
+#define OP_WRITE_BUFFER1	0x84	/* group B */
+#define OP_WRITE_BUFFER2	0x87	/* group B */
+
+/* erasing flash */
+#define OP_ERASE_PAGE		0x81
+#define OP_ERASE_BLOCK		0x50
+
+/* move data between buffer and flash */
+#define OP_TRANSFER_BUF1	0x53
+#define OP_TRANSFER_BUF2	0x55
+#define OP_MREAD_BUFFER1	0xD4
+#define OP_MREAD_BUFFER2	0xD6
+#define OP_MWERASE_BUFFER1	0x83
+#define OP_MWERASE_BUFFER2	0x86
+#define OP_MWRITE_BUFFER1	0x88	/* sector must be pre-erased */
+#define OP_MWRITE_BUFFER2	0x89	/* sector must be pre-erased */
+
+/* write to buffer, then write-erase to flash */
+#define OP_PROGRAM_VIA_BUF1	0x82
+#define OP_PROGRAM_VIA_BUF2	0x85
+
+/* compare buffer to flash */
+#define OP_COMPARE_BUF1		0x60
+#define OP_COMPARE_BUF2		0x61
+
+/* read flash to buffer, then write-erase to flash */
+#define OP_REWRITE_VIA_BUF1	0x58
+#define OP_REWRITE_VIA_BUF2	0x59
+
+/* newer chips report JEDEC manufacturer and device IDs; chip
+ * serial number and OTP bits; and per-sector writeprotect.
+ */
+#define OP_READ_ID		0x9F
+#define OP_READ_SECURITY	0x77
+#define OP_WRITE_SECURITY	0x9A	/* OTP bits */
+
+
+struct dataflash {
+	u8			command[4];
+	char			name[24];
+
+	unsigned		partitioned:1;
+
+	unsigned short		page_offset;	/* offset in flash address */
+	unsigned int		page_size;	/* of bytes per page */
+
+	struct semaphore	lock;
+	struct spi_device	*spi;
+
+	struct mtd_info		mtd;
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+#define	mtd_has_partitions()	(1)
+#else
+#define	mtd_has_partitions()	(0)
+#endif
+
+/* ......................................................................... */
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static inline int dataflash_status(struct spi_device *spi)
+{
+	/* NOTE:  at45db321c over 25 MHz wants to write
+	 * a dummy byte after the opcode...
+	 */
+	return spi_w8r8(spi, OP_READ_STATUS);
+}
+
+/*
+ * Poll the DataFlash device until it is READY.
+ * This usually takes 5-20 msec or so; more for sector erase.
+ */
+static int dataflash_waitready(struct spi_device *spi)
+{
+	int	status;
+
+	for (;;) {
+		status = dataflash_status(spi);
+		if (status < 0) {
+			DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n",
+					spi->dev.bus_id, status);
+			status = 0;
+		}
+
+		if (status & (1 << 7))	/* RDY/nBSY */
+			return status;
+
+		msleep(3);
+	}
+}
+
+/* ......................................................................... */
+
+/*
+ * Erase pages of flash.
+ */
+static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct dataflash	*priv = (struct dataflash *)mtd->priv;
+	struct spi_device	*spi = priv->spi;
+	struct spi_transfer	x = { .tx_dma = 0, };
+	struct spi_message	msg;
+	unsigned		blocksize = priv->page_size << 3;
+	u8			*command;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n",
+			spi->dev.bus_id,
+			instr->addr, instr->len);
+
+	/* Sanity checks */
+	if ((instr->addr + instr->len) > mtd->size
+			|| (instr->len % priv->page_size) != 0
+			|| (instr->addr % priv->page_size) != 0)
+		return -EINVAL;
+
+	spi_message_init(&msg);
+
+	x.tx_buf = command = priv->command;
+	x.len = 4;
+	spi_message_add_tail(&x, &msg);
+
+	down(&priv->lock);
+	while (instr->len > 0) {
+		unsigned int	pageaddr;
+		int		status;
+		int		do_block;
+
+		/* Calculate flash page address; use block erase (for speed) if
+		 * we're at a block boundary and need to erase the whole block.
+		 */
+		pageaddr = instr->addr / priv->page_size;
+		do_block = (pageaddr & 0x7) == 0 && instr->len <= blocksize;
+		pageaddr = pageaddr << priv->page_offset;
+
+		command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
+		command[1] = (u8)(pageaddr >> 16);
+		command[2] = (u8)(pageaddr >> 8);
+		command[3] = 0;
+
+		DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n",
+			do_block ? "block" : "page",
+			command[0], command[1], command[2], command[3],
+			pageaddr);
+
+		status = spi_sync(spi, &msg);
+		(void) dataflash_waitready(spi);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s: erase %x, err %d\n",
+				spi->dev.bus_id, pageaddr, status);
+			/* REVISIT:  can retry instr->retries times; or
+			 * giveup and instr->fail_addr = instr->addr;
+			 */
+			continue;
+		}
+
+		if (do_block) {
+			instr->addr += blocksize;
+			instr->len -= blocksize;
+		} else {
+			instr->addr += priv->page_size;
+			instr->len -= priv->page_size;
+		}
+	}
+	up(&priv->lock);
+
+	/* Inform MTD subsystem that erase is complete */
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ *   from   : Start offset in flash device
+ *   len    : Amount to read
+ *   retlen : About of data actually read
+ *   buf    : Buffer containing the data
+ */
+static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
+			       size_t *retlen, u_char *buf)
+{
+	struct dataflash	*priv = (struct dataflash *)mtd->priv;
+	struct spi_transfer	x[2] = { { .tx_dma = 0, }, };
+	struct spi_message	msg;
+	unsigned int		addr;
+	u8			*command;
+	int			status;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n",
+		priv->spi->dev.bus_id, (unsigned)from, (unsigned)(from + len));
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	/* Calculate flash page/byte address */
+	addr = (((unsigned)from / priv->page_size) << priv->page_offset)
+		+ ((unsigned)from % priv->page_size);
+
+	command = priv->command;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n",
+		command[0], command[1], command[2], command[3]);
+
+	spi_message_init(&msg);
+
+	x[0].tx_buf = command;
+	x[0].len = 8;
+	spi_message_add_tail(&x[0], &msg);
+
+	x[1].rx_buf = buf;
+	x[1].len = len;
+	spi_message_add_tail(&x[1], &msg);
+
+	down(&priv->lock);
+
+	/* Continuous read, max clock = f(car) which may be less than
+	 * the peak rate available.  Some chips support commands with
+	 * fewer "don't care" bytes.  Both buffers stay unchanged.
+	 */
+	command[0] = OP_READ_CONTINUOUS;
+	command[1] = (u8)(addr >> 16);
+	command[2] = (u8)(addr >> 8);
+	command[3] = (u8)(addr >> 0);
+	/* plus 4 "don't care" bytes */
+
+	status = spi_sync(priv->spi, &msg);
+	up(&priv->lock);
+
+	if (status >= 0) {
+		*retlen = msg.actual_length - 8;
+		status = 0;
+	} else
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n",
+			priv->spi->dev.bus_id,
+			(unsigned)from, (unsigned)(from + len),
+			status);
+	return status;
+}
+
+/*
+ * Write to the DataFlash device.
+ *   to     : Start offset in flash device
+ *   len    : Amount to write
+ *   retlen : Amount of data actually written
+ *   buf    : Buffer containing the data
+ */
+static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
+				size_t * retlen, const u_char * buf)
+{
+	struct dataflash	*priv = (struct dataflash *)mtd->priv;
+	struct spi_device	*spi = priv->spi;
+	struct spi_transfer	x[2] = { { .tx_dma = 0, }, };
+	struct spi_message	msg;
+	unsigned int		pageaddr, addr, offset, writelen;
+	size_t			remaining = len;
+	u_char			*writebuf = (u_char *) buf;
+	int			status = -EINVAL;
+	u8			*command;
+
+	DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n",
+		spi->dev.bus_id, (unsigned)to, (unsigned)(to + len));
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if ((to + len) > mtd->size)
+		return -EINVAL;
+
+	spi_message_init(&msg);
+
+	x[0].tx_buf = command = priv->command;
+	x[0].len = 4;
+	spi_message_add_tail(&x[0], &msg);
+
+	pageaddr = ((unsigned)to / priv->page_size);
+	offset = ((unsigned)to % priv->page_size);
+	if (offset + len > priv->page_size)
+		writelen = priv->page_size - offset;
+	else
+		writelen = len;
+
+	down(&priv->lock);
+	while (remaining > 0) {
+		DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
+			pageaddr, offset, writelen);
+
+		/* REVISIT:
+		 * (a) each page in a sector must be rewritten at least
+		 *     once every 10K sibling erase/program operations.
+		 * (b) for pages that are already erased, we could
+		 *     use WRITE+MWRITE not PROGRAM for ~30% speedup.
+		 * (c) WRITE to buffer could be done while waiting for
+		 *     a previous MWRITE/MWERASE to complete ...
+		 * (d) error handling here seems to be mostly missing.
+		 *
+		 * Two persistent bits per page, plus a per-sector counter,
+		 * could support (a) and (b) ... we might consider using
+		 * the second half of sector zero, which is just one block,
+		 * to track that state.  (On AT91, that sector should also
+		 * support boot-from-DataFlash.)
+		 */
+
+		addr = pageaddr << priv->page_offset;
+
+		/* (1) Maybe transfer partial page to Buffer1 */
+		if (writelen != priv->page_size) {
+			command[0] = OP_TRANSFER_BUF1;
+			command[1] = (addr & 0x00FF0000) >> 16;
+			command[2] = (addr & 0x0000FF00) >> 8;
+			command[3] = 0;
+
+			DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n",
+				command[0], command[1], command[2], command[3]);
+
+			status = spi_sync(spi, &msg);
+			if (status < 0)
+				DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n",
+					spi->dev.bus_id, addr, status);
+
+			(void) dataflash_waitready(priv->spi);
+		}
+
+		/* (2) Program full page via Buffer1 */
+		addr += offset;
+		command[0] = OP_PROGRAM_VIA_BUF1;
+		command[1] = (addr & 0x00FF0000) >> 16;
+		command[2] = (addr & 0x0000FF00) >> 8;
+		command[3] = (addr & 0x000000FF);
+
+		DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n",
+			command[0], command[1], command[2], command[3]);
+
+		x[1].tx_buf = writebuf;
+		x[1].len = writelen;
+		spi_message_add_tail(x + 1, &msg);
+		status = spi_sync(spi, &msg);
+		spi_transfer_del(x + 1);
+		if (status < 0)
+			DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n",
+				spi->dev.bus_id, addr, writelen, status);
+
+		(void) dataflash_waitready(priv->spi);
+
+
+#ifdef	CONFIG_DATAFLASH_WRITE_VERIFY
+
+		/* (3) Compare to Buffer1 */
+		addr = pageaddr << priv->page_offset;
+		command[0] = OP_COMPARE_BUF1;
+		command[1] = (addr & 0x00FF0000) >> 16;
+		command[2] = (addr & 0x0000FF00) >> 8;
+		command[3] = 0;
+
+		DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n",
+			command[0], command[1], command[2], command[3]);
+
+		status = spi_sync(spi, &msg);
+		if (status < 0)
+			DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n",
+				spi->dev.bus_id, addr, status);
+
+		status = dataflash_waitready(priv->spi);
+
+		/* Check result of the compare operation */
+		if ((status & (1 << 6)) == 1) {
+			printk(KERN_ERR "%s: compare page %u, err %d\n",
+				spi->dev.bus_id, pageaddr, status);
+			remaining = 0;
+			status = -EIO;
+			break;
+		} else
+			status = 0;
+
+#endif	/* CONFIG_DATAFLASH_WRITE_VERIFY */
+
+		remaining = remaining - writelen;
+		pageaddr++;
+		offset = 0;
+		writebuf += writelen;
+		*retlen += writelen;
+
+		if (remaining > priv->page_size)
+			writelen = priv->page_size;
+		else
+			writelen = remaining;
+	}
+	up(&priv->lock);
+
+	return status;
+}
+
+/* ......................................................................... */
+
+/*
+ * Register DataFlash device with MTD subsystem.
+ */
+static int __devinit
+add_dataflash(struct spi_device *spi, char *name,
+		int nr_pages, int pagesize, int pageoffset)
+{
+	struct dataflash		*priv;
+	struct mtd_info			*device;
+	struct flash_platform_data	*pdata = spi->dev.platform_data;
+
+	priv = (struct dataflash *) kzalloc(sizeof *priv, GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	init_MUTEX(&priv->lock);
+	priv->spi = spi;
+	priv->page_size = pagesize;
+	priv->page_offset = pageoffset;
+
+	/* name must be usable with cmdlinepart */
+	sprintf(priv->name, "spi%d.%d-%s",
+			spi->master->bus_num, spi->chip_select,
+			name);
+
+	device = &priv->mtd;
+	device->name = (pdata && pdata->name) ? pdata->name : priv->name;
+	device->size = nr_pages * pagesize;
+	device->erasesize = pagesize;
+	device->owner = THIS_MODULE;
+	device->type = MTD_DATAFLASH;
+	device->flags = MTD_CAP_NORFLASH;
+	device->erase = dataflash_erase;
+	device->read = dataflash_read;
+	device->write = dataflash_write;
+	device->priv = priv;
+
+	dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
+	dev_set_drvdata(&spi->dev, priv);
+
+	if (mtd_has_partitions()) {
+		struct mtd_partition	*parts;
+		int			nr_parts = 0;
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+		nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
+#endif
+
+		if (nr_parts <= 0 && pdata && pdata->parts) {
+			parts = pdata->parts;
+			nr_parts = pdata->nr_parts;
+		}
+
+		if (nr_parts > 0) {
+			priv->partitioned = 1;
+			return add_mtd_partitions(device, parts, nr_parts);
+		}
+	} else if (pdata && pdata->nr_parts)
+		dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
+				pdata->nr_parts, device->name);
+
+	return add_mtd_device(device) == 1 ? -ENODEV : 0;
+}
+
+/*
+ * Detect and initialize DataFlash device:
+ *
+ *   Device      Density         ID code          #Pages PageSize  Offset
+ *   AT45DB011B  1Mbit   (128K)  xx0011xx (0x0c)    512    264      9
+ *   AT45DB021B  2Mbit   (256K)  xx0101xx (0x14)   1025    264      9
+ *   AT45DB041B  4Mbit   (512K)  xx0111xx (0x1c)   2048    264      9
+ *   AT45DB081B  8Mbit   (1M)    xx1001xx (0x24)   4096    264      9
+ *   AT45DB0161B 16Mbit  (2M)    xx1011xx (0x2c)   4096    528     10
+ *   AT45DB0321B 32Mbit  (4M)    xx1101xx (0x34)   8192    528     10
+ *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11
+ *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11
+ */
+static int __devinit dataflash_probe(struct spi_device *spi)
+{
+	int status;
+
+	status = dataflash_status(spi);
+	if (status <= 0 || status == 0xff) {
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n",
+				spi->dev.bus_id, status);
+		if (status == 0xff)
+			status = -ENODEV;
+		return status;
+	}
+
+	/* if there's a device there, assume it's dataflash.
+	 * board setup should have set spi->max_speed_max to
+	 * match f(car) for continuous reads, mode 0 or 3.
+	 */
+	switch (status & 0x3c) {
+	case 0x0c:	/* 0 0 1 1 x x */
+		status = add_dataflash(spi, "AT45DB011B", 512, 264, 9);
+		break;
+	case 0x14:	/* 0 1 0 1 x x */
+		status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9);
+		break;
+	case 0x1c:	/* 0 1 1 1 x x */
+		status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9);
+		break;
+	case 0x24:	/* 1 0 0 1 x x */
+		status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9);
+		break;
+	case 0x2c:	/* 1 0 1 1 x x */
+		status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10);
+		break;
+	case 0x34:	/* 1 1 0 1 x x */
+		status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10);
+		break;
+	case 0x38:	/* 1 1 1 x x x */
+	case 0x3c:
+		status = add_dataflash(spi, "AT45DB642x", 8192, 1056, 11);
+		break;
+	/* obsolete AT45DB1282 not (yet?) supported */
+	default:
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n",
+				spi->dev.bus_id, status & 0x3c);
+		status = -ENODEV;
+	}
+
+	if (status < 0)
+		DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n",
+				spi->dev.bus_id, status);
+
+	return status;
+}
+
+static int __devexit dataflash_remove(struct spi_device *spi)
+{
+	struct dataflash	*flash = dev_get_drvdata(&spi->dev);
+	int			status;
+
+	DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);
+
+	if (mtd_has_partitions() && flash->partitioned)
+		status = del_mtd_partitions(&flash->mtd);
+	else
+		status = del_mtd_device(&flash->mtd);
+	if (status == 0)
+		kfree(flash);
+	return status;
+}
+
+static struct spi_driver dataflash_driver = {
+	.driver = {
+		.name		= "mtd_dataflash",
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+
+	.probe		= dataflash_probe,
+	.remove		= __devexit_p(dataflash_remove),
+
+	/* FIXME:  investigate suspend and resume... */
+};
+
+static int __init dataflash_init(void)
+{
+	return spi_register_driver(&dataflash_driver);
+}
+module_init(dataflash_init);
+
+static void __exit dataflash_exit(void)
+{
+	spi_unregister_driver(&dataflash_driver);
+}
+module_exit(dataflash_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrew Victor, David Brownell");
+MODULE_DESCRIPTION("MTD DataFlash driver");
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 21d4e8f..ec5e45e 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1506,7 +1506,7 @@
 	return 1;
 }
 
-static inline int __init doc_probe(unsigned long physadr)
+static int __init doc_probe(unsigned long physadr)
 {
 	unsigned char ChipID;
 	struct mtd_info *mtd;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5c15f3e..171999e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1387,7 +1387,7 @@
 
 config CS89x0
 	tristate "CS89x0 support"
-	depends on NET_PCI && (ISA || ARCH_IXDP2X01 || ARCH_PNX010X)
+	depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X)
 	---help---
 	  Support for CS89x0 chipset based Ethernet cards. If you have a
 	  network (Ethernet) card of this type, say Y and read the
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index e2cfde7..fab6586 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -87,6 +87,12 @@
   Deepak Saxena     : dsaxena@plexity.net
                     : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support
 
+  Dmitry Pervushin  : dpervushin@ru.mvista.com
+                    : PNX010X platform support
+
+  Deepak Saxena     : dsaxena@plexity.net
+                    : Intel IXDP2351 platform support
+
 */
 
 /* Always include 'config.h' first in case the user wants to turn on
@@ -171,6 +177,10 @@
 static unsigned int netcard_portlist[] __initdata =
    { 0x0300, 0};
 static unsigned int cs8900_irq_map[] = {1,0,0,0};
+#elif defined(CONFIG_MACH_IXDP2351)
+static unsigned int netcard_portlist[] __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
+static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
+#include <asm/irq.h>
 #elif defined(CONFIG_ARCH_IXDP2X01)
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
@@ -338,45 +348,55 @@
 }
 #endif
 
-#if defined(CONFIG_ARCH_IXDP2X01)
-static int
+#if defined(CONFIG_MACH_IXDP2351)
+static u16
 readword(unsigned long base_addr, int portno)
 {
-	return (u16)__raw_readl(base_addr + (portno << 1));
+	return __raw_readw(base_addr + (portno << 1));
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
-	__raw_writel((u16)value, base_addr + (portno << 1));
+	__raw_writew(value, base_addr + (portno << 1));
 }
-#else
-#if defined(CONFIG_ARCH_PNX010X)
-static int
+#elif defined(CONFIG_ARCH_IXDP2X01)
+static u16
+readword(unsigned long base_addr, int portno)
+{
+	return __raw_readl(base_addr + (portno << 1));
+}
+
+static void
+writeword(unsigned long base_addr, int portno, u16 value)
+{
+	__raw_writel(value, base_addr + (portno << 1));
+}
+#elif defined(CONFIG_ARCH_PNX010X)
+static u16
 readword(unsigned long base_addr, int portno)
 {
 	return inw(base_addr + (portno << 1));
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
 	outw(value, base_addr + (portno << 1));
 }
 #else
-static int
+static u16
 readword(unsigned long base_addr, int portno)
 {
 	return inw(base_addr + portno);
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
 	outw(value, base_addr + portno);
 }
 #endif
-#endif
 
 static void
 readwords(unsigned long base_addr, int portno, void *buf, int length)
@@ -384,11 +404,11 @@
 	u8 *buf8 = (u8 *)buf;
 
 	do {
-		u32 tmp32;
+		u16 tmp16;
 
-		tmp32 = readword(base_addr, portno);
-		*buf8++ = (u8)tmp32;
-		*buf8++ = (u8)(tmp32 >> 8);
+		tmp16 = readword(base_addr, portno);
+		*buf8++ = (u8)tmp16;
+		*buf8++ = (u8)(tmp16 >> 8);
 	} while (--length);
 }
 
@@ -398,23 +418,23 @@
 	u8 *buf8 = (u8 *)buf;
 
 	do {
-		u32 tmp32;
+		u16 tmp16;
 
-		tmp32 = *buf8++;
-		tmp32 |= (*buf8++) << 8;
-		writeword(base_addr, portno, tmp32);
+		tmp16 = *buf8++;
+		tmp16 |= (*buf8++) << 8;
+		writeword(base_addr, portno, tmp16);
 	} while (--length);
 }
 
-static int
-readreg(struct net_device *dev, int regno)
+static u16
+readreg(struct net_device *dev, u16 regno)
 {
 	writeword(dev->base_addr, ADD_PORT, regno);
 	return readword(dev->base_addr, DATA_PORT);
 }
 
 static void
-writereg(struct net_device *dev, int regno, int value)
+writereg(struct net_device *dev, u16 regno, u16 value)
 {
 	writeword(dev->base_addr, ADD_PORT, regno);
 	writeword(dev->base_addr, DATA_PORT, value);
@@ -780,7 +800,7 @@
 	} else {
 		i = lp->isa_config & INT_NO_MASK;
 		if (lp->chip_type == CS8900) {
-#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
+#if defined(CONFIG_MACH_IXDP2351) || defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
 		        i = cs8900_irq_map[0];
 #else
 			/* Translate the IRQ using the IRQ mapping table. */
@@ -1012,7 +1032,7 @@
 
 void  __init reset_chip(struct net_device *dev)
 {
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
 	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 #endif
@@ -1023,7 +1043,7 @@
 	/* wait 30 ms */
 	msleep(30);
 
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
 	if (lp->chip_type != CS8900) {
 		/* Hardware problem requires PNP registers to be reconfigured after a reset */
 		writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT);
@@ -1287,7 +1307,7 @@
 	else
 #endif
 	{
-#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
 		if (((1 << dev->irq) & lp->irq_map) == 0) {
 			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 23de226..4726722 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -592,7 +592,7 @@
 	(void)readb(&nic->csr->scb.status);
 }
 
-static inline void e100_enable_irq(struct nic *nic)
+static void e100_enable_irq(struct nic *nic)
 {
 	unsigned long flags;
 
@@ -602,7 +602,7 @@
 	e100_write_flush(nic);
 }
 
-static inline void e100_disable_irq(struct nic *nic)
+static void e100_disable_irq(struct nic *nic)
 {
 	unsigned long flags;
 
@@ -791,7 +791,7 @@
 
 #define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
 #define E100_WAIT_SCB_FAST 20       /* delay like the old code */
-static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
+static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 {
 	unsigned long flags;
 	unsigned int i;
@@ -822,7 +822,7 @@
 	return err;
 }
 
-static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
+static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
 	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
 {
 	struct cb *cb;
@@ -1567,7 +1567,7 @@
 	mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
 }
 
-static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
 	struct sk_buff *skb)
 {
 	cb->command = nic->tx_command;
@@ -1617,7 +1617,7 @@
 	return 0;
 }
 
-static inline int e100_tx_clean(struct nic *nic)
+static int e100_tx_clean(struct nic *nic)
 {
 	struct cb *cb;
 	int tx_cleaned = 0;
@@ -1728,7 +1728,7 @@
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
-static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 {
 	if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
 		return -ENOMEM;
@@ -1762,7 +1762,7 @@
 	return 0;
 }
 
-static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
+static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 	unsigned int *work_done, unsigned int work_to_do)
 {
 	struct sk_buff *skb = rx->skb;
@@ -1822,7 +1822,7 @@
 	return 0;
 }
 
-static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
+static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
 	unsigned int work_to_do)
 {
 	struct rx *rx;
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index d6388e1..7613947 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -94,7 +94,7 @@
 	const char* name);
 static inline int card_wait_for_ready(const int ioaddr[], const char* name,
 	unsigned char in[]);
-static inline int card_send_command(const int ioaddr[], const char* name,
+static int card_send_command(const int ioaddr[], const char* name,
 	const unsigned char out[], unsigned char in[]);
 
 /* SB1000 hardware routines to be used during frame rx interrupt */
@@ -309,7 +309,7 @@
 }
 
 /* Card Send Command (cannot be used during an interrupt) */
-static inline int
+static int
 card_send_command(const int ioaddr[], const char* name,
 	const unsigned char out[], unsigned char in[])
 {
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index ffac508..4b13b76 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -435,7 +435,7 @@
 }
 
 
-static inline int
+static int
 hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
 		     struct hostap_80211_rx_status *rx_stats, u16 type,
 		     u16 stype)
@@ -499,7 +499,7 @@
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
+static struct net_device *prism2_rx_get_wds(local_info_t *local,
 						   u8 *addr)
 {
 	struct hostap_interface *iface = NULL;
@@ -519,7 +519,7 @@
 }
 
 
-static inline int
+static int
 hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
 		    u16 fc, struct net_device **wds)
 {
@@ -615,7 +615,7 @@
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline int
+static int
 hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
 			struct ieee80211_crypt_data *crypt)
 {
@@ -654,7 +654,7 @@
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline int
+static int
 hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
 			     int keyidx, struct ieee80211_crypt_data *crypt)
 {
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index abfae7f..b1f142d 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -253,7 +253,7 @@
  * @dev: pointer to net_device
  * @entry: Prism2 command queue entry to be issued
  */
-static inline int hfa384x_cmd_issue(struct net_device *dev,
+static int hfa384x_cmd_issue(struct net_device *dev,
 				    struct hostap_cmd_queue *entry)
 {
 	struct hostap_interface *iface;
@@ -743,7 +743,7 @@
 }
 
 
-static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
+static int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
 {
 	int tries = HFA384X_BAP_BUSY_TIMEOUT;
 	int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
@@ -1904,7 +1904,7 @@
  * and will try to get the correct fid eventually. */
 #define EXTRA_FID_READ_TESTS
 
-static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
+static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
 {
 #ifdef EXTRA_FID_READ_TESTS
 	u16 val, val2, val3;
@@ -2581,7 +2581,7 @@
 
 
 /* Called only from hardware IRQ */
-static inline void prism2_check_magic(local_info_t *local)
+static void prism2_check_magic(local_info_t *local)
 {
 	/* at least PCI Prism2.5 with bus mastering seems to sometimes
 	 * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index cf05661..7518384 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -411,7 +411,7 @@
 	write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
 }
 
-static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
+static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
 				    const u8 * buf)
 {
 	u32 aligned_addr;
@@ -449,7 +449,7 @@
 				    *buf);
 }
 
-static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
+static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
 				   u8 * buf)
 {
 	u32 aligned_addr;
@@ -657,7 +657,7 @@
 
 #define MAX_RESET_BACKOFF 10
 
-static inline void schedule_reset(struct ipw2100_priv *priv)
+static void schedule_reset(struct ipw2100_priv *priv)
 {
 	unsigned long now = get_seconds();
 
@@ -1130,7 +1130,7 @@
 	write_register(priv->net_dev, IPW_REG_GPIO, reg);
 }
 
-static inline int rf_kill_active(struct ipw2100_priv *priv)
+static int rf_kill_active(struct ipw2100_priv *priv)
 {
 #define MAX_RF_KILL_CHECKS 5
 #define RF_KILL_CHECK_DELAY 40
@@ -2177,7 +2177,7 @@
 };
 #endif
 
-static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv,
+static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
 				    struct ipw2100_rx_packet *packet)
 {
 	packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
@@ -2201,7 +2201,7 @@
 #define SEARCH_SNAPSHOT 1
 
 #define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
-static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
+static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
 	if (priv->snapshot[0])
@@ -2221,7 +2221,7 @@
 	return 1;
 }
 
-static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
+static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 {
 	int i;
 	if (!priv->snapshot[0])
@@ -2231,7 +2231,7 @@
 	priv->snapshot[0] = NULL;
 }
 
-static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
+static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
 				    size_t len, int mode)
 {
 	u32 i, j;
@@ -2288,7 +2288,7 @@
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
-static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
+static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
 #ifdef CONFIG_IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2346,7 +2346,7 @@
 	schedule_reset(priv);
 }
 
-static inline void isr_rx(struct ipw2100_priv *priv, int i,
+static void isr_rx(struct ipw2100_priv *priv, int i,
 			  struct ieee80211_rx_stats *stats)
 {
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2425,7 +2425,7 @@
 	priv->rx_queue.drv[i].host_addr = packet->dma_addr;
 }
 
-static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
+static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
 {
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
@@ -2481,7 +2481,7 @@
  * The WRITE index is cached in the variable 'priv->rx_queue.next'.
  *
  */
-static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
+static void __ipw2100_rx_process(struct ipw2100_priv *priv)
 {
 	struct ipw2100_bd_queue *rxq = &priv->rx_queue;
 	struct ipw2100_status_queue *sq = &priv->status_queue;
@@ -2634,7 +2634,7 @@
  * for use by future command and data packets.
  *
  */
-static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
+static int __ipw2100_tx_process(struct ipw2100_priv *priv)
 {
 	struct ipw2100_bd_queue *txq = &priv->tx_queue;
 	struct ipw2100_bd *tbd;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index cdfe502..819be2b 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -813,7 +813,7 @@
 	up(&priv->sem);
 }
 
-static inline void __ipw_led_activity_on(struct ipw_priv *priv)
+static void __ipw_led_activity_on(struct ipw_priv *priv)
 {
 	u32 led;
 
@@ -1508,7 +1508,7 @@
 static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
 		   show_direct_dword, store_direct_dword);
 
-static inline int rf_kill_active(struct ipw_priv *priv)
+static int rf_kill_active(struct ipw_priv *priv)
 {
 	if (0 == (ipw_read32(priv, 0x30) & 0x10000))
 		priv->status |= STATUS_RF_KILL_HW;
@@ -2359,7 +2359,7 @@
 }
 
 /* perform a chip select operation */
-static inline void eeprom_cs(struct ipw_priv *priv)
+static void eeprom_cs(struct ipw_priv *priv)
 {
 	eeprom_write_reg(priv, 0);
 	eeprom_write_reg(priv, EEPROM_BIT_CS);
@@ -2368,7 +2368,7 @@
 }
 
 /* perform a chip select operation */
-static inline void eeprom_disable_cs(struct ipw_priv *priv)
+static void eeprom_disable_cs(struct ipw_priv *priv)
 {
 	eeprom_write_reg(priv, EEPROM_BIT_CS);
 	eeprom_write_reg(priv, 0);
@@ -2475,7 +2475,7 @@
 	IPW_DEBUG_TRACE("<<\n");
 }
 
-static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
+static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
 {
 	count >>= 2;
 	if (!count)
@@ -2772,7 +2772,7 @@
 	return ipw_read32(priv, 0x90) == 0xd55555d5;
 }
 
-static inline int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
+static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
 			       int timeout)
 {
 	int i = 0;
@@ -3150,7 +3150,7 @@
 
 #define IPW_RX_BUF_SIZE (3000)
 
-static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
+static void ipw_rx_queue_reset(struct ipw_priv *priv,
 				      struct ipw_rx_queue *rxq)
 {
 	unsigned long flags;
@@ -3608,7 +3608,7 @@
 	ipw_queue_tx_free(priv, &priv->txq[3]);
 }
 
-static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
+static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
 {
 	/* First 3 bytes are manufacturer */
 	bssid[0] = priv->mac_addr[0];
@@ -3622,7 +3622,7 @@
 	bssid[0] |= 0x02;	/* set local assignment bit (IEEE802) */
 }
 
-static inline u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
+static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
 {
 	struct ipw_station_entry entry;
 	int i;
@@ -3655,7 +3655,7 @@
 	return i;
 }
 
-static inline u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
+static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
 {
 	int i;
 
@@ -3794,7 +3794,7 @@
 	memset(avg, 0, sizeof(*avg));
 }
 
-static void inline average_add(struct average *avg, s16 val)
+static void average_add(struct average *avg, s16 val)
 {
 	avg->sum -= avg->entries[avg->pos];
 	avg->sum += val;
@@ -3805,7 +3805,7 @@
 	}
 }
 
-static s16 inline average_value(struct average *avg)
+static s16 average_value(struct average *avg)
 {
 	if (!unlikely(avg->init)) {
 		if (avg->pos)
@@ -3847,7 +3847,7 @@
 
 }
 
-static inline u32 ipw_get_max_rate(struct ipw_priv *priv)
+static u32 ipw_get_max_rate(struct ipw_priv *priv)
 {
 	u32 i = 0x80000000;
 	u32 mask = priv->rates_mask;
@@ -4087,7 +4087,7 @@
  * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
  * Above disassociate threshold, give up and stop scanning.
  * Roaming is disabled if disassociate_threshold <= roaming_threshold  */
-static inline void ipw_handle_missed_beacon(struct ipw_priv *priv,
+static void ipw_handle_missed_beacon(struct ipw_priv *priv,
 					    int missed_count)
 {
 	priv->notif_missed_beacons = missed_count;
@@ -4157,7 +4157,7 @@
  * Handle host notification packet.
  * Called from interrupt routine
  */
-static inline void ipw_rx_notification(struct ipw_priv *priv,
+static void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
 	notif->size = le16_to_cpu(notif->size);
@@ -5095,7 +5095,7 @@
 	return 1;
 }
 
-static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
+static void ipw_copy_rates(struct ipw_supported_rates *dest,
 				  const struct ipw_supported_rates *src)
 {
 	u8 i;
@@ -5856,7 +5856,7 @@
 #define ipw_debug_config(x) do {} while (0)
 #endif
 
-static inline void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
+static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 {
 	/* TODO: Verify that this works... */
 	struct ipw_fixed_rate fr = {
@@ -7634,7 +7634,7 @@
 }
 #endif
 
-static inline int is_network_packet(struct ipw_priv *priv,
+static int is_network_packet(struct ipw_priv *priv,
 				    struct ieee80211_hdr_4addr *header)
 {
 	/* Filter incoming packets to determine if they are targetted toward
@@ -7672,7 +7672,7 @@
 
 #define IPW_PACKET_RETRY_TIME HZ
 
-static inline int is_duplicate_packet(struct ipw_priv *priv,
+static  int is_duplicate_packet(struct ipw_priv *priv,
 				      struct ieee80211_hdr_4addr *header)
 {
 	u16 sc = le16_to_cpu(header->seq_ctl);
@@ -9581,7 +9581,7 @@
 
 /* net device stuff */
 
-static inline void init_sys_config(struct ipw_sys_config *sys_config)
+static  void init_sys_config(struct ipw_sys_config *sys_config)
 {
 	memset(sys_config, 0, sizeof(struct ipw_sys_config));
 	sys_config->bt_coexistence = 1;	/* We may need to look into prvStaBtConfig */
@@ -9627,7 +9627,7 @@
 we need to heavily modify the ieee80211_skb_to_txb.
 */
 
-static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
+static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
 			     int pri)
 {
 	struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index b0d8b5b..ff192e9 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -102,7 +102,7 @@
  * Write to card's Host Adapter Command Register. Include a delay for
  * those times when it is needed.
  */
-static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
+static void hacr_write_slow(unsigned long ioaddr, u16 hacr)
 {
 	hacr_write(ioaddr, hacr);
 	/* delay might only be needed sometimes */
@@ -242,7 +242,7 @@
  * The Windows drivers don't use the CRC, but the AP and the PtP tool
  * depend on it.
  */
-static inline u16 psa_crc(u8 * psa,	/* The PSA */
+static u16 psa_crc(u8 * psa,	/* The PSA */
 			      int size)
 {				/* Number of short for CRC */
 	int byte_cnt;		/* Loop on the PSA */
@@ -310,7 +310,7 @@
 /*
  * Write 1 byte to the MMC.
  */
-static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
+static void mmc_out(unsigned long ioaddr, u16 o, u8 d)
 {
 	int count = 0;
 
@@ -326,7 +326,7 @@
  * Routine to write bytes to the Modem Management Controller.
  * We start at the end because it is the way it should be!
  */
-static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
+static void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
 {
 	o += n;
 	b += n;
@@ -340,7 +340,7 @@
  * Read a byte from the MMC.
  * Optimised version for 1 byte, avoid using memory.
  */
-static inline u8 mmc_in(unsigned long ioaddr, u16 o)
+static u8 mmc_in(unsigned long ioaddr, u16 o)
 {
 	int count = 0;
 
@@ -587,7 +587,7 @@
  * Set channel attention bit and busy wait until command has
  * completed, then acknowledge completion of the command.
  */
-static inline int wv_synchronous_cmd(struct net_device * dev, const char *str)
+static int wv_synchronous_cmd(struct net_device * dev, const char *str)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
@@ -633,7 +633,7 @@
  * Configuration commands completion interrupt.
  * Check if done, and if OK.
  */
-static inline int
+static int
 wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp)
 {
 	unsigned short mcs_addr;
@@ -843,7 +843,7 @@
  * wavelan_interrupt is not an option), so you may experience
  * delays sometimes.
  */
-static inline void wv_82586_reconfig(struct net_device * dev)
+static void wv_82586_reconfig(struct net_device * dev)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long flags;
@@ -1281,7 +1281,7 @@
  * This is the information which is displayed by the driver at startup.
  * There are lots of flags for configuring it to your liking.
  */
-static inline void wv_init_info(struct net_device * dev)
+static void wv_init_info(struct net_device * dev)
 {
 	short ioaddr = dev->base_addr;
 	net_local *lp = (net_local *) dev->priv;
@@ -1502,7 +1502,7 @@
  * It's a bit complicated and you don't really want to look into it.
  * (called in wavelan_ioctl)
  */
-static inline int wv_set_frequency(unsigned long ioaddr,	/* I/O port of the card */
+static int wv_set_frequency(unsigned long ioaddr,	/* I/O port of the card */
 				   iw_freq * frequency)
 {
 	const int BAND_NUM = 10;	/* Number of bands */
@@ -1677,7 +1677,7 @@
 /*
  * Give the list of available frequencies.
  */
-static inline int wv_frequency_list(unsigned long ioaddr,	/* I/O port of the card */
+static int wv_frequency_list(unsigned long ioaddr,	/* I/O port of the card */
 				    iw_freq * list,	/* List of frequencies to fill */
 				    int max)
 {				/* Maximum number of frequencies */
@@ -2489,7 +2489,7 @@
  * Note: if any errors occur, the packet is "dropped on the floor".
  * (called by wv_packet_rcv())
  */
-static inline void
+static void
 wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
 {
 	net_local *lp = (net_local *) dev->priv;
@@ -2585,7 +2585,7 @@
  * (called in wavelan_interrupt()).
  * Note : the spinlock is already grabbed for us.
  */
-static inline void wv_receive(struct net_device * dev)
+static void wv_receive(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
 	net_local *lp = (net_local *) dev->priv;
@@ -2768,7 +2768,7 @@
  *
  * (called in wavelan_packet_xmit())
  */
-static inline int wv_packet_write(struct net_device * dev, void *buf, short length)
+static int wv_packet_write(struct net_device * dev, void *buf, short length)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
@@ -2964,7 +2964,7 @@
  * Routine to initialize the Modem Management Controller.
  * (called by wv_hw_reset())
  */
-static inline int wv_mmc_init(struct net_device * dev)
+static int wv_mmc_init(struct net_device * dev)
 {
 	unsigned long ioaddr = dev->base_addr;
 	net_local *lp = (net_local *) dev->priv;
@@ -3136,7 +3136,7 @@
  * Start the receive unit.
  * (called by wv_hw_reset())
  */
-static inline int wv_ru_start(struct net_device * dev)
+static int wv_ru_start(struct net_device * dev)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
@@ -3228,7 +3228,7 @@
  *
  * (called by wv_hw_reset())
  */
-static inline int wv_cu_start(struct net_device * dev)
+static int wv_cu_start(struct net_device * dev)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
@@ -3329,7 +3329,7 @@
  *
  * (called by wv_hw_reset())
  */
-static inline int wv_82586_start(struct net_device * dev)
+static int wv_82586_start(struct net_device * dev)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
@@ -3641,7 +3641,7 @@
  * WaveLAN controller (i82586).
  * (called by wavelan_close())
  */
-static inline void wv_82586_stop(struct net_device * dev)
+static void wv_82586_stop(struct net_device * dev)
 {
 	net_local *lp = (net_local *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 7146b69..0aa14c9 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -380,8 +380,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &pci_bus_type;
-	drv->driver.probe = pci_device_probe;
-	drv->driver.remove = pci_device_remove;
 	/* FIXME, once all of the existing PCI drivers have been fixed to set
 	 * the pci shutdown function, this test can go away. */
 	if (!drv->driver.shutdown)
@@ -513,6 +511,8 @@
 	.name		= "pci",
 	.match		= pci_bus_match,
 	.uevent		= pci_uevent,
+	.probe		= pci_device_probe,
+	.remove		= pci_device_remove,
 	.suspend	= pci_device_suspend,
 	.resume		= pci_device_resume,
 	.dev_attrs	= pci_dev_attrs,
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 621ec45..0a424a4 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -311,8 +311,6 @@
 	/* initialize common fields */
 	driver->drv.bus = &pcmcia_bus_type;
 	driver->drv.owner = driver->owner;
-	driver->drv.probe = pcmcia_device_probe;
-	driver->drv.remove = pcmcia_device_remove;
 
 	return driver_register(&driver->drv);
 }
@@ -1200,6 +1198,8 @@
 	.uevent = pcmcia_bus_uevent,
 	.match = pcmcia_bus_match,
 	.dev_attrs = pcmcia_dev_attrs,
+	.probe = pcmcia_device_probe,
+	.remove = pcmcia_device_remove,
 	.suspend = pcmcia_dev_suspend,
 	.resume = pcmcia_dev_resume,
 };
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 15fb758..7cafacd 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -195,6 +195,8 @@
 struct bus_type pnp_bus_type = {
 	.name	= "pnp",
 	.match	= pnp_bus_match,
+	.probe	= pnp_device_probe,
+	.remove	= pnp_device_remove,
 	.suspend = pnp_bus_suspend,
 	.resume = pnp_bus_resume,
 };
@@ -215,8 +217,6 @@
 
 	drv->driver.name = drv->name;
 	drv->driver.bus = &pnp_bus_type;
-	drv->driver.probe = pnp_device_probe;
-	drv->driver.remove = pnp_device_remove;
 
 	count = driver_register(&drv->driver);
 
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index dc74960..5480119 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -147,8 +147,6 @@
 	/* initialize common driver fields */
 	rdrv->driver.name = rdrv->name;
 	rdrv->driver.bus = &rio_bus_type;
-	rdrv->driver.probe = rio_device_probe;
-	rdrv->driver.remove = rio_device_remove;
 
 	/* register with core */
 	return driver_register(&rdrv->driver);
@@ -204,7 +202,9 @@
 struct bus_type rio_bus_type = {
 	.name = "rapidio",
 	.match = rio_match_bus,
-	.dev_attrs = rio_dev_attrs
+	.dev_attrs = rio_dev_attrs,
+	.probe = rio_device_probe,
+	.remove = rio_device_remove,
 };
 
 /**
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 9c25654..ef4c687 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1635,7 +1635,7 @@
 	blk_queue_max_hw_segments(device->request_queue, -1L);
 	blk_queue_max_segment_size(device->request_queue, -1L);
 	blk_queue_segment_boundary(device->request_queue, -1L);
-	blk_queue_ordered(device->request_queue, 1);
+	blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
 }
 
 /*
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 83e6a06..cd2cc28 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -2,12 +2,12 @@
  *  drivers/s390/cio/airq.c
  *   S/390 common I/O routines -- support for adapter interruptions
  *
- *   $Revision: 1.12 $
+ *   $Revision: 1.15 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Arnd Bergmann (arndb@de.ibm.com)
  */
 
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index daf21e0..72f27c1 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/blacklist.c
  *   S/390 common I/O routines -- blacklisting of specific devices
- *   $Revision: 1.39 $
+ *   $Revision: 1.42 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Arnd Bergmann (arndb@de.ibm.com)
  */
 
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e849289..6c077ad 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.33 $
+ *   $Revision: 1.35 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *               Cornelia Huck (cohuck@de.ibm.com)
+ *               Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -52,11 +52,7 @@
 	return 0;
 }
 
-static struct bus_type ccwgroup_bus_type = {
-	.name    = "ccwgroup",
-	.match   = ccwgroup_bus_match,
-	.uevent = ccwgroup_uevent,
-};
+static struct bus_type ccwgroup_bus_type;
 
 static inline void
 __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
@@ -389,6 +385,14 @@
 	return 0;
 }
 
+static struct bus_type ccwgroup_bus_type = {
+	.name   = "ccwgroup",
+	.match  = ccwgroup_bus_match,
+	.uevent = ccwgroup_uevent,
+	.probe  = ccwgroup_probe,
+	.remove = ccwgroup_remove,
+};
+
 int
 ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
 {
@@ -396,8 +400,6 @@
 	cdriver->driver = (struct device_driver) {
 		.bus = &ccwgroup_bus_type,
 		.name = cdriver->name,
-		.probe = ccwgroup_probe,
-		.remove = ccwgroup_remove,
 	};
 
 	return driver_register(&cdriver->driver);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 7270808..2cbb724 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.126 $
+ *   $Revision: 1.128 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Arnd Bergmann (arndb@de.ibm.com)
  */
 
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 7376bc8..6223b06 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.138 $
+ *   $Revision: 1.140 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Arnd Bergmann (arndb@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index e565193..5161087 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.93 $
+ *   $Revision: 1.96 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -542,9 +542,41 @@
 	return 0;
 }
 
+static int
+css_probe (struct device *dev)
+{
+	struct subchannel *sch;
+
+	sch = to_subchannel(dev);
+	sch->driver = container_of (dev->driver, struct css_driver, drv);
+	return (sch->driver->probe ? sch->driver->probe(sch) : 0);
+}
+
+static int
+css_remove (struct device *dev)
+{
+	struct subchannel *sch;
+
+	sch = to_subchannel(dev);
+	return (sch->driver->remove ? sch->driver->remove(sch) : 0);
+}
+
+static void
+css_shutdown (struct device *dev)
+{
+	struct subchannel *sch;
+
+	sch = to_subchannel(dev);
+	if (sch->driver->shutdown)
+		sch->driver->shutdown(sch);
+}
+
 struct bus_type css_bus_type = {
-	.name  = "css",
-	.match = &css_bus_match,
+	.name     = "css",
+	.match    = css_bus_match,
+	.probe    = css_probe,
+	.remove   = css_remove,
+	.shutdown = css_shutdown,
 };
 
 subsys_initcall(init_channel_subsystem);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 251ebd7..b637586 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -115,6 +115,7 @@
  * Currently, we only care about I/O subchannels (type 0), these
  * have a ccw_device connected to them.
  */
+struct subchannel;
 struct css_driver {
 	unsigned int subchannel_type;
 	struct device_driver drv;
@@ -122,6 +123,9 @@
 	int (*notify)(struct device *, int);
 	void (*verify)(struct device *);
 	void (*termination)(struct device *);
+	int (*probe)(struct subchannel *);
+	int (*remove)(struct subchannel *);
+	void (*shutdown)(struct subchannel *);
 };
 
 /*
@@ -143,7 +147,7 @@
 struct channel_subsystem {
 	u8 cssid;
 	int valid;
-	struct channel_path *chps[__MAX_CHPID];
+	struct channel_path *chps[__MAX_CHPID + 1];
 	struct device device;
 	struct pgid global_pgid;
 };
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index fa3e4c0..a67e7e6 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.137 $
+ *   $Revision: 1.140 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *		 Cornelia Huck (cohuck@de.ibm.com)
+ *		 Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 #include <linux/config.h>
@@ -107,33 +107,29 @@
 	return 0;
 }
 
-struct bus_type ccw_bus_type = {
-	.name  = "ccw",
-	.match = &ccw_bus_match,
-	.uevent = &ccw_uevent,
-};
+struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct device *);
-static int io_subchannel_remove (struct device *);
+static int io_subchannel_probe (struct subchannel *);
+static int io_subchannel_remove (struct subchannel *);
 void io_subchannel_irq (struct device *);
 static int io_subchannel_notify(struct device *, int);
 static void io_subchannel_verify(struct device *);
 static void io_subchannel_ioterm(struct device *);
-static void io_subchannel_shutdown(struct device *);
+static void io_subchannel_shutdown(struct subchannel *);
 
 struct css_driver io_subchannel_driver = {
 	.subchannel_type = SUBCHANNEL_TYPE_IO,
 	.drv = {
 		.name = "io_subchannel",
 		.bus  = &css_bus_type,
-		.probe = &io_subchannel_probe,
-		.remove = &io_subchannel_remove,
-		.shutdown = &io_subchannel_shutdown,
 	},
 	.irq = io_subchannel_irq,
 	.notify = io_subchannel_notify,
 	.verify = io_subchannel_verify,
 	.termination = io_subchannel_ioterm,
+	.probe = io_subchannel_probe,
+	.remove = io_subchannel_remove,
+	.shutdown = io_subchannel_shutdown,
 };
 
 struct workqueue_struct *ccw_device_work;
@@ -803,14 +799,12 @@
 }
 
 static int
-io_subchannel_probe (struct device *pdev)
+io_subchannel_probe (struct subchannel *sch)
 {
-	struct subchannel *sch;
 	struct ccw_device *cdev;
 	int rc;
 	unsigned long flags;
 
-	sch = to_subchannel(pdev);
 	if (sch->dev.driver_data) {
 		/*
 		 * This subchannel already has an associated ccw_device.
@@ -846,7 +840,7 @@
 	memset(cdev->private, 0, sizeof(struct ccw_device_private));
 	atomic_set(&cdev->private->onoff, 0);
 	cdev->dev = (struct device) {
-		.parent = pdev,
+		.parent = &sch->dev,
 		.release = ccw_device_release,
 	};
 	INIT_LIST_HEAD(&cdev->private->kick_work.entry);
@@ -859,7 +853,7 @@
 		return -ENODEV;
 	}
 
-	rc = io_subchannel_recog(cdev, to_subchannel(pdev));
+	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
 		spin_lock_irqsave(&sch->lock, flags);
 		sch->dev.driver_data = NULL;
@@ -883,17 +877,17 @@
 }
 
 static int
-io_subchannel_remove (struct device *dev)
+io_subchannel_remove (struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 	unsigned long flags;
 
-	if (!dev->driver_data)
+	if (!sch->dev.driver_data)
 		return 0;
-	cdev = dev->driver_data;
+	cdev = sch->dev.driver_data;
 	/* Set ccw device to not operational and drop reference. */
 	spin_lock_irqsave(cdev->ccwlock, flags);
-	dev->driver_data = NULL;
+	sch->dev.driver_data = NULL;
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	spin_unlock_irqrestore(cdev->ccwlock, flags);
 	/*
@@ -948,14 +942,12 @@
 }
 
 static void
-io_subchannel_shutdown(struct device *dev)
+io_subchannel_shutdown(struct subchannel *sch)
 {
-	struct subchannel *sch;
 	struct ccw_device *cdev;
 	int ret;
 
-	sch = to_subchannel(dev);
-	cdev = dev->driver_data;
+	cdev = sch->dev.driver_data;
 
 	if (cio_is_console(sch->schid))
 		return;
@@ -1129,6 +1121,14 @@
 	return 0;
 }
 
+struct bus_type ccw_bus_type = {
+	.name   = "ccw",
+	.match  = ccw_bus_match,
+	.uevent = ccw_uevent,
+	.probe  = ccw_device_probe,
+	.remove = ccw_device_remove,
+};
+
 int
 ccw_driver_register (struct ccw_driver *cdriver)
 {
@@ -1136,8 +1136,6 @@
 
 	drv->bus = &ccw_bus_type;
 	drv->name = cdriver->name;
-	drv->probe = ccw_device_probe;
-	drv->remove = ccw_device_remove;
 
 	return driver_register(drv);
 }
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 23d12b6..b302779 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -4,7 +4,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 04ceba3..e60b2d8 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Sense ID functions.
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 143b6c2..8b02189 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.58 $
+ *   $Revision: 1.61 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Cornelia Huck (cohuck@de.ibm.com)
+ *               Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/config.h>
 #include <linux/module.h>
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 052832d..d2a5b04 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Path Group ID functions.
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index db09c20..dad4dd9 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Status accumulation and basic sense functions.
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 30a836f..77be2c3 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -7,7 +7,7 @@
  *
  * Copyright 2000,2002 IBM Corporation
  * Author(s):             Utz Bacher <utz.bacher@de.ibm.com>
- * 2.6 cio integration by Cornelia Huck <cohuck@de.ibm.com>
+ * 2.6 cio integration by Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * Restriction: only 63 iqdio subchannels would have its own indicator,
  * after that, subsequent subchannels share one indicator
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.114 $"
+#define VERSION_QDIO_C "$Revision: 1.117 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 0db4f57..1901fee 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.78 2005/09/07 12:18:02 pavlic Exp $
+ * $Id: ctcmain.c,v 1.79 2006/01/11 11:32:18 cohuck Exp $
  *
  * CTC / ESCON network driver
  *
@@ -8,7 +8,7 @@
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 	      Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <cohuck@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -37,7 +37,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.78 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.79 $
  *
  */
 #undef DEBUG
@@ -248,7 +248,7 @@
 print_banner(void)
 {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.78 $";
+	char vbuf[] = "$Revision: 1.79 $";
 	char *version = vbuf;
 
 	if (printed)
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 77dacb4..2014fb7 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -1,11 +1,11 @@
 /*
- * $Id: cu3088.c,v 1.36 2005/10/25 14:37:17 cohuck Exp $
+ * $Id: cu3088.c,v 1.38 2006/01/12 14:33:09 cohuck Exp $
  *
  * CTC / LCS ccw_device driver
  *
  * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Arnd Bergmann <arndb@de.ibm.com>
- *            Cornelia Huck <cohuck@de.ibm.com>
+ *            Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 69425a7..ac4c4b8 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,12 +1,13 @@
 /*
- * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $
+ * $Id: netiucv.c,v 1.69 2006/01/12 14:33:09 cohuck Exp $
  *
  * IUCV network driver
  *
  * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  *
- * Driverfs integration and all bugs therein by Cornelia Huck(cohuck@de.ibm.com)
+ * Sysfs integration and all bugs therein by Cornelia Huck
+ * (cornelia.huck@de.ibm.com)
  *
  * Documentation used:
  *  the source of the original IUCV driver by:
@@ -30,7 +31,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.66 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.69 $
  *
  */
 
@@ -2076,7 +2077,7 @@
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.66 $";
+	char vbuf[] = "$Revision: 1.69 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff --git a/drivers/s390/s390_rdev.c b/drivers/s390/s390_rdev.c
index 566cc3d..206518c 100644
--- a/drivers/s390/s390_rdev.c
+++ b/drivers/s390/s390_rdev.c
@@ -1,11 +1,11 @@
 /*
  *  drivers/s390/s390_rdev.c
  *  s390 root device
- *   $Revision: 1.2 $
+ *   $Revision: 1.4 $
  *
  *    Copyright (C) 2002, 2005 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
- *    Author(s): Cornelia Huck (cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *		  Carsten Otte  (cotte@de.ibm.com)
  */
 
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 5e84c5a..167fef3 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -1125,6 +1125,8 @@
 	zfcp_free_low_mem_buffers(adapter);
 	/* free memory of adapter data structure and queues */
 	zfcp_qdio_free_queues(adapter);
+	kfree(adapter->fc_stats);
+	kfree(adapter->stats_reset_data);
 	ZFCP_LOG_TRACE("freeing adapter structure\n");
 	kfree(adapter);
  out:
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index d81b737..9bb5110 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -921,7 +921,6 @@
 	u32			physical_s_id;     /* local FC port ID */
 	struct ccw_device       *ccw_device;	   /* S/390 ccw device */
 	u8			fc_service_class;
-	u32			fc_topology;	   /* FC topology */
 	u32			hydra_version;	   /* Hydra version */
 	u32			fsf_lic_version;
 	u32			adapter_features;  /* FCP channel features */
@@ -978,6 +977,9 @@
 	struct zfcp_adapter_mempool	pool;      /* Adapter memory pools */
 	struct qdio_initialize  qdio_init_data;    /* for qdio_establish */
 	struct device           generic_services;  /* directory for WKA ports */
+	struct fc_host_statistics *fc_stats;
+	struct fsf_qtcb_bottom_port *stats_reset_data;
+	unsigned long		stats_reset;
 };
 
 /*
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index ee7314d..7bdb00b 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -2613,7 +2613,7 @@
 	case ZFCP_ERP_STEP_UNINITIALIZED:
 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
 	case ZFCP_ERP_STEP_PORT_CLOSING:
-		if (adapter->fc_topology == FSF_TOPO_P2P) {
+		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) {
 			if (port->wwpn != adapter->peer_wwpn) {
 				ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx "
 						"on adapter %s.\nPeer WWPN "
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 5958795..cbfab09 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -964,6 +964,40 @@
 					| ZFCP_STATUS_COMMON_ERP_FAILED);
 		break;
 
+	case FSF_STATUS_READ_NOTIFICATION_LOST:
+		ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: "
+				"adapter %s%s%s%s%s%s%s%s%s\n",
+				zfcp_get_busid_by_adapter(adapter),
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_INCOMING_ELS) ?
+					", incoming ELS" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_SENSE_DATA) ?
+					", sense data" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_LINK_STATUS) ?
+					", link status change" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_PORT_CLOSED) ?
+					", port close" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ?
+					", bit error exception" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_ACT_UPDATED) ?
+					", ACT update" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_ACT_HARDENED) ?
+					", ACT hardening" : "",
+				(status_buffer->status_subtype &
+					FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ?
+					", adapter feature change" : "");
+
+		if (status_buffer->status_subtype &
+		    FSF_STATUS_READ_SUB_ACT_UPDATED)
+			zfcp_erp_adapter_access_changed(adapter);
+		break;
+
 	case FSF_STATUS_READ_CFDC_UPDATED:
 		ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n",
 			      zfcp_get_busid_by_adapter(adapter));
@@ -1954,6 +1988,7 @@
 	erp_action->fsf_req->qtcb->bottom.config.feature_selection =
 			FSF_FEATURE_CFDC |
 			FSF_FEATURE_LUN_SHARING |
+			FSF_FEATURE_NOTIFICATION_LOST |
 			FSF_FEATURE_UPDATE_ALERT;
 
 	/* start QDIO request for this FSF request */
@@ -2008,27 +2043,30 @@
 		fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
 		fc_host_speed(shost) = bottom->fc_link_speed;
 		fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
-		adapter->fc_topology = bottom->fc_topology;
 		adapter->hydra_version = bottom->adapter_type;
-		if (adapter->physical_wwpn == 0)
-			adapter->physical_wwpn = fc_host_port_name(shost);
-		if (adapter->physical_s_id == 0)
-			adapter->physical_s_id = fc_host_port_id(shost);
+		if (fc_host_permanent_port_name(shost) == -1)
+			fc_host_permanent_port_name(shost) =
+				fc_host_port_name(shost);
+		if (bottom->fc_topology == FSF_TOPO_P2P) {
+			adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
+			adapter->peer_wwpn = bottom->plogi_payload.wwpn;
+			adapter->peer_wwnn = bottom->plogi_payload.wwnn;
+			fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+		} else if (bottom->fc_topology == FSF_TOPO_FABRIC)
+			fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+		else if (bottom->fc_topology == FSF_TOPO_AL)
+			fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+		else
+			fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
 	} else {
 		fc_host_node_name(shost) = 0;
 		fc_host_port_name(shost) = 0;
 		fc_host_port_id(shost) = 0;
 		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
-		adapter->fc_topology = 0;
+		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
 		adapter->hydra_version = 0;
 	}
 
-	if (adapter->fc_topology == FSF_TOPO_P2P) {
-		adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
-		adapter->peer_wwpn = bottom->plogi_payload.wwpn;
-		adapter->peer_wwnn = bottom->plogi_payload.wwnn;
-	}
-
 	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
 		adapter->hardware_version = bottom->hardware_version;
 		memcpy(fc_host_serial_number(shost), bottom->serial_number,
@@ -2097,8 +2135,8 @@
 		if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
 			return -EIO;
 
-		switch (adapter->fc_topology) {
-		case FSF_TOPO_P2P:
+		switch (fc_host_port_type(adapter->scsi_host)) {
+		case FC_PORTTYPE_PTP:
 			ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
 					"configuration detected at adapter %s\n"
 					"Peer WWNN 0x%016llx, "
@@ -2111,7 +2149,7 @@
 			debug_text_event(fsf_req->adapter->erp_dbf, 0,
 					 "top-p-to-p");
 			break;
-		case FSF_TOPO_AL:
+		case FC_PORTTYPE_NLPORT:
 			ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
 					"topology detected at adapter %s "
 					"unsupported, shutting down adapter\n",
@@ -2120,7 +2158,7 @@
 					 "top-al");
 			zfcp_erp_adapter_shutdown(adapter, 0);
 			return -EIO;
-		case FSF_TOPO_FABRIC:
+		case FC_PORTTYPE_NPORT:
 			ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
 				      "network detected at adapter %s.\n",
 				      zfcp_get_busid_by_adapter(adapter));
@@ -2133,7 +2171,6 @@
 					"of a type known to the zfcp "
 					"driver, shutting down adapter\n",
 					zfcp_get_busid_by_adapter(adapter));
-			adapter->fc_topology = FSF_TOPO_ERROR;
 			debug_text_exception(fsf_req->adapter->erp_dbf, 0,
 					     "unknown-topo");
 			zfcp_erp_adapter_shutdown(adapter, 0);
@@ -2293,14 +2330,13 @@
 		data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
 		if (data)
 			memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
-		if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
-			adapter->physical_wwpn = bottom->wwpn;
-			adapter->physical_s_id = bottom->fc_port_id;
-		} else {
-			adapter->physical_wwpn = fc_host_port_name(shost);
-			adapter->physical_s_id = fc_host_port_id(shost);
-		}
+		if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
+			fc_host_permanent_port_name(shost) = bottom->wwpn;
+		else
+			fc_host_permanent_port_name(shost) =
+				fc_host_port_name(shost);
 		fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
+		fc_host_supported_speeds(shost) = bottom->supported_speed;
 		break;
 
 	case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 48719f0..e734415 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -166,6 +166,7 @@
 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD	0x00000004
 #define FSF_STATUS_READ_LINK_DOWN		0x00000005
 #define FSF_STATUS_READ_LINK_UP          	0x00000006
+#define FSF_STATUS_READ_NOTIFICATION_LOST	0x00000009
 #define FSF_STATUS_READ_CFDC_UPDATED		0x0000000A
 #define FSF_STATUS_READ_CFDC_HARDENED		0x0000000B
 #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT	0x0000000C
@@ -179,6 +180,16 @@
 #define FSF_STATUS_READ_SUB_FDISC_FAILED	0x00000001
 #define FSF_STATUS_READ_SUB_FIRMWARE_UPDATE	0x00000002
 
+/* status subtypes for unsolicited status notification lost */
+#define FSF_STATUS_READ_SUB_INCOMING_ELS	0x00000001
+#define FSF_STATUS_READ_SUB_SENSE_DATA		0x00000002
+#define FSF_STATUS_READ_SUB_LINK_STATUS		0x00000004
+#define FSF_STATUS_READ_SUB_PORT_CLOSED		0x00000008
+#define FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD	0x00000010
+#define FSF_STATUS_READ_SUB_ACT_UPDATED		0x00000020
+#define FSF_STATUS_READ_SUB_ACT_HARDENED	0x00000040
+#define FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT 0x00000080
+
 /* status subtypes for CFDC */
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE	0x00000002
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
@@ -188,7 +199,6 @@
 #define FSF_TOPO_P2P				0x00000001
 #define FSF_TOPO_FABRIC				0x00000002
 #define FSF_TOPO_AL				0x00000003
-#define FSF_TOPO_FABRIC_VIRT			0x00000004
 
 /* data direction for FCP commands */
 #define FSF_DATADIR_WRITE			0x00000001
@@ -211,6 +221,7 @@
 /* channel features */
 #define FSF_FEATURE_CFDC			0x00000002
 #define FSF_FEATURE_LUN_SHARING			0x00000004
+#define FSF_FEATURE_NOTIFICATION_LOST		0x00000008
 #define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS        0x00000020
 #define FSF_FEATURE_UPDATE_ALERT		0x00000100
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 66608d1..3c2cbcc 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -49,8 +49,6 @@
 
 static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
 					  scsi_lun_t);
-static struct zfcp_port *zfcp_port_lookup(struct zfcp_adapter *, int,
-					  scsi_id_t);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
 
@@ -406,18 +404,6 @@
 	return retval;
 }
 
-static struct zfcp_port *
-zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
-{
-	struct zfcp_port *port;
-
-	list_for_each_entry(port, &adapter->port_list_head, list) {
-		if (port->rport && (id == port->rport->scsi_target_id))
-			return port;
-	}
-	return (struct zfcp_port *) NULL;
-}
-
 /**
  * zfcp_scsi_eh_abort_handler - abort the specified SCSI command
  * @scpnt: pointer to scsi_cmnd to be aborted 
@@ -731,70 +717,164 @@
 /*
  * Support functions for FC transport class
  */
-static void
-zfcp_get_port_id(struct scsi_target *starget)
+static struct fc_host_statistics*
+zfcp_init_fc_host_stats(struct zfcp_adapter *adapter)
 {
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-	struct zfcp_port *port;
-	unsigned long flags;
+	struct fc_host_statistics *fc_stats;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-	if (port)
-		fc_starget_port_id(starget) = port->d_id;
-	else
-		fc_starget_port_id(starget) = -1;
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	if (!adapter->fc_stats) {
+		fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL);
+		if (!fc_stats)
+			return NULL;
+		adapter->fc_stats = fc_stats; /* freed in adater_dequeue */
+	}
+	memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats));
+	return adapter->fc_stats;
 }
 
 static void
-zfcp_get_port_name(struct scsi_target *starget)
+zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats,
+			  struct fsf_qtcb_bottom_port *data,
+			  struct fsf_qtcb_bottom_port *old)
 {
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-	struct zfcp_port *port;
-	unsigned long flags;
-
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-	if (port)
-		fc_starget_port_name(starget) = port->wwpn;
-	else
-		fc_starget_port_name(starget) = -1;
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	fc_stats->seconds_since_last_reset = data->seconds_since_last_reset -
+		old->seconds_since_last_reset;
+	fc_stats->tx_frames = data->tx_frames - old->tx_frames;
+	fc_stats->tx_words = data->tx_words - old->tx_words;
+	fc_stats->rx_frames = data->rx_frames - old->rx_frames;
+	fc_stats->rx_words = data->rx_words - old->rx_words;
+	fc_stats->lip_count = data->lip - old->lip;
+	fc_stats->nos_count = data->nos - old->nos;
+	fc_stats->error_frames = data->error_frames - old->error_frames;
+	fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames;
+	fc_stats->link_failure_count = data->link_failure - old->link_failure;
+	fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync;
+	fc_stats->loss_of_signal_count = data->loss_of_signal -
+		old->loss_of_signal;
+	fc_stats->prim_seq_protocol_err_count = data->psp_error_counts -
+		old->psp_error_counts;
+	fc_stats->invalid_tx_word_count = data->invalid_tx_words -
+		old->invalid_tx_words;
+	fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs;
+	fc_stats->fcp_input_requests = data->input_requests -
+		old->input_requests;
+	fc_stats->fcp_output_requests = data->output_requests -
+		old->output_requests;
+	fc_stats->fcp_control_requests = data->control_requests -
+		old->control_requests;
+	fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb;
+	fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb;
 }
 
 static void
-zfcp_get_node_name(struct scsi_target *starget)
+zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats,
+		       struct fsf_qtcb_bottom_port *data)
 {
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-	struct zfcp_port *port;
-	unsigned long flags;
+	fc_stats->seconds_since_last_reset = data->seconds_since_last_reset;
+	fc_stats->tx_frames = data->tx_frames;
+	fc_stats->tx_words = data->tx_words;
+	fc_stats->rx_frames = data->rx_frames;
+	fc_stats->rx_words = data->rx_words;
+	fc_stats->lip_count = data->lip;
+	fc_stats->nos_count = data->nos;
+	fc_stats->error_frames = data->error_frames;
+	fc_stats->dumped_frames = data->dumped_frames;
+	fc_stats->link_failure_count = data->link_failure;
+	fc_stats->loss_of_sync_count = data->loss_of_sync;
+	fc_stats->loss_of_signal_count = data->loss_of_signal;
+	fc_stats->prim_seq_protocol_err_count = data->psp_error_counts;
+	fc_stats->invalid_tx_word_count = data->invalid_tx_words;
+	fc_stats->invalid_crc_count = data->invalid_crcs;
+	fc_stats->fcp_input_requests = data->input_requests;
+	fc_stats->fcp_output_requests = data->output_requests;
+	fc_stats->fcp_control_requests = data->control_requests;
+	fc_stats->fcp_input_megabytes = data->input_mb;
+	fc_stats->fcp_output_megabytes = data->output_mb;
+}
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-	if (port)
-		fc_starget_node_name(starget) = port->wwnn;
-	else
-		fc_starget_node_name(starget) = -1;
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+/**
+ * zfcp_get_fc_host_stats - provide fc_host_statistics for scsi_transport_fc
+ *
+ * assumption: scsi_transport_fc synchronizes calls of
+ *             get_fc_host_stats and reset_fc_host_stats
+ *             (XXX to be checked otherwise introduce locking)
+ */
+static struct fc_host_statistics *
+zfcp_get_fc_host_stats(struct Scsi_Host *shost)
+{
+	struct zfcp_adapter *adapter;
+	struct fc_host_statistics *fc_stats;
+	struct fsf_qtcb_bottom_port *data;
+	int ret;
+
+	adapter = (struct zfcp_adapter *)shost->hostdata[0];
+	fc_stats = zfcp_init_fc_host_stats(adapter);
+	if (!fc_stats)
+		return NULL;
+
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+	memset(data, 0, sizeof(*data));
+
+	ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+	if (ret) {
+		kfree(data);
+		return NULL; /* XXX return zeroed fc_stats? */
+	}
+
+	if (adapter->stats_reset &&
+	    ((jiffies/HZ - adapter->stats_reset) <
+	     data->seconds_since_last_reset)) {
+		zfcp_adjust_fc_host_stats(fc_stats, data,
+					  adapter->stats_reset_data);
+	} else
+		zfcp_set_fc_host_stats(fc_stats, data);
+
+	kfree(data);
+	return fc_stats;
+}
+
+static void
+zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
+{
+	struct zfcp_adapter *adapter;
+	struct fsf_qtcb_bottom_port *data, *old_data;
+	int ret;
+
+	adapter = (struct zfcp_adapter *)shost->hostdata[0];
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return;
+	memset(data, 0, sizeof(*data));
+
+	ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+	if (ret == 0) {
+		adapter->stats_reset = jiffies/HZ;
+		old_data = adapter->stats_reset_data;
+		adapter->stats_reset_data = data; /* finally freed in
+						     adater_dequeue */
+		kfree(old_data);
+	}
 }
 
 struct fc_function_template zfcp_transport_functions = {
-	.get_starget_port_id = zfcp_get_port_id,
-	.get_starget_port_name = zfcp_get_port_name,
-	.get_starget_node_name = zfcp_get_node_name,
 	.show_starget_port_id = 1,
 	.show_starget_port_name = 1,
 	.show_starget_node_name = 1,
 	.show_rport_supported_classes = 1,
 	.show_host_node_name = 1,
 	.show_host_port_name = 1,
+	.show_host_permanent_port_name = 1,
 	.show_host_supported_classes = 1,
+	.show_host_supported_speeds = 1,
 	.show_host_maxframe_size = 1,
 	.show_host_serial_number = 1,
+	.get_fc_host_stats = zfcp_get_fc_host_stats,
+	.reset_fc_host_stats = zfcp_reset_fc_host_stats,
+	/* no functions registered for following dynamic attributes but
+	   directly set by LLDD */
+	.show_host_port_type = 1,
 	.show_host_speed = 1,
 	.show_host_port_id = 1,
 };
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c
index 0cd4352..9f26225 100644
--- a/drivers/s390/scsi/zfcp_sysfs_adapter.c
+++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c
@@ -33,14 +33,6 @@
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
 
-static const char fc_topologies[5][25] = {
-	"<error>",
-	"point-to-point",
-	"fabric",
-	"arbitrated loop",
-	"fabric (virt. adapter)"
-};
-
 /**
  * ZFCP_DEFINE_ADAPTER_ATTR
  * @_name:   name of show attribute
@@ -69,12 +61,8 @@
 ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id);
 ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
-ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
-ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
-			 fc_topologies[adapter->fc_topology]);
 ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
 			 adapter->hardware_version);
-ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no);
 ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
 			 (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
 
@@ -259,9 +247,6 @@
 	&dev_attr_physical_s_id.attr,
 	&dev_attr_card_version.attr,
 	&dev_attr_lic_version.attr,
-	&dev_attr_fc_service_class.attr,
-	&dev_attr_fc_topology.attr,
-	&dev_attr_scsi_host_no.attr,
 	&dev_attr_status.attr,
 	&dev_attr_hardware_version.attr,
 	NULL
diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c
index c55e82d..3924eb3 100644
--- a/drivers/s390/scsi/zfcp_sysfs_port.c
+++ b/drivers/s390/scsi/zfcp_sysfs_port.c
@@ -65,8 +65,6 @@
 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL);
 
 ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
-ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn);
-ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id);
 ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
 		      (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
 ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -245,8 +243,6 @@
 	&dev_attr_failed.attr,
 	&dev_attr_in_recovery.attr,
 	&dev_attr_status.attr,
-	&dev_attr_wwnn.attr,
-	&dev_attr_d_id.attr,
 	&dev_attr_access_denied.attr,
 	NULL
 };
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c
index 0556642..2f50815 100644
--- a/drivers/s390/scsi/zfcp_sysfs_unit.c
+++ b/drivers/s390/scsi/zfcp_sysfs_unit.c
@@ -65,7 +65,6 @@
 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL);
 
 ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status));
-ZFCP_DEFINE_UNIT_ATTR(scsi_lun, "0x%x\n", unit->scsi_lun);
 ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask
 		      (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status));
 ZFCP_DEFINE_UNIT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -138,7 +137,6 @@
 		   zfcp_sysfs_unit_failed_store);
 
 static struct attribute *zfcp_unit_attrs[] = {
-	&dev_attr_scsi_lun.attr,
 	&dev_attr_failed.attr,
 	&dev_attr_in_recovery.attr,
 	&dev_attr_status.attr,
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 92e6c5639..015db40 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -92,7 +92,6 @@
 
 /* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
 static unsigned char * tmp_buf = NULL;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 DECLARE_TASK_QUEUE(tq_aurora);
 
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 3ff74f4..31c4975 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -73,6 +73,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -615,7 +616,7 @@
 	void __user *argp = (void __user *)arg;
 
 	/* Only let one of these through at a time */
-	if (down_interruptible(&tw_dev->ioctl_sem)) {
+	if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
 		retval = TW_IOCTL_ERROR_OS_EINTR;
 		goto out;
 	}
@@ -852,7 +853,7 @@
 	/* Now free ioctl buf memory */
 	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
 out2:
-	up(&tw_dev->ioctl_sem);
+	mutex_unlock(&tw_dev->ioctl_lock);
 out:
 	return retval;
 } /* End twa_chrdev_ioctl() */
@@ -1182,7 +1183,7 @@
 	tw_dev->error_sequence_id = 1;
 	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-	init_MUTEX(&tw_dev->ioctl_sem);
+	mutex_init(&tw_dev->ioctl_lock);
 	init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
 	retval = 0;
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 46f22cd..1b16d57 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -672,7 +672,7 @@
 	u32                     ioctl_msec;
 	int			chrdev_request_id;
 	wait_queue_head_t	ioctl_wqueue;
-	struct semaphore	ioctl_sem;
+	struct mutex		ioctl_lock;
 	char			aen_clobber;
 	unsigned short		working_srl;
 	unsigned short		working_branch;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 283f6d2..25f678d 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -203,6 +203,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -888,7 +889,7 @@
 	dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
 
 	/* Only let one of these through at a time */
-	if (down_interruptible(&tw_dev->ioctl_sem))
+	if (mutex_lock_interruptible(&tw_dev->ioctl_lock))
 		return -EINTR;
 
 	/* First copy down the buffer length */
@@ -1029,7 +1030,7 @@
 	/* Now free ioctl buf memory */
 	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
 out:
-	up(&tw_dev->ioctl_sem);
+	mutex_unlock(&tw_dev->ioctl_lock);
 	return retval;
 } /* End tw_chrdev_ioctl() */
 
@@ -1270,7 +1271,7 @@
 	tw_dev->pending_tail = TW_Q_START;
 	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-	init_MUTEX(&tw_dev->ioctl_sem);
+	mutex_init(&tw_dev->ioctl_lock);
 	init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
 	return 0;
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 4f81fc3..31fe5ea 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -420,7 +420,7 @@
 	u32			max_sector_count;
 	u32			aen_count;
 	struct Scsi_Host	*host;
-	struct semaphore	ioctl_sem;
+	struct mutex		ioctl_lock;
 	unsigned short		aen_queue[TW_Q_LENGTH];
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 9d6040b..1c45934 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2216,6 +2216,7 @@
 		HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
 		HostAdapter->Bus = ProbeInfo->Bus;
 		HostAdapter->Device = ProbeInfo->Device;
+		HostAdapter->PCI_Device = ProbeInfo->PCI_Device;
 		HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
 		HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
 		/*
@@ -2296,7 +2297,7 @@
 				scsi_host_put(Host);
 			} else {
 				BusLogic_InitializeHostStructure(HostAdapter, Host);
-				scsi_add_host(Host, NULL);
+				scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
 				scsi_scan_host(Host);
 				BusLogicHostAdapterCount++;
 			}
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 6e0c059..320e765 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -80,7 +80,7 @@
 obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogicfas408.o
 obj-$(CONFIG_SCSI_QLOGIC_FC)	+= qlogicfc.o 
 obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
-obj-$(CONFIG_SCSI_QLA2XXX)	+= qla2xxx/
+obj-$(CONFIG_SCSI_QLA_FC)	+= qla2xxx/
 obj-$(CONFIG_SCSI_LPFC)		+= lpfc/
 obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
 obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
diff --git a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README
deleted file mode 100644
index 4193865..0000000
--- a/drivers/scsi/aacraid/README
+++ /dev/null
@@ -1,74 +0,0 @@
-AACRAID Driver for Linux (take two)
-
-Introduction
--------------------------
-The aacraid driver adds support for Adaptec (http://www.adaptec.com)
-RAID controllers. This is a major rewrite from the original 
-Adaptec supplied driver. It has signficantly cleaned up both the code
-and the running binary size (the module is less than half the size of
-the original).
-
-Supported Cards/Chipsets
--------------------------
-	Adaptec 2020S
-	Adaptec 2025S
-	Adaptec 2120S
-	Adaptec 2130S
-	Adaptec 2200S
-	Adaptec 2230S
-	Adaptec 2240S
-	Adaptec 2410SA
-	Adaptec 2610SA
-	Adaptec 2810SA
-	Adaptec 21610SA
-	Adaptec 3230S
-	Adaptec 3240S
-	Adaptec 4000SAS
-	Adaptec 4005SAS
-	Adaptec 4800SAS
-	Adaptec 4805SAS
-	Adaptec 5400S
-	Dell PERC 2 Quad Channel
-	Dell PERC 2/Si
-	Dell PERC 3/Si
-	Dell PERC 3/Di
-	Dell CERC 2
-	HP NetRAID-4M
-	Legend S220
-	Legend S230
-	IBM ServeRAID 8i
-	ICP 9014R0
-	ICP 9024R0
-	ICP 9047MA
-	ICP 9087MA
-	ICP 9085LI
-	ICP 5085AU
-
-People
--------------------------
-Alan Cox <alan@redhat.com>
-Christoph Hellwig <hch@infradead.org>	(updates for new-style PCI probing and SCSI host registration,
-					 small cleanups/fixes)
-Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
-Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
-					 added new ioctls, changed scsi interface to use new error handler,
-					 increased the number of fibs and outstanding commands to a container)
-
-					(fixed 64bit and 64G memory model, changed confusing naming convention
-					 where fibs that go to the hardware are consistently called hw_fibs and
-					 not just fibs like the name of the driver tracking structure)
-Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas. Performance tuning, card failover and bug mitigations.
-
-Original Driver
--------------------------
-Adaptec Unix OEM Product Group
-
-Mailing List
--------------------------
-linux-scsi@vger.kernel.org (Interested parties troll here)
-Also note this is very different to Brian's original driver
-so don't expect him to support it.
-Adaptec does support this driver.  Contact either tech support or Mark Salyzyn.
-
-Original by Brian Boerner February 2001
-Rewritten by Alan Cox, November 2001
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 30fd8d6..66dbb6d 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -532,6 +532,13 @@
 #define AAC_QUIRK_MASTER 0x0008
 
 /*
+ * Some adapter firmware perform poorly when it must split up scatter gathers
+ * in order to deal with the limits of the underlying CHIM. This limit in this
+ * class of adapters is 17 scatter gather elements.
+ */
+#define AAC_QUIRK_17SG	0x0010
+
+/*
  *	The adapter interface specs all queues to be located in the same
  *	physically contigous block. The host structure that defines the
  *	commuication queues will assume they are each a separate physically
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index ef623bd..4fe79cd 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -85,6 +85,10 @@
 	if (size < le16_to_cpu(kfib->header.SenderSize))
 		size = le16_to_cpu(kfib->header.SenderSize);
 	if (size > dev->max_fib_size) {
+		if (size > 2048) {
+			retval = -EINVAL;
+			goto cleanup;
+		}
 		/* Highjack the hw_fib */
 		hw_fib = fibptr->hw_fib;
 		hw_fib_pa = fibptr->hw_fib_pa;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 9b9062f..0bf5f9a 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -200,10 +200,10 @@
 	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "Callisto        ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA       ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA       ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
-	{ aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+	{ aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1, AAC_QUIRK_17SG }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1, AAC_QUIRK_17SG }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2026ZCR     ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2610SA      ", 1 }, /* SATA 6Ch (Bearcat) */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2240S       ", 1 }, /* ASR-2240S (SabreExpress) */
@@ -574,7 +574,15 @@
 	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
 	int len;
 
-	len = snprintf(buf, PAGE_SIZE, "%s\n",
+	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+		while (*cp && *cp != ' ')
+			++cp;
+		while (*cp == ' ')
+			++cp;
+		len = snprintf(buf, PAGE_SIZE, "%s\n", cp);
+	} else
+		len = snprintf(buf, PAGE_SIZE, "%s\n",
 		  aac_drivers[dev->cardtype].model);
 	return len;
 }
@@ -585,7 +593,15 @@
 	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
 	int len;
 
-	len = snprintf(buf, PAGE_SIZE, "%s\n",
+	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+		char * cp = dev->supplement_adapter_info.AdapterTypeText;
+		while (*cp && *cp != ' ')
+			++cp;
+		len = snprintf(buf, PAGE_SIZE, "%.*s\n",
+		  (int)(cp - (char *)dev->supplement_adapter_info.AdapterTypeText),
+		  dev->supplement_adapter_info.AdapterTypeText);
+	} else
+		len = snprintf(buf, PAGE_SIZE, "%s\n",
 		  aac_drivers[dev->cardtype].vname);
 	return len;
 }
@@ -837,6 +853,13 @@
  		  = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
  	}
 
+ 	if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+			(aac->scsi_host_ptr->sg_tablesize > 17)) {
+ 		aac->scsi_host_ptr->sg_tablesize = 17;
+ 		aac->scsi_host_ptr->max_sectors
+ 		  = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
+ 	}
+
 	/*
 	 * Firware printf works only with older firmware.
 	 */
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index ac8de03..6c2c395 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -42,13 +42,13 @@
 config AIC7XXX_RESET_DELAY_MS
 	int "Initial bus reset delay in milli-seconds"
 	depends on SCSI_AIC7XXX
-	default "15000"
+	default "5000"
 	---help---
 	The number of milliseconds to delay after an initial bus reset.
 	The bus settle delay following all error recovery actions is
 	dictated by the SCSI layer and is not affected by this value.
 
-	Default: 15000 (15 seconds)
+	Default: 5000 (5 seconds)
 
 config AIC7XXX_PROBE_EISA_VL
 	bool "Probe for EISA and VL AIC7XXX Adapters"
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 653fb0b..2cfdbef 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#95 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#108 $
  *
  * $FreeBSD$
  */
@@ -75,8 +75,7 @@
 #define INITIATOR_WILDCARD	(~0)
 #define	SCB_LIST_NULL		0xFF00
 #define	SCB_LIST_NULL_LE	(ahd_htole16(SCB_LIST_NULL))
-#define QOUTFIFO_ENTRY_VALID 0x8000
-#define QOUTFIFO_ENTRY_VALID_LE (ahd_htole16(0x8000))
+#define QOUTFIFO_ENTRY_VALID 0x80
 #define SCBID_IS_NULL(scbid) (((scbid) & 0xFF00 ) == SCB_LIST_NULL)
 
 #define SCSIID_TARGET(ahd, scsiid)	\
@@ -1053,6 +1052,13 @@
 
 typedef void ahd_callback_t (void *);
 
+struct ahd_completion
+{
+	uint16_t	tag;
+	uint8_t		sg_status;
+	uint8_t		valid_tag;
+};
+
 struct ahd_softc {
 	bus_space_tag_t           tags[2];
 	bus_space_handle_t        bshs[2];
@@ -1062,6 +1068,7 @@
 	struct scb_data		  scb_data;
 
 	struct hardware_scb	 *next_queued_hscb;
+	struct map_node		 *next_queued_hscb_map;
 
 	/*
 	 * SCBs that have been sent to the controller
@@ -1140,16 +1147,23 @@
 	ahd_flag		  flags;
 	struct seeprom_config	 *seep_config;
 
-	/* Values to store in the SEQCTL register for pause and unpause */
-	uint8_t			  unpause;
-	uint8_t			  pause;
-
 	/* Command Queues */
+	struct ahd_completion	  *qoutfifo;
 	uint16_t		  qoutfifonext;
 	uint16_t		  qoutfifonext_valid_tag;
 	uint16_t		  qinfifonext;
 	uint16_t		  qinfifo[AHD_SCB_MAX];
-	uint16_t		 *qoutfifo;
+
+	/*
+	 * Our qfreeze count.  The sequencer compares
+	 * this value with its own counter to determine
+	 * whether to allow selections to occur.
+	 */
+	uint16_t		  qfreeze_cnt;
+
+	/* Values to store in the SEQCTL register for pause and unpause */
+	uint8_t			  unpause;
+	uint8_t			  pause;
 
 	/* Critical Section Data */
 	struct cs		 *critical_sections;
@@ -1197,8 +1211,7 @@
 	 */
 	bus_dma_tag_t		  parent_dmat;
 	bus_dma_tag_t		  shared_data_dmat;
-	bus_dmamap_t		  shared_data_dmamap;
-	dma_addr_t		  shared_data_busaddr;
+	struct map_node		  shared_data_map;
 
 	/* Information saved through suspend/resume cycles */
 	struct ahd_suspend_state  suspend_state;
@@ -1296,9 +1309,9 @@
 };
 
 /****************************** PCI Structures ********************************/
-#define AHD_PCI_IOADDR0	PCIR_MAPS	/* I/O BAR*/
-#define AHD_PCI_MEMADDR	(PCIR_MAPS + 4)	/* Memory BAR */
-#define AHD_PCI_IOADDR1	(PCIR_MAPS + 12)/* Second I/O BAR */
+#define AHD_PCI_IOADDR0	PCIR_BAR(0)	/* I/O BAR*/
+#define AHD_PCI_MEMADDR	PCIR_BAR(1)	/* Memory BAR */
+#define AHD_PCI_IOADDR1	PCIR_BAR(3)	/* Second I/O BAR */
 
 typedef int (ahd_device_setup_t)(struct ahd_softc *);
 
diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
index cca58ed..3a32047 100644
--- a/drivers/scsi/aic7xxx/aic79xx.reg
+++ b/drivers/scsi/aic7xxx/aic79xx.reg
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -65,13 +65,6 @@
 		mvi	MODE_PTR, MK_MODE(src, dst);			\
 	}
 
-#define TOGGLE_DFF_MODE							\
-	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {			\
-		call	toggle_dff_mode_work_around;			\
-	} else {							\
-		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);		\
-	}
-	
 #define RESTORE_MODE(mode)						\
 	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {			\
 		mov	mode call set_mode_work_around;			\
@@ -1199,7 +1192,7 @@
 
 /*
  * LQ Packet In
- * The last LQ Packet received
+ * The last LQ Packet recieved
  */
 register LQIN {
 	address			0x020
@@ -3542,10 +3535,34 @@
 	COMPLETE_DMA_SCB_HEAD {
 		size		2
 	}
-	/* Counting semaphore to prevent new select-outs */
+	/*
+	 * tail of list of SCBs that have
+	 * completed but need to be uploaded
+	 * to the host prior to being completed.
+	 */
+	COMPLETE_DMA_SCB_TAIL {
+		size		2
+	}
+	/*
+	 * head of list of SCBs that have
+	 * been uploaded to the host, but cannot
+	 * be completed until the QFREEZE is in
+	 * full effect (i.e. no selections pending).
+	 */
+	COMPLETE_ON_QFREEZE_HEAD {
+		size		2
+	}
+	/*
+	 * Counting semaphore to prevent new select-outs
+	 * The queue is frozen so long as the sequencer
+	 * and kernel freeze counts differ.
+	 */
 	QFREEZE_COUNT {
 		size		2
 	}
+	KERNEL_QFREEZE_COUNT {
+		size		2
+	}
 	/*
 	 * Mode to restore on legacy idle loop exit.
 	 */
@@ -3625,6 +3642,17 @@
 		size		1
 	}
 	/*
+	 * Kernel and sequencer offsets into the queue of
+	 * incoming target mode command descriptors.  The
+	 * queue is full when the KERNEL_TQINPOS == TQINPOS.
+	 */
+	KERNEL_TQINPOS {
+		size		1
+	}
+	TQINPOS {                
+		size		1
+	}
+	/*
 	 * Base address of our shared data with the kernel driver in host
 	 * memory.  This includes the qoutfifo and target mode
 	 * incoming command queue.
@@ -3639,17 +3667,6 @@
 	QOUTFIFO_NEXT_ADDR {
 		size		4
 	}
-	/*
-	 * Kernel and sequencer offsets into the queue of
-	 * incoming target mode command descriptors.  The
-	 * queue is full when the KERNEL_TQINPOS == TQINPOS.
-	 */
-	KERNEL_TQINPOS {
-		size		1
-	}
-	TQINPOS {                
-		size		1
-	}
 	ARG_1 {
 		size		1
 		mask	SEND_MSG		0x80
@@ -3951,6 +3968,7 @@
 const SG_SIZEOF download
 const PKT_OVERRUN_BUFOFFSET download
 const SCB_TRANSFER_SIZE	download
+const CACHELINE_MASK download
 
 /*
  * BIOS SCB offsets
diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
index 65339bc..bef1f9d 100644
--- a/drivers/scsi/aic7xxx/aic79xx.seq
+++ b/drivers/scsi/aic7xxx/aic79xx.seq
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#99 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -68,13 +68,47 @@
 	}
 	SET_MODE(M_SCSI, M_SCSI)
 	test	SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus;
-	test	SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus;
+	test	SEQ_FLAGS2, SELECTOUT_QFROZEN jz check_waiting_list;
+	/*
+	 * If the kernel has caught up with us, thaw the queue.
+	 */
+	mov	A, KERNEL_QFREEZE_COUNT;
+	cmp	QFREEZE_COUNT, A jne check_frozen_completions;
+	mov	A, KERNEL_QFREEZE_COUNT[1];
+	cmp	QFREEZE_COUNT[1], A jne check_frozen_completions;
+	and	SEQ_FLAGS2, ~SELECTOUT_QFROZEN;
+	jmp	check_waiting_list;
+check_frozen_completions:
+	test	SSTAT0, SELDO|SELINGO jnz idle_loop_checkbus;
+BEGIN_CRITICAL;
+	/*
+	 * If we have completions stalled waiting for the qfreeze
+	 * to take effect, move them over to the complete_scb list
+	 * now that no selections are pending.
+	 */
+	cmp	COMPLETE_ON_QFREEZE_HEAD[1],SCB_LIST_NULL je idle_loop_checkbus;
+	/*
+	 * Find the end of the qfreeze list.  The first element has
+	 * to be treated specially.
+	 */
+	bmov	SCBPTR, COMPLETE_ON_QFREEZE_HEAD, 2;
+	cmp 	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je join_lists;
+	/*
+	 * Now the normal loop.
+	 */
+	bmov	SCBPTR, SCB_NEXT_COMPLETE, 2;
+	cmp 	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . - 1;
+join_lists:
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
+	bmov	COMPLETE_SCB_HEAD, COMPLETE_ON_QFREEZE_HEAD, 2;
+	mvi	COMPLETE_ON_QFREEZE_HEAD[1], SCB_LIST_NULL;
+	jmp	idle_loop_checkbus;
+check_waiting_list:
 	cmp	WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus;
 	/*
 	 * ENSELO is cleared by a SELDO, so we must test for SELDO
 	 * one last time.
 	 */
-BEGIN_CRITICAL;
 	test	SSTAT0, SELDO jnz select_out;
 END_CRITICAL;
 	call	start_selection;
@@ -90,6 +124,13 @@
 	test	SSTAT2, NONPACKREQ jz . + 2;
 	call	unexpected_nonpkt_phase_find_ctxt;
 	if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+		/*
+		 * On Rev A. hardware, the busy LED is only
+		 * turned on automaically during selections
+		 * and re-selections.  Make the LED status
+		 * more useful by forcing it to be on so
+		 * long as one of our data FIFOs is active.
+		 */
 		and	A, FIFO0FREE|FIFO1FREE, DFFSTAT;
 		cmp	A, FIFO0FREE|FIFO1FREE jne . + 3;
 		and	SBLKCTL, ~DIAGLEDEN|DIAGLEDON;
@@ -101,9 +142,9 @@
 	call	idle_loop_cchan;
 	jmp	idle_loop;
 
-BEGIN_CRITICAL;
 idle_loop_gsfifo:
 	SET_MODE(M_SCSI, M_SCSI)
+BEGIN_CRITICAL;
 idle_loop_gsfifo_in_scsi_mode:
 	test	LQISTAT2, LQIGSAVAIL jz return;
 	/*
@@ -152,11 +193,15 @@
 
 idle_loop_service_fifos:
 	SET_MODE(M_DFF0, M_DFF0)
+BEGIN_CRITICAL;
 	test	LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo;
 	call	longjmp;
+END_CRITICAL;
 idle_loop_next_fifo:
 	SET_MODE(M_DFF1, M_DFF1)
+BEGIN_CRITICAL;
 	test	LONGJMP_ADDR[1], INVALID_ADDR jz longjmp;
+END_CRITICAL;
 return:
 	ret;
 
@@ -170,7 +215,6 @@
 	test	CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle;
 	test	CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog;
 	test	CCSCBCTL, CCSCBDONE jz return;
-END_CRITICAL;
 	/* FALLTHROUGH */
 scbdma_tohost_done:
 	test	CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
@@ -180,26 +224,18 @@
 	 * bad SCSI status (currently only for underruns), we
 	 * queue the SCB for normal completion.  Otherwise, we
 	 * wait until any select-out activity has halted, and
-	 * then notify the host so that the transaction can be
-	 * dealt with.
+	 * then queue the completion.
 	 */
-	test	SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host;
 	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
 	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	cmp	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . + 2;
+	mvi	COMPLETE_DMA_SCB_TAIL[1], SCB_LIST_NULL;
+	test	SCB_SCSI_STATUS, 0xff jz scbdma_queue_completion;
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_ON_QFREEZE_HEAD, 2;
+	bmov	COMPLETE_ON_QFREEZE_HEAD, SCBPTR, 2 ret;
+scbdma_queue_completion:
 	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
 	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
-scbdma_notify_host:
-	SET_MODE(M_SCSI, M_SCSI)
-	test	SCSISEQ0, ENSELO jnz return;
-	test	SSTAT0, (SELDO|SELINGO) jnz return;
-	SET_MODE(M_CCHAN, M_CCHAN)
-	/*
-	 * Remove SCB and notify host.
-	 */
-	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
-	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
-	SET_SEQINTCODE(BAD_SCB_STATUS)
-	ret;
 fill_qoutfifo_dmadone:
 	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
 	call	qoutfifo_updated;
@@ -208,6 +244,7 @@
 	test	QOFF_CTLSTA, SDSCB_ROLLOVR jz return;
 	bmov	QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4;
 	xor	QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret;
+END_CRITICAL;
 
 qoutfifo_updated:
 	/*
@@ -324,14 +361,15 @@
 	 * Keep track of the SCBs we are dmaing just
 	 * in case the DMA fails or is aborted.
 	 */
-	mov	A, QOUTFIFO_ENTRY_VALID_TAG;
 	bmov	COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2;
 	mvi	CCSCBCTL, CCSCBRESET;
 	bmov	SCBHADDR, QOUTFIFO_NEXT_ADDR, 4;
+	mov	A, QOUTFIFO_NEXT_ADDR;
 	bmov	SCBPTR, COMPLETE_SCB_HEAD, 2;
 fill_qoutfifo_loop:
-	mov	CCSCBRAM, SCBPTR;
-	or	CCSCBRAM, A, SCBPTR[1];
+	bmov	CCSCBRAM, SCBPTR, 2;
+	mov	CCSCBRAM, SCB_SGPTR[0];
+	mov	CCSCBRAM, QOUTFIFO_ENTRY_VALID_TAG;
 	mov	NONE, SDSCB_QOFF;
 	inc	INT_COALESCING_CMDCOUNT;
 	add	CMDS_PENDING, -1;
@@ -339,6 +377,18 @@
 	cmp	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
 	cmp	CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done;
 	test	QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done;
+	/*
+	 * Don't cross an ADB or Cachline boundary when DMA'ing
+	 * completion entries.  In PCI mode, at least in 32/33
+	 * configurations, the SCB DMA engine may lose its place
+	 * in the data-stream should the target force a retry on
+	 * something other than an 8byte aligned boundary. In
+	 * PCI-X mode, we do this to avoid split transactions since
+	 * many chipsets seem to be unable to format proper split
+	 * completions to continue the data transfer.
+	 */
+	add	SINDEX, A, CCSCBADDR;
+	test	SINDEX, CACHELINE_MASK jz fill_qoutfifo_done;
 	bmov	SCBPTR, SCB_NEXT_COMPLETE, 2;
 	jmp	fill_qoutfifo_loop;
 fill_qoutfifo_done:
@@ -354,7 +404,6 @@
 	bmov	SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
 	bmov	SCBHADDR, SCB_BUSADDR, 4;
 	mvi	CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;
-END_CRITICAL;
 
 /*
  * Either post or fetch an SCB from host memory.  The caller
@@ -371,9 +420,19 @@
 	mvi	SCBHCNT, SCB_TRANSFER_SIZE;
 	mov	CCSCBCTL, SINDEX ret;
 
-BEGIN_CRITICAL;
 setjmp:
-	bmov	LONGJMP_ADDR, STACK, 2 ret;
+	/*
+	 * At least on the A, a return in the same
+	 * instruction as the bmov results in a return
+	 * to the caller, not to the new address at the
+	 * top of the stack.  Since we want the latter
+	 * (we use setjmp to register a handler from an
+	 * interrupt context but not invoke that handler
+	 * until we return to our idle loop), use a
+	 * separate ret instruction.
+	 */
+	bmov	LONGJMP_ADDR, STACK, 2;
+	ret;
 setjmp_inline:
 	bmov	LONGJMP_ADDR, STACK, 2;
 longjmp:
@@ -392,11 +451,6 @@
 	mvi	SEQINTCTL, INTVEC1DSL;
 	mov	MODE_PTR, SINDEX;
 	clr	SEQINTCTL ret;
-
-toggle_dff_mode_work_around:
-	mvi	SEQINTCTL, INTVEC1DSL;
-	xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
-	clr	SEQINTCTL ret;
 }
 
 
@@ -490,6 +544,21 @@
 SET_SRC_MODE	M_SCSI;
 SET_DST_MODE	M_SCSI;
 select_in:
+	if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+		/*
+		 * On Rev A. hardware, the busy LED is only
+		 * turned on automaically during selections
+		 * and re-selections.  Make the LED status
+		 * more useful by forcing it to be on from
+		 * the point of selection until our idle
+		 * loop determines that neither of our FIFOs
+		 * are busy.  This handles the non-packetized
+		 * case nicely as we will not return to the
+		 * idle loop until the busfree at the end of
+		 * each transaction.
+		 */
+		or	SBLKCTL, DIAGLEDEN|DIAGLEDON;
+	}
 	if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
 		/*
 		 * Test to ensure that the bus has not
@@ -528,6 +597,21 @@
 SET_DST_MODE	M_SCSI;
 select_out:
 BEGIN_CRITICAL;
+	if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+		/*
+		 * On Rev A. hardware, the busy LED is only
+		 * turned on automaically during selections
+		 * and re-selections.  Make the LED status
+		 * more useful by forcing it to be on from
+		 * the point of re-selection until our idle
+		 * loop determines that neither of our FIFOs
+		 * are busy.  This handles the non-packetized
+		 * case nicely as we will not return to the
+		 * idle loop until the busfree at the end of
+		 * each transaction.
+		 */
+		or	SBLKCTL, DIAGLEDEN|DIAGLEDON;
+	}
 	/* Clear out all SCBs that have been successfully sent. */
 	if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) {
 		/*
@@ -1000,15 +1084,9 @@
 /*
  * We received a "command complete" message.  Put the SCB on the complete
  * queue and trigger a completion interrupt via the idle loop.  Before doing
- * so, check to see if there
- * is a residual or the status byte is something other than STATUS_GOOD (0).
- * In either of these conditions, we upload the SCB back to the host so it can
- * process this information.  In the case of a non zero status byte, we 
- * additionally interrupt the kernel driver synchronously, allowing it to
- * decide if sense should be retrieved.  If the kernel driver wishes to request
- * sense, it will fill the kernel SCB with a request sense command, requeue
- * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
- * RETURN_1 to SEND_SENSE.
+ * so, check to see if there is a residual or the status byte is something
+ * other than STATUS_GOOD (0).  In either of these conditions, we upload the
+ * SCB back to the host so it can process this information.
  */
 mesgin_complete:
 
@@ -1053,6 +1131,7 @@
 	call	queue_scb_completion;
 	jmp	await_busfree;
 
+BEGIN_CRITICAL;
 freeze_queue:
 	/* Cancel any pending select-out. */
 	test	SSTAT0, SELDO|SELINGO jnz . + 2;
@@ -1063,6 +1142,7 @@
 	adc	QFREEZE_COUNT[1], A;
 	or	SEQ_FLAGS2, SELECTOUT_QFROZEN;
 	mov	A, ACCUM_SAVE ret;
+END_CRITICAL;
 
 /*
  * Complete the current FIFO's SCB if data for this same
@@ -1085,8 +1165,10 @@
 	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
 	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
 complete:
+BEGIN_CRITICAL;
 	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
 	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+END_CRITICAL;
 bad_status:
 	cmp	SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb;
 	call	freeze_queue;
@@ -1097,9 +1179,18 @@
 	 * it on the host.
 	 */
 	bmov	SCB_TAG, SCBPTR, 2;
-	bmov	SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2;
+BEGIN_CRITICAL;
+	or	SCB_SGPTR, SG_STATUS_VALID;
+	mvi	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL;
+	cmp	COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne add_dma_scb_tail;
 	bmov	COMPLETE_DMA_SCB_HEAD, SCBPTR, 2;
-	or	SCB_SGPTR, SG_STATUS_VALID ret;
+	bmov	COMPLETE_DMA_SCB_TAIL, SCBPTR, 2 ret;
+add_dma_scb_tail:
+	bmov	REG0, SCBPTR, 2;
+	bmov	SCBPTR, COMPLETE_DMA_SCB_TAIL, 2;
+	bmov	SCB_NEXT_COMPLETE, REG0, 2;
+	bmov	COMPLETE_DMA_SCB_TAIL, REG0, 2 ret;
+END_CRITICAL;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -1146,8 +1237,18 @@
 await_busfree_clrchn:
 	mvi	DFFSXFRCTL, CLRCHN;
 await_busfree_not_m_dff:
-	call	clear_target_state;
+	/* clear target specific flags */
+	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT;
 	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	/*
+	 * We only set BUSFREE status once either a new
+	 * phase has been detected or we are really
+	 * BUSFREE.  This allows the driver to know
+	 * that we are active on the bus even though
+	 * no identified transaction exists should a
+	 * timeout occur while awaiting busfree.
+	 */
+	mvi	LASTPHASE, P_BUSFREE;
 	test	SSTAT1, BUSFREE jnz idle_loop;
 	SET_SEQINTCODE(MISSED_BUSFREE)
 
@@ -1202,11 +1303,6 @@
 	call	allocate_fifo;
 	jmp	mesgin_done;
 
-clear_target_state:
-	mvi	LASTPHASE, P_BUSFREE;
-	/* clear target specific flags */
-	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
-
 phase_lock:     
 	if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) {
 		/*
@@ -1298,6 +1394,47 @@
 	test	CCSGCTL, CCSGENACK jnz return;
 
 	/*
+	 * Should the other FIFO get the S/G cache first?  If
+	 * both FIFOs have been allocated since we last checked
+	 * any FIFO, it is important that we service a FIFO
+	 * that is not actively on the bus first.  This guarantees
+	 * that a FIFO will be freed to handle snapshot requests for
+	 * any FIFO that is still on the bus.  Chips with RTI do not
+	 * perform snapshots, so don't bother with this test there.
+	 */
+	if ((ahd->features & AHD_RTI) == 0) {
+		/*
+		 * If we're not still receiving SCSI data,
+		 * it is safe to allocate the S/G cache to
+		 * this FIFO.
+		 */
+		test	DFCNTRL, SCSIEN jz idle_sgfetch_start;
+
+		/*
+		 * Switch to the other FIFO.  Non-RTI chips
+		 * also have the "set mode" bug, so we must
+		 * disable interrupts during the switch.
+		 */
+		mvi	SEQINTCTL, INTVEC1DSL;
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+
+		/*
+		 * If the other FIFO needs loading, then it
+		 * must not have claimed the S/G cache yet
+		 * (SG_CACHE_AVAIL would have been cleared in
+		 * the orginal FIFO mode and we test this above).
+		 * Return to the idle loop so we can process the
+		 * FIFO not currently on the bus first.
+		 */
+		test	SG_STATE, LOADING_NEEDED jz idle_sgfetch_okay;
+		clr	SEQINTCTL ret;
+idle_sgfetch_okay:
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+		clr	SEQINTCTL;
+	}
+
+idle_sgfetch_start:
+	/*
 	 * We fetch a "cacheline aligned" and sized amount of data
 	 * so we don't end up referencing a non-existant page.
 	 * Cacheline aligned is in quotes because the kernel will
@@ -1308,7 +1445,7 @@
 	mvi	SGHCNT, SG_PREFETCH_CNT;
 	if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {
 		/*
-		 * Need two instruction between "touches" of SGHADDR.
+		 * Need two instructions between "touches" of SGHADDR.
 		 */
 		nop;
 	}
@@ -1658,7 +1795,7 @@
 		 * savepointer in the current FIFO.  We do this so that
 		 * a pending CTXTDONE or SAVEPTR is visible in the active
 		 * FIFO.  This status is the only way we can detect if we
-		 * have lost the race (e.g. host paused us) and our attepts
+		 * have lost the race (e.g. host paused us) and our attempts
 		 * to disable the channel occurred after all REQs were
 		 * already seen and acked (REQINIT never comes true).
 		 */
@@ -1667,7 +1804,7 @@
 		test	DFCNTRL, DIRECTION jz interrupt_return;
 		and	DFCNTRL, ~SCSIEN;
 snapshot_wait_data_valid:
-		test	SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid;
+		test	SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz interrupt_return;
 		test	SSTAT1, REQINIT	jz snapshot_wait_data_valid;
 snapshot_data_valid:
 		or	DFCNTRL, SCSIEN;
@@ -1834,7 +1971,6 @@
 	dec	SCB_FIFO_USE_COUNT;
 	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
 	mvi	DFFSXFRCTL, CLRCHN ret;
-END_CRITICAL;
 
 /*
  * LAST_SEG_DONE status has been seen in the current FIFO.
@@ -1843,7 +1979,6 @@
  * Check for overrun and see if we can complete this command.
  */
 pkt_last_seg_done:
-BEGIN_CRITICAL;
 	/*
 	 * Mark transfer as completed.
 	 */
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 4e8f00d..db8f5ce 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -37,9 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#202 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#247 $
  */
 
 #ifdef __linux__
@@ -332,6 +330,14 @@
 	ahd_outb(ahd, SCSISEQ1,
 		 ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
 	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+	/*
+	 * Clear any pending sequencer interrupt.  It is no
+	 * longer relevant since we're resetting the Program
+	 * Counter.
+	 */
+	ahd_outb(ahd, CLRINT, CLRSEQINT);
+
 	ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);
 	ahd_unpause(ahd);
 }
@@ -373,13 +379,7 @@
 	saved_modes = ahd_save_modes(ahd);
 
 	/*
-	 * Complete any SCBs that just finished being
-	 * DMA'ed into the qoutfifo.
-	 */
-	ahd_run_qoutfifo(ahd);
-
-	/*
-	 * Flush the good status FIFO for compelted packetized commands.
+	 * Flush the good status FIFO for completed packetized commands.
 	 */
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	saved_scbptr = ahd_get_scbptr(ahd);
@@ -387,8 +387,7 @@
 		u_int fifo_mode;
 		u_int i;
 		
-		scbid = (ahd_inb(ahd, GSFIFO+1) << 8)
-		      | ahd_inb(ahd, GSFIFO);
+		scbid = ahd_inw(ahd, GSFIFO);
 		scb = ahd_lookup_scb(ahd, scbid);
 		if (scb == NULL) {
 			printf("%s: Warning - GSFIFO SCB %d invalid\n",
@@ -401,22 +400,33 @@
 		 * the host before completing the  command.
 		 */
 		fifo_mode = 0;
+rescan_fifos:
 		for (i = 0; i < 2; i++) {
 			/* Toggle to the other mode. */
 			fifo_mode ^= 1;
 			ahd_set_modes(ahd, fifo_mode, fifo_mode);
+
 			if (ahd_scb_active_in_fifo(ahd, scb) == 0)
 				continue;
 
 			ahd_run_data_fifo(ahd, scb);
 
 			/*
-			 * Clearing this transaction in this FIFO may
-			 * cause a CFG4DATA for this same transaction
-			 * to assert in the other FIFO.  Make sure we
-			 * loop one more time and check the other FIFO.
+			 * Running this FIFO may cause a CFG4DATA for
+			 * this same transaction to assert in the other
+			 * FIFO or a new snapshot SAVEPTRS interrupt
+			 * in this FIFO.  Even running a FIFO may not
+			 * clear the transaction if we are still waiting
+			 * for data to drain to the host. We must loop
+			 * until the transaction is not active in either
+			 * FIFO just to be sure.  Reset our loop counter
+			 * so we will visit both FIFOs again before
+			 * declaring this transaction finished.  We
+			 * also delay a bit so that status has a chance
+			 * to change before we look at this FIFO again.
 			 */
-			i = 0;
+			ahd_delay(200);
+			goto rescan_fifos;
 		}
 		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 		ahd_set_scbptr(ahd, scbid);
@@ -429,19 +439,28 @@
 			/*
 			 * The transfer completed with a residual.
 			 * Place this SCB on the complete DMA list
-			 * so that we Update our in-core copy of the
+			 * so that we update our in-core copy of the
 			 * SCB before completing the command.
 			 */
 			ahd_outb(ahd, SCB_SCSI_STATUS, 0);
 			ahd_outb(ahd, SCB_SGPTR,
 				 ahd_inb_scbram(ahd, SCB_SGPTR)
 				 | SG_STATUS_VALID);
-			ahd_outw(ahd, SCB_TAG, SCB_GET_TAG(scb));
+			ahd_outw(ahd, SCB_TAG, scbid);
+			ahd_outw(ahd, SCB_NEXT_COMPLETE, SCB_LIST_NULL);
 			comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
-			ahd_outw(ahd, SCB_NEXT_COMPLETE, comp_head);
-			if (SCBID_IS_NULL(comp_head))
-				ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD,
-					 SCB_GET_TAG(scb));
+			if (SCBID_IS_NULL(comp_head)) {
+				ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, scbid);
+				ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid);
+			} else {
+				u_int tail;
+
+				tail = ahd_inw(ahd, COMPLETE_DMA_SCB_TAIL);
+				ahd_set_scbptr(ahd, tail);
+				ahd_outw(ahd, SCB_NEXT_COMPLETE, scbid);
+				ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid);
+				ahd_set_scbptr(ahd, scbid);
+			}
 		} else
 			ahd_complete_scb(ahd, scb);
 	}
@@ -465,9 +484,22 @@
 			break;
 		ahd_delay(200);
 	}
-	if ((ccscbctl & CCSCBDIR) != 0)
+	/*
+	 * We leave the sequencer to cleanup in the case of DMA's to
+	 * update the qoutfifo.  In all other cases (DMA's to the
+	 * chip or a push of an SCB from the COMPLETE_DMA_SCB list),
+	 * we disable the DMA engine so that the sequencer will not
+	 * attempt to handle the DMA completion.
+	 */
+	if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0)
 		ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN));
 
+	/*
+	 * Complete any SCBs that just finished
+	 * being DMA'ed into the qoutfifo.
+	 */
+	ahd_run_qoutfifo(ahd);
+
 	saved_scbptr = ahd_get_scbptr(ahd);
 	/*
 	 * Manually update/complete any completed SCBs that are waiting to be
@@ -494,6 +526,24 @@
 		scbid = next_scbid;
 	}
 	ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+	ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL);
+
+	scbid = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
+	while (!SCBID_IS_NULL(scbid)) {
+
+		ahd_set_scbptr(ahd, scbid);
+		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: Warning - Complete Qfrz SCB %d invalid\n",
+			       ahd_name(ahd), scbid);
+			continue;
+		}
+
+		ahd_complete_scb(ahd, scb);
+		scbid = next_scbid;
+	}
+	ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL);
 
 	scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD);
 	while (!SCBID_IS_NULL(scbid)) {
@@ -558,150 +608,146 @@
 {
 	u_int seqintsrc;
 
-	while (1) {
-		seqintsrc = ahd_inb(ahd, SEQINTSRC);
-		if ((seqintsrc & CFG4DATA) != 0) {
-			uint32_t datacnt;
-			uint32_t sgptr;
+	seqintsrc = ahd_inb(ahd, SEQINTSRC);
+	if ((seqintsrc & CFG4DATA) != 0) {
+		uint32_t datacnt;
+		uint32_t sgptr;
 
-			/*
-			 * Clear full residual flag.
-			 */
-			sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID;
-			ahd_outb(ahd, SCB_SGPTR, sgptr);
+		/*
+		 * Clear full residual flag.
+		 */
+		sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID;
+		ahd_outb(ahd, SCB_SGPTR, sgptr);
 
-			/*
-			 * Load datacnt and address.
-			 */
-			datacnt = ahd_inl_scbram(ahd, SCB_DATACNT);
-			if ((datacnt & AHD_DMA_LAST_SEG) != 0) {
-				sgptr |= LAST_SEG;
-				ahd_outb(ahd, SG_STATE, 0);
-			} else
-				ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
-			ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR));
-			ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK);
-			ahd_outb(ahd, SG_CACHE_PRE, sgptr);
-			ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
-
-			/*
-			 * Initialize Residual Fields.
-			 */
-			ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24);
-			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK);
-
-			/*
-			 * Mark the SCB as having a FIFO in use.
-			 */
-			ahd_outb(ahd, SCB_FIFO_USE_COUNT,
-				 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1);
-
-			/*
-			 * Install a "fake" handler for this FIFO.
-			 */
-			ahd_outw(ahd, LONGJMP_ADDR, 0);
-
-			/*
-			 * Notify the hardware that we have satisfied
-			 * this sequencer interrupt.
-			 */
-			ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA);
-		} else if ((seqintsrc & SAVEPTRS) != 0) {
-			uint32_t sgptr;
-			uint32_t resid;
-
-			if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) {
-				/*
-				 * Snapshot Save Pointers.  Clear
-				 * the snapshot and continue.
-				 */
-				ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
-				continue;
-			}
-
-			/*
-			 * Disable S/G fetch so the DMA engine
-			 * is available to future users.
-			 */
-			if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
-				ahd_outb(ahd, CCSGCTL, 0);
+		/*
+		 * Load datacnt and address.
+		 */
+		datacnt = ahd_inl_scbram(ahd, SCB_DATACNT);
+		if ((datacnt & AHD_DMA_LAST_SEG) != 0) {
+			sgptr |= LAST_SEG;
 			ahd_outb(ahd, SG_STATE, 0);
+		} else
+			ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+		ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR));
+		ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK);
+		ahd_outb(ahd, SG_CACHE_PRE, sgptr);
+		ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
 
-			/*
-			 * Flush the data FIFO.  Strickly only
-			 * necessary for Rev A parts.
-			 */
-			ahd_outb(ahd, DFCNTRL,
-				 ahd_inb(ahd, DFCNTRL) | FIFOFLUSH);
+		/*
+		 * Initialize Residual Fields.
+		 */
+		ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24);
+		ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK);
 
-			/*
-			 * Calculate residual.
-			 */
-			sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
-			resid = ahd_inl(ahd, SHCNT);
-			resid |=
-			    ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24;
-			ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid);
-			if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) {
-				/*
-				 * Must back up to the correct S/G element.
-				 * Typically this just means resetting our
-				 * low byte to the offset in the SG_CACHE,
-				 * but if we wrapped, we have to correct
-				 * the other bytes of the sgptr too.
-				 */
-				if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0
-				 && (sgptr & 0x80) == 0)
-					sgptr -= 0x100;
-				sgptr &= ~0xFF;
-				sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW)
-				       & SG_ADDR_MASK;
-				ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
-				ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0);
-			} else if ((resid & AHD_SG_LEN_MASK) == 0) {
-				ahd_outb(ahd, SCB_RESIDUAL_SGPTR,
-					 sgptr | SG_LIST_NULL);
-			}
-			/*
-			 * Save Pointers.
-			 */
-			ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR));
-			ahd_outl(ahd, SCB_DATACNT, resid);
-			ahd_outl(ahd, SCB_SGPTR, sgptr);
-			ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS);
-			ahd_outb(ahd, SEQIMODE,
-				 ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS);
-			/*
-			 * If the data is to the SCSI bus, we are
-			 * done, otherwise wait for FIFOEMP.
-			 */
-			if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0)
-				break;
-		} else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) {
-			uint32_t sgptr;
-			uint64_t data_addr;
-			uint32_t data_len;
-			u_int	 dfcntrl;
+		/*
+		 * Mark the SCB as having a FIFO in use.
+		 */
+		ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+			 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1);
 
-			/*
-			 * Disable S/G fetch so the DMA engine
-			 * is available to future users.
-			 */
-			if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) {
-				ahd_outb(ahd, CCSGCTL, 0);
-				ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
-			}
+		/*
+		 * Install a "fake" handler for this FIFO.
+		 */
+		ahd_outw(ahd, LONGJMP_ADDR, 0);
 
+		/*
+		 * Notify the hardware that we have satisfied
+		 * this sequencer interrupt.
+		 */
+		ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA);
+	} else if ((seqintsrc & SAVEPTRS) != 0) {
+		uint32_t sgptr;
+		uint32_t resid;
+
+		if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) {
 			/*
-			 * Wait for the DMA engine to notice that the
-			 * host transfer is enabled and that there is
-			 * space in the S/G FIFO for new segments before
-			 * loading more segments.
+			 * Snapshot Save Pointers.  All that
+			 * is necessary to clear the snapshot
+			 * is a CLRCHN.
 			 */
-			if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) == 0)
-				continue;
-			if ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) == 0)
-				continue;
+			goto clrchn;
+		}
+
+		/*
+		 * Disable S/G fetch so the DMA engine
+		 * is available to future users.
+		 */
+		if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
+			ahd_outb(ahd, CCSGCTL, 0);
+		ahd_outb(ahd, SG_STATE, 0);
+
+		/*
+		 * Flush the data FIFO.  Strickly only
+		 * necessary for Rev A parts.
+		 */
+		ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH);
+
+		/*
+		 * Calculate residual.
+		 */
+		sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+		resid = ahd_inl(ahd, SHCNT);
+		resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24;
+		ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid);
+		if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) {
+			/*
+			 * Must back up to the correct S/G element.
+			 * Typically this just means resetting our
+			 * low byte to the offset in the SG_CACHE,
+			 * but if we wrapped, we have to correct
+			 * the other bytes of the sgptr too.
+			 */
+			if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0
+			 && (sgptr & 0x80) == 0)
+				sgptr -= 0x100;
+			sgptr &= ~0xFF;
+			sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW)
+			       & SG_ADDR_MASK;
+			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+			ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0);
+		} else if ((resid & AHD_SG_LEN_MASK) == 0) {
+			ahd_outb(ahd, SCB_RESIDUAL_SGPTR,
+				 sgptr | SG_LIST_NULL);
+		}
+		/*
+		 * Save Pointers.
+		 */
+		ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR));
+		ahd_outl(ahd, SCB_DATACNT, resid);
+		ahd_outl(ahd, SCB_SGPTR, sgptr);
+		ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS);
+		ahd_outb(ahd, SEQIMODE,
+			 ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS);
+		/*
+		 * If the data is to the SCSI bus, we are
+		 * done, otherwise wait for FIFOEMP.
+		 */
+		if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0)
+			goto clrchn;
+	} else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) {
+		uint32_t sgptr;
+		uint64_t data_addr;
+		uint32_t data_len;
+		u_int	 dfcntrl;
+
+		/*
+		 * Disable S/G fetch so the DMA engine
+		 * is available to future users.  We won't
+		 * be using the DMA engine to load segments.
+		 */
+		if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) {
+			ahd_outb(ahd, CCSGCTL, 0);
+			ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+		}
+
+		/*
+		 * Wait for the DMA engine to notice that the
+		 * host transfer is enabled and that there is
+		 * space in the S/G FIFO for new segments before
+		 * loading more segments.
+		 */
+		if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0
+		 && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) {
 
 			/*
 			 * Determine the offset of the next S/G
@@ -748,7 +794,7 @@
 			 * Advertise the segment to the hardware.
 			 */
 			dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN;
-			if ((ahd->features & AHD_NEW_DFCNTRL_OPTS)!=0) {
+			if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
 				/*
 				 * Use SCSIENWRDIS so that SCSIEN
 				 * is never modified by this
@@ -757,35 +803,44 @@
 				dfcntrl |= SCSIENWRDIS;
 			}
 			ahd_outb(ahd, DFCNTRL, dfcntrl);
-		} else if ((ahd_inb(ahd, SG_CACHE_SHADOW)
-			 & LAST_SEG_DONE) != 0) {
-
-			/*
-			 * Transfer completed to the end of SG list
-			 * and has flushed to the host.
-			 */
-			ahd_outb(ahd, SCB_SGPTR,
-				 ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL);
-			break;
-		} else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) {
-			break;
 		}
-		ahd_delay(200);
+	} else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) {
+
+		/*
+		 * Transfer completed to the end of SG list
+		 * and has flushed to the host.
+		 */
+		ahd_outb(ahd, SCB_SGPTR,
+			 ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL);
+		goto clrchn;
+	} else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) {
+clrchn:
+		/*
+		 * Clear any handler for this FIFO, decrement
+		 * the FIFO use count for the SCB, and release
+		 * the FIFO.
+		 */
+		ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
+		ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+			 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1);
+		ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
 	}
-	/*
-	 * Clear any handler for this FIFO, decrement
-	 * the FIFO use count for the SCB, and release
-	 * the FIFO.
-	 */
-	ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
-	ahd_outb(ahd, SCB_FIFO_USE_COUNT,
-		 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1);
-	ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
 }
 
+/*
+ * Look for entries in the QoutFIFO that have completed.
+ * The valid_tag completion field indicates the validity
+ * of the entry - the valid value toggles each time through
+ * the queue. We use the sg_status field in the completion
+ * entry to avoid referencing the hscb if the completion
+ * occurred with no errors and no residual.  sg_status is
+ * a copy of the first byte (little endian) of the sgptr
+ * hscb field.
+ */
 void
 ahd_run_qoutfifo(struct ahd_softc *ahd)
 {
+	struct ahd_completion *completion;
 	struct scb *scb;
 	u_int  scb_index;
 
@@ -793,11 +848,13 @@
 		panic("ahd_run_qoutfifo recursion");
 	ahd->flags |= AHD_RUNNING_QOUTFIFO;
 	ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD);
-	while ((ahd->qoutfifo[ahd->qoutfifonext]
-	     & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) {
+	for (;;) {
+		completion = &ahd->qoutfifo[ahd->qoutfifonext];
 
-		scb_index = ahd_le16toh(ahd->qoutfifo[ahd->qoutfifonext]
-				      & ~QOUTFIFO_ENTRY_VALID_LE);
+		if (completion->valid_tag != ahd->qoutfifonext_valid_tag)
+			break;
+
+		scb_index = ahd_le16toh(completion->tag);
 		scb = ahd_lookup_scb(ahd, scb_index);
 		if (scb == NULL) {
 			printf("%s: WARNING no command for scb %d "
@@ -805,12 +862,15 @@
 			       ahd_name(ahd), scb_index,
 			       ahd->qoutfifonext);
 			ahd_dump_card_state(ahd);
-		} else
-			ahd_complete_scb(ahd, scb);
+		} else if ((completion->sg_status & SG_STATUS_VALID) != 0) {
+			ahd_handle_scb_status(ahd, scb);
+		} else {
+			ahd_done(ahd, scb);
+		}
 
 		ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1);
 		if (ahd->qoutfifonext == 0)
-			ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID_LE;
+			ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID;
 	}
 	ahd->flags &= ~AHD_RUNNING_QOUTFIFO;
 }
@@ -876,26 +936,6 @@
 		       ahd_name(ahd), seqintcode);
 #endif
 	switch (seqintcode) {
-	case BAD_SCB_STATUS:
-	{
-		struct	scb *scb;
-		u_int	scbid;
-		int	cmds_pending;
-
-		scbid = ahd_get_scbptr(ahd);
-		scb = ahd_lookup_scb(ahd, scbid);
-		if (scb != NULL) {
-			ahd_complete_scb(ahd, scb);
-		} else {
-			printf("%s: WARNING no command for scb %d "
-			       "(bad status)\n", ahd_name(ahd), scbid);
-			ahd_dump_card_state(ahd);
-		}
-		cmds_pending = ahd_inw(ahd, CMDS_PENDING);
-		if (cmds_pending > 0)
-			ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1);
-		break;
-	}
 	case ENTERING_NONPACK:
 	{
 		struct	scb *scb;
@@ -1060,7 +1100,7 @@
 			ahd_outb(ahd, SAVED_LUN, 0);
 			ahd_outb(ahd, SEQ_FLAGS, 0);
 			ahd_assert_atn(ahd);
-			scb->flags &= ~(SCB_PACKETIZED);
+			scb->flags &= ~SCB_PACKETIZED;
 			scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT;
 			ahd_freeze_devq(ahd, scb);
 			ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
@@ -1503,9 +1543,6 @@
 	 && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
 		scb = NULL;
 
-	/* Make sure the sequencer is in a safe location. */
-	ahd_clear_critical_section(ahd);
-
 	if ((status0 & IOERR) != 0) {
 		u_int now_lvd;
 
@@ -1521,26 +1558,35 @@
 		ahd_setup_iocell_workaround(ahd);
 		ahd_unpause(ahd);
 	} else if ((status0 & OVERRUN) != 0) {
+
 		printf("%s: SCSI offset overrun detected.  Resetting bus.\n",
 		       ahd_name(ahd));
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 	} else if ((status & SCSIRSTI) != 0) {
+
 		printf("%s: Someone reset channel A\n", ahd_name(ahd));
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
 	} else if ((status & SCSIPERR) != 0) {
+
+		/* Make sure the sequencer is in a safe location. */
+		ahd_clear_critical_section(ahd);
+
 		ahd_handle_transmission_error(ahd);
 	} else if (lqostat0 != 0) {
+
 		printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
 		ahd_outb(ahd, CLRLQOINT0, lqostat0);
-		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
 			ahd_outb(ahd, CLRLQOINT1, 0);
-		}
 	} else if ((status & SELTO) != 0) {
 		u_int  scbid;
 
 		/* Stop the selection */
 		ahd_outb(ahd, SCSISEQ0, 0);
 
+		/* Make sure the sequencer is in a safe location. */
+		ahd_clear_critical_section(ahd);
+
 		/* No more pending messages */
 		ahd_clear_msg_state(ahd);
 
@@ -1573,24 +1619,27 @@
 				       scbid);
 			}
 #endif
-			/*
-			 * Force a renegotiation with this target just in
-			 * case the cable was pulled and will later be
-			 * re-attached.  The target may forget its negotiation
-			 * settings with us should it attempt to reselect
-			 * during the interruption.  The target will not issue
-			 * a unit attention in this case, so we must always
-			 * renegotiate.
-			 */
 			ahd_scb_devinfo(ahd, &devinfo, scb);
-			ahd_force_renegotiation(ahd, &devinfo);
 			ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);
 			ahd_freeze_devq(ahd, scb);
+
+			/*
+			 * Cancel any pending transactions on the device
+			 * now that it seems to be missing.  This will
+			 * also revert us to async/narrow transfers until
+			 * we can renegotiate with the device.
+			 */
+			ahd_handle_devreset(ahd, &devinfo,
+					    CAM_LUN_WILDCARD,
+					    CAM_SEL_TIMEOUT,
+					    "Selection Timeout",
+					    /*verbose_level*/1);
 		}
 		ahd_outb(ahd, CLRINT, CLRSCSIINT);
 		ahd_iocell_first_selection(ahd);
 		ahd_unpause(ahd);
 	} else if ((status0 & (SELDI|SELDO)) != 0) {
+
 		ahd_iocell_first_selection(ahd);
 		ahd_unpause(ahd);
 	} else if (status3 != 0) {
@@ -1598,6 +1647,10 @@
 		       ahd_name(ahd), status3);
 		ahd_outb(ahd, CLRSINT3, status3);
 	} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
+
+		/* Make sure the sequencer is in a safe location. */
+		ahd_clear_critical_section(ahd);
+
 		ahd_handle_lqiphase_error(ahd, lqistat1);
 	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
 		/*
@@ -1622,6 +1675,9 @@
 		 */
 		ahd_outb(ahd, SCSISEQ0, 0);
 
+		/* Make sure the sequencer is in a safe location. */
+		ahd_clear_critical_section(ahd);
+
 		/*
 		 * Determine what we were up to at the time of
 		 * the busfree.
@@ -1659,7 +1715,16 @@
 			clear_fifo = 0;
 			packetized =  (lqostat1 & LQOBUSFREE) != 0;
 			if (!packetized
-			 && ahd_inb(ahd, LASTPHASE) == P_BUSFREE)
+			 && ahd_inb(ahd, LASTPHASE) == P_BUSFREE
+			 && (ahd_inb(ahd, SSTAT0) & SELDI) == 0
+			 && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0
+			  || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0))
+				/*
+				 * Assume packetized if we are not
+				 * on the bus in a non-packetized
+				 * capacity and any pending selection
+				 * was a packetized selection.
+				 */
 				packetized = 1;
 			break;
 		}
@@ -2310,8 +2375,7 @@
 		       "PRGMCNT == 0x%x\n",
 		       ahd_lookup_phase_entry(lastphase)->phasemsg,
 		       aborted,
-		       ahd_inb(ahd, PRGMCNT)
-			| (ahd_inb(ahd, PRGMCNT+1) << 8));
+		       ahd_inw(ahd, PRGMCNT));
 		ahd_dump_card_state(ahd);
 	}
 	/* Always restart the sequencer. */
@@ -2474,8 +2538,7 @@
 		u_int	i;
 
 		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-		seqaddr = ahd_inb(ahd, CURADDR)
-			| (ahd_inb(ahd, CURADDR+1) << 8);
+		seqaddr = ahd_inw(ahd, CURADDR);
 
 		cs = ahd->critical_sections;
 		for (i = 0; i < ahd->num_critical_sections; i++, cs++) {
@@ -3196,14 +3259,25 @@
 		iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK;
 
 		if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0
-		 && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) {
+		 && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0
+		 && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) {
 			/*
 			 * Slow down our CRC interval to be
-			 * compatible with devices that can't
-			 * handle a CRC at full speed.
+			 * compatible with non-packetized
+			 * U160 devices that can't handle a
+			 * CRC at full speed.
 			 */
 			con_opts |= ENSLOWCRC;
 		}
+
+		if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) {
+			/*
+			 * On H2A4, revert to a slower slewrate
+			 * on non-paced transfers.
+			 */
+			iocell_opts[AHD_PRECOMP_SLEW_INDEX] &=
+			    ~AHD_SLEWRATE_MASK;
+		}
 	}
 
 	ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW);
@@ -3292,11 +3366,15 @@
 	 * Force the sequencer to reinitialize the selection for
 	 * the command at the head of the execution queue if it
 	 * has already been setup.  The negotiation changes may
-	 * effect whether we select-out with ATN.
+	 * effect whether we select-out with ATN.  It is only
+	 * safe to clear ENSELO when the bus is not free and no
+	 * selection is in progres or completed.
 	 */
 	saved_modes = ahd_save_modes(ahd);
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-	ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+	if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0
+	 && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
+		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
 	saved_scbptr = ahd_get_scbptr(ahd);
 	/* Ensure that the hscbs down on the card match the new information */
 	for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) {
@@ -4909,10 +4987,7 @@
 	 * Determine initial values for data_addr and data_cnt
 	 * for resuming the data phase.
 	 */
-	sgptr = (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24)
-	      | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16)
-	      | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8)
-	      |	ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR);
+	sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
 	sgptr &= SG_PTR_MASK;
 
 	resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16)
@@ -4930,10 +5005,7 @@
 		dataptr = ahd_le64toh(sg->addr)
 			+ (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK)
 			- resid;
-		ahd_outb(ahd, HADDR + 7, dataptr >> 56);
-		ahd_outb(ahd, HADDR + 6, dataptr >> 48);
-		ahd_outb(ahd, HADDR + 5, dataptr >> 40);
-		ahd_outb(ahd, HADDR + 4, dataptr >> 32);
+		ahd_outl(ahd, HADDR + 4, dataptr >> 32);
 	} else {
 		struct	 ahd_dma_seg *sg;
 
@@ -4948,10 +5020,7 @@
 		ahd_outb(ahd, HADDR + 4,
 			 (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24);
 	}
-	ahd_outb(ahd, HADDR + 3, dataptr >> 24);
-	ahd_outb(ahd, HADDR + 2, dataptr >> 16);
-	ahd_outb(ahd, HADDR + 1, dataptr >> 8);
-	ahd_outb(ahd, HADDR, dataptr);
+	ahd_outl(ahd, HADDR, dataptr);
 	ahd_outb(ahd, HCNT + 2, resid >> 16);
 	ahd_outb(ahd, HCNT + 1, resid >> 8);
 	ahd_outb(ahd, HCNT, resid);
@@ -5011,13 +5080,14 @@
 	ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
 		      AHD_TRANS_CUR, /*paused*/TRUE);
 	ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0,
-			 /*ppr_options*/0, AHD_TRANS_CUR, /*paused*/TRUE);
+			 /*ppr_options*/0, AHD_TRANS_CUR,
+			 /*paused*/TRUE);
 	
-	ahd_send_async(ahd, devinfo->channel, devinfo->target,
-		       lun, AC_SENT_BDR, NULL);
+	if (status != CAM_SEL_TIMEOUT)
+		ahd_send_async(ahd, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
 
-	if (message != NULL
-	 && (verbose_level <= bootverbose))
+	if (message != NULL && bootverbose)
 		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
 		       message, devinfo->channel, devinfo->target, found);
 }
@@ -5203,13 +5273,13 @@
 		/* FALLTHROUGH */
 	case 4:
 		ahd_dmamap_unload(ahd, ahd->shared_data_dmat,
-				  ahd->shared_data_dmamap);
+				  ahd->shared_data_map.dmamap);
 		/* FALLTHROUGH */
 	case 3:
 		ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo,
-				ahd->shared_data_dmamap);
+				ahd->shared_data_map.dmamap);
 		ahd_dmamap_destroy(ahd, ahd->shared_data_dmat,
-				   ahd->shared_data_dmamap);
+				   ahd->shared_data_map.dmamap);
 		/* FALLTHROUGH */
 	case 2:
 		ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat);
@@ -5975,16 +6045,13 @@
 	newcount = MIN(scb_data->sense_left, scb_data->scbs_left);
 	newcount = MIN(newcount, scb_data->sgs_left);
 	newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
-	scb_data->sense_left -= newcount;
-	scb_data->scbs_left -= newcount;
-	scb_data->sgs_left -= newcount;
 	for (i = 0; i < newcount; i++) {
-		u_int col_tag;
-
 		struct scb_platform_data *pdata;
+		u_int col_tag;
 #ifndef __linux__
 		int error;
 #endif
+
 		next_scb = (struct scb *)malloc(sizeof(*next_scb),
 						M_DEVBUF, M_NOWAIT);
 		if (next_scb == NULL)
@@ -6041,6 +6108,9 @@
 		sense_data += AHD_SENSE_BUFSIZE;
 		sense_busaddr += AHD_SENSE_BUFSIZE;
 		scb_data->numscbs++;
+		scb_data->sense_left--;
+		scb_data->scbs_left--;
+		scb_data->sgs_left--;
 	}
 }
 
@@ -6088,7 +6158,6 @@
 int
 ahd_init(struct ahd_softc *ahd)
 {
-	uint8_t		*base_vaddr;
 	uint8_t		*next_vaddr;
 	dma_addr_t	 next_baddr;
 	size_t		 driver_data_size;
@@ -6156,7 +6225,7 @@
 	 * for the target mode role, we must additionally provide space for
 	 * the incoming target command fifo.
 	 */
-	driver_data_size = AHD_SCB_MAX * sizeof(uint16_t)
+	driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo)
 			 + sizeof(struct hardware_scb);
 	if ((ahd->features & AHD_TARGETMODE) != 0)
 		driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd);
@@ -6178,20 +6247,23 @@
 
 	/* Allocation of driver data */
 	if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat,
-			     (void **)&base_vaddr,
-			     BUS_DMA_NOWAIT, &ahd->shared_data_dmamap) != 0) {
+			     (void **)&ahd->shared_data_map.vaddr,
+			     BUS_DMA_NOWAIT,
+			     &ahd->shared_data_map.dmamap) != 0) {
 		return (ENOMEM);
 	}
 
 	ahd->init_level++;
 
 	/* And permanently map it in */
-	ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-			base_vaddr, driver_data_size, ahd_dmamap_cb,
-			&ahd->shared_data_busaddr, /*flags*/0);
-	ahd->qoutfifo = (uint16_t *)base_vaddr;
+	ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+			ahd->shared_data_map.vaddr, driver_data_size,
+			ahd_dmamap_cb, &ahd->shared_data_map.physaddr,
+			/*flags*/0);
+	ahd->qoutfifo = (struct ahd_completion *)ahd->shared_data_map.vaddr;
 	next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE];
-	next_baddr = ahd->shared_data_busaddr + AHD_QOUT_SIZE*sizeof(uint16_t);
+	next_baddr = ahd->shared_data_map.physaddr
+		   + AHD_QOUT_SIZE*sizeof(struct ahd_completion);
 	if ((ahd->features & AHD_TARGETMODE) != 0) {
 		ahd->targetcmds = (struct target_cmd *)next_vaddr;
 		next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd);
@@ -6212,6 +6284,7 @@
 	 * specially from the DMA safe memory chunk used for the QOUTFIFO.
 	 */
 	ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr;
+	ahd->next_queued_hscb_map = &ahd->shared_data_map;
 	ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr);
 
 	ahd->init_level++;
@@ -6517,10 +6590,10 @@
 
 	/* All of our queues are empty */
 	ahd->qoutfifonext = 0;
-	ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID_LE;
-	ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID >> 8);
+	ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID;
+	ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID);
 	for (i = 0; i < AHD_QOUT_SIZE; i++)
-		ahd->qoutfifo[i] = 0;
+		ahd->qoutfifo[i].valid_tag = 0;
 	ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD);
 
 	ahd->qinfifonext = 0;
@@ -6553,24 +6626,22 @@
 	ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL);
 	ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL);
 	ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+	ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL);
+	ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL);
 
 	/*
 	 * The Freeze Count is 0.
 	 */
+	ahd->qfreeze_cnt = 0;
 	ahd_outw(ahd, QFREEZE_COUNT, 0);
+	ahd_outw(ahd, KERNEL_QFREEZE_COUNT, 0);
 
 	/*
 	 * Tell the sequencer where it can find our arrays in memory.
 	 */
-	busaddr = ahd->shared_data_busaddr;
-	ahd_outb(ahd, SHARED_DATA_ADDR, busaddr & 0xFF);
-	ahd_outb(ahd, SHARED_DATA_ADDR + 1, (busaddr >> 8) & 0xFF);
-	ahd_outb(ahd, SHARED_DATA_ADDR + 2, (busaddr >> 16) & 0xFF);
-	ahd_outb(ahd, SHARED_DATA_ADDR + 3, (busaddr >> 24) & 0xFF);
-	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR, busaddr & 0xFF);
-	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 1, (busaddr >> 8) & 0xFF);
-	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 2, (busaddr >> 16) & 0xFF);
-	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 3, (busaddr >> 24) & 0xFF);
+	busaddr = ahd->shared_data_map.physaddr;
+	ahd_outl(ahd, SHARED_DATA_ADDR, busaddr);
+	ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr);
 
 	/*
 	 * Setup the allowed SCSI Sequences based on operational mode.
@@ -6619,10 +6690,7 @@
 	 * Tell the sequencer which SCB will be the next one it receives.
 	 */
 	busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+	ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
 
 	/*
 	 * Default to coalescing disabled.
@@ -6926,43 +6994,34 @@
 {
 	u_int intstat;
 	u_int maxloops;
-	u_int qfreeze_cnt;
 
 	maxloops = 1000;
 	ahd->flags |= AHD_ALL_INTERRUPTS;
 	ahd_pause(ahd);
 	/*
-	 * Increment the QFreeze Count so that the sequencer
-	 * will not start new selections.  We do this only
+	 * Freeze the outgoing selections.  We do this only
 	 * until we are safely paused without further selections
 	 * pending.
 	 */
-	ahd_outw(ahd, QFREEZE_COUNT, ahd_inw(ahd, QFREEZE_COUNT) + 1);
+	ahd->qfreeze_cnt--;
+	ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
 	ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
 	do {
-		struct scb *waiting_scb;
 
 		ahd_unpause(ahd);
+		/*
+		 * Give the sequencer some time to service
+		 * any active selections.
+		 */
+		ahd_delay(500);
+
 		ahd_intr(ahd);
 		ahd_pause(ahd);
-		ahd_clear_critical_section(ahd);
 		intstat = ahd_inb(ahd, INTSTAT);
-		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-		if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
-			ahd_outb(ahd, SCSISEQ0,
-				 ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
-		/*
-		 * In the non-packetized case, the sequencer (for Rev A),
-		 * relies on ENSELO remaining set after SELDO.  The hardware
-		 * auto-clears ENSELO in the packetized case.
-		 */
-		waiting_scb = ahd_lookup_scb(ahd,
-					     ahd_inw(ahd, WAITING_TID_HEAD));
-		if (waiting_scb != NULL
-		 && (waiting_scb->flags & SCB_PACKETIZED) == 0
-		 && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
-			ahd_outb(ahd, SCSISEQ0,
-				 ahd_inb(ahd, SCSISEQ0) | ENSELO);
+		if ((intstat & INT_PEND) == 0) {
+			ahd_clear_critical_section(ahd);
+			intstat = ahd_inb(ahd, INTSTAT);
+		}
 	} while (--maxloops
 	      && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
 	      && ((intstat & INT_PEND) != 0
@@ -6973,17 +7032,8 @@
 		printf("Infinite interrupt loop, INTSTAT = %x",
 		      ahd_inb(ahd, INTSTAT));
 	}
-	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
-	if (qfreeze_cnt == 0) {
-		printf("%s: ahd_pause_and_flushwork with 0 qfreeze count!\n",
-		       ahd_name(ahd));
-	} else {
-		qfreeze_cnt--;
-	}
-	ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
-	if (qfreeze_cnt == 0)
-		ahd_outb(ahd, SEQ_FLAGS2,
-			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+	ahd->qfreeze_cnt++;
+	ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
 
 	ahd_flush_qoutfifo(ahd);
 
@@ -7155,10 +7205,7 @@
 		uint32_t busaddr;
 
 		busaddr = ahd_le32toh(scb->hscb->hscb_busaddr);
-		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+		ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
 	} else {
 		prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
 		ahd_sync_scb(ahd, prev_scb, 
@@ -7265,10 +7312,7 @@
 	 */
 	ahd->qinfifonext = qinstart;
 	busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+	ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
 
 	while (qinpos != qintail) {
 		scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]);
@@ -7330,6 +7374,7 @@
 	 * appropriate, traverse the SCBs of each "their id"
 	 * looking for matches.
 	 */
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	savedscbptr = ahd_get_scbptr(ahd);
 	tid_next = ahd_inw(ahd, WAITING_TID_HEAD);
 	tid_prev = SCB_LIST_NULL;
@@ -7399,7 +7444,7 @@
 	u_int	prev;
 	int	found;
 
-	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 	found = 0;
 	prev = SCB_LIST_NULL;
 	next = *list_head;
@@ -7466,7 +7511,7 @@
 ahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev,
 		    u_int tid_cur, u_int tid_next)
 {
-	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 
 	if (SCBID_IS_NULL(tid_cur)) {
 
@@ -7506,7 +7551,7 @@
 {
 	u_int tail_offset;
 
-	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 	if (!SCBID_IS_NULL(prev)) {
 		ahd_set_scbptr(ahd, prev);
 		ahd_outw(ahd, SCB_NEXT, next);
@@ -7739,7 +7784,7 @@
 	 */
 	ahd_clear_msg_state(ahd);
 	ahd_outb(ahd, SIMODE1,
-		 ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
+		 ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
 
 	if (initiate_reset)
 		ahd_reset_current_bus(ahd);
@@ -7910,30 +7955,35 @@
 void
 ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
 {
-	struct hardware_scb *hscb;
-	u_int  qfreeze_cnt;
+	struct	hardware_scb *hscb;
+	int	paused;
 
 	/*
 	 * The sequencer freezes its select-out queue
 	 * anytime a SCSI status error occurs.  We must
-	 * handle the error and decrement the QFREEZE count
-	 * to allow the sequencer to continue.
+	 * handle the error and increment our qfreeze count
+	 * to allow the sequencer to continue.  We don't
+	 * bother clearing critical sections here since all
+	 * operations are on data structures that the sequencer
+	 * is not touching once the queue is frozen.
 	 */
 	hscb = scb->hscb; 
 
+	if (ahd_is_paused(ahd)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahd_pause(ahd);
+	}
+
 	/* Freeze the queue until the client sees the error. */
 	ahd_freeze_devq(ahd, scb);
 	ahd_freeze_scb(scb);
-	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
-	if (qfreeze_cnt == 0) {
-		printf("%s: Bad status with 0 qfreeze count!\n", ahd_name(ahd));
-	} else {
-		qfreeze_cnt--;
-		ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
-	}
-	if (qfreeze_cnt == 0)
-		ahd_outb(ahd, SEQ_FLAGS2,
-			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+	ahd->qfreeze_cnt++;
+	ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
+
+	if (paused == 0)
+		ahd_unpause(ahd);
 
 	/* Don't want to clobber the original sense code */
 	if ((scb->flags & SCB_SENSE) != 0) {
@@ -8317,8 +8367,7 @@
 	max_prog = 2048;
 
 	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
-	ahd_outb(ahd, PRGMCNT, 0);
-	ahd_outb(ahd, PRGMCNT+1, 0);
+	ahd_outw(ahd, PRGMCNT, 0);
 	for (i = 0; i < max_prog; i++) {
 		uint8_t ins_bytes[4];
 
@@ -8347,13 +8396,14 @@
 	u_int	sg_prefetch_cnt_limit;
 	u_int	sg_prefetch_align;
 	u_int	sg_size;
+	u_int	cacheline_mask;
 	uint8_t	download_consts[DOWNLOAD_CONST_COUNT];
 
 	if (bootverbose)
 		printf("%s: Downloading Sequencer Program...",
 		       ahd_name(ahd));
 
-#if DOWNLOAD_CONST_COUNT != 7
+#if DOWNLOAD_CONST_COUNT != 8
 #error "Download Const Mismatch"
 #endif
 	/*
@@ -8389,6 +8439,9 @@
 	/* Round down to the nearest power of 2. */
 	while (powerof2(sg_prefetch_align) == 0)
 		sg_prefetch_align--;
+
+	cacheline_mask = sg_prefetch_align - 1;
+
 	/*
 	 * If the cacheline boundary is greater than half our prefetch RAM
 	 * we risk not being able to fetch even a single complete S/G
@@ -8429,12 +8482,12 @@
 	download_consts[PKT_OVERRUN_BUFOFFSET] =
 		(ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256;
 	download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN;
+	download_consts[CACHELINE_MASK] = cacheline_mask;
 	cur_patch = patches;
 	downloaded = 0;
 	skip_addr = 0;
 	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
-	ahd_outb(ahd, PRGMCNT, 0);
-	ahd_outb(ahd, PRGMCNT+1, 0);
+	ahd_outw(ahd, PRGMCNT, 0);
 
 	for (i = 0; i < sizeof(seqprog)/4; i++) {
 		if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) {
@@ -8727,7 +8780,7 @@
 	printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
 	       "%s: Dumping Card State at program address 0x%x Mode 0x%x\n",
 	       ahd_name(ahd), 
-	       ahd_inb(ahd, CURADDR) | (ahd_inb(ahd, CURADDR+1) << 8),
+	       ahd_inw(ahd, CURADDR),
 	       ahd_build_mode_state(ahd, ahd->saved_src_mode,
 				    ahd->saved_dst_mode));
 	if (paused)
@@ -8843,6 +8896,15 @@
 		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
 	}
 	printf("\n");
+	printf("Sequencer On QFreeze and Complete list: ");
+	scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
+	i = 0;
+	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
+		ahd_set_scbptr(ahd, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+	}
+	printf("\n");
 	ahd_set_scbptr(ahd, saved_scb_index);
 	dffstat = ahd_inb(ahd, DFFSTAT);
 	for (i = 0; i < 2; i++) {
@@ -9077,7 +9139,7 @@
 {
 	int cnt;
 
-	cnt = 20;
+	cnt = 5000;
 	while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt)
 		ahd_delay(5);
 
@@ -9423,13 +9485,9 @@
 			if ((ahd->features & AHD_MULTI_TID) != 0) {
 				u_int targid_mask;
 
-				targid_mask = ahd_inb(ahd, TARGID)
-					    | (ahd_inb(ahd, TARGID + 1) << 8);
-
+				targid_mask = ahd_inw(ahd, TARGID);
 				targid_mask |= target_mask;
-				ahd_outb(ahd, TARGID, targid_mask);
-				ahd_outb(ahd, TARGID+1, (targid_mask >> 8));
-				
+				ahd_outw(ahd, TARGID, targid_mask);
 				ahd_update_scsiid(ahd, targid_mask);
 			} else {
 				u_int our_id;
@@ -9543,14 +9601,9 @@
 				if (ahd->features & AHD_MULTI_TID) {
 					u_int targid_mask;
 
-					targid_mask = ahd_inb(ahd, TARGID)
-						    | (ahd_inb(ahd, TARGID + 1)
-						       << 8);
-
+					targid_mask = ahd_inw(ahd, TARGID);
 					targid_mask &= ~target_mask;
-					ahd_outb(ahd, TARGID, targid_mask);
-					ahd_outb(ahd, TARGID+1,
-					 	 (targid_mask >> 8));
+					ahd_outw(ahd, TARGID, targid_mask);
 					ahd_update_scsiid(ahd, targid_mask);
 				}
 			}
@@ -9651,7 +9704,7 @@
 
 		cmd->cmd_valid = 0;
 		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-				ahd->shared_data_dmamap,
+				ahd->shared_data_map.dmamap,
 				ahd_targetcmd_offset(ahd, ahd->tqinfifonext),
 				sizeof(struct target_cmd),
 				BUS_DMASYNC_PREREAD);
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index d80bc51..91c4f7f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#51 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#58 $
  *
  * $FreeBSD$
  */
@@ -522,12 +522,21 @@
 static __inline uint16_t
 ahd_inw(struct ahd_softc *ahd, u_int port)
 {
+	/*
+	 * Read high byte first as some registers increment
+	 * or have other side effects when the low byte is
+	 * read.
+	 */
 	return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
 }
 
 static __inline void
 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
 {
+	/*
+	 * Write low byte first to accomodate registers
+	 * such as PRGMCNT where the order maters.
+	 */
 	ahd_outb(ahd, port, value & 0xFF);
 	ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
 }
@@ -684,7 +693,7 @@
 	 * Razor #528
 	 */
 	value = ahd_inb(ahd, offset);
-	if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+	if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
 		ahd_inb(ahd, MODE_PTR);
 	return (value);
 }
@@ -727,7 +736,8 @@
 static __inline void
 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
 {
-	struct hardware_scb *q_hscb;
+	struct	 hardware_scb *q_hscb;
+	struct	 map_node *q_hscb_map;
 	uint32_t saved_hscb_busaddr;
 
 	/*
@@ -743,6 +753,7 @@
 	 * locate the correct SCB by SCB_TAG.
 	 */
 	q_hscb = ahd->next_queued_hscb;
+	q_hscb_map = ahd->next_queued_hscb_map;
 	saved_hscb_busaddr = q_hscb->hscb_busaddr;
 	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
 	q_hscb->hscb_busaddr = saved_hscb_busaddr;
@@ -750,7 +761,9 @@
 
 	/* Now swap HSCB pointers. */
 	ahd->next_queued_hscb = scb->hscb;
+	ahd->next_queued_hscb_map = scb->hscb_map;
 	scb->hscb = q_hscb;
+	scb->hscb_map = q_hscb_map;
 
 	/* Now define the mapping from tag to SCB in the scbindex */
 	ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
@@ -824,8 +837,9 @@
 static __inline void
 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
 {
-	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-			/*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
+	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+			/*offset*/0,
+			/*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
 }
 
 static __inline void
@@ -834,7 +848,7 @@
 #ifdef AHD_TARGET_MODE
 	if ((ahd->flags & AHD_TARGETROLE) != 0) {
 		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-				ahd->shared_data_dmamap,
+				ahd->shared_data_map.dmamap,
 				ahd_targetcmd_offset(ahd, 0),
 				sizeof(struct target_cmd) * AHD_TMODE_CMDS,
 				op);
@@ -854,17 +868,17 @@
 	u_int retval;
 
 	retval = 0;
-	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-			/*offset*/ahd->qoutfifonext, /*len*/2,
-			BUS_DMASYNC_POSTREAD);
-	if ((ahd->qoutfifo[ahd->qoutfifonext]
-	     & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag)
+	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+			/*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
+			/*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
+	if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
+	  == ahd->qoutfifonext_valid_tag)
 		retval |= AHD_RUN_QOUTFIFO;
 #ifdef AHD_TARGET_MODE
 	if ((ahd->flags & AHD_TARGETROLE) != 0
 	 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
 		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-				ahd->shared_data_dmamap,
+				ahd->shared_data_map.dmamap,
 				ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
 				/*len*/sizeof(struct target_cmd),
 				BUS_DMASYNC_POSTREAD);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 1c8f872..2567e29 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1468,6 +1468,30 @@
 	if ((tstate->auto_negotiate & mask) != 0) {
 		scb->flags |= SCB_AUTO_NEGOTIATE;
 		scb->hscb->control |= MK_MESSAGE;
+		} else if (cmd->cmnd[0] == INQUIRY
+			&& (tinfo->curr.offset != 0
+			 || tinfo->curr.width != MSG_EXT_WDTR_BUS_8_BIT
+			 || tinfo->curr.ppr_options != 0)
+			&& (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)==0) {
+			/*
+			 * The SCSI spec requires inquiry
+			 * commands to complete without
+			 * reporting unit attention conditions.
+			 * Because of this, an inquiry command
+			 * that occurs just after a device is
+			 * reset will result in a data phase
+			 * with mismatched negotiated rates.
+			 * The core already forces a renegotiation
+			 * for reset events that are visible to
+			 * our controller or that we initiate,
+			 * but a third party device reset or a
+			 * hot-plug insertion can still cause this
+			 * issue.  Therefore, we force a re-negotiation
+			 * for every inquiry command unless we
+			 * are async.
+			 */
+			scb->flags |= SCB_NEGOTIATE;
+			scb->hscb->control |= MK_MESSAGE;
 	}
 
 	if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
@@ -2058,6 +2082,7 @@
 	int    paused;
 	int    wait;
 	int    disconnected;
+	int    found;
 	ahd_mode_state saved_modes;
 	unsigned long flags;
 
@@ -2176,7 +2201,8 @@
 	last_phase = ahd_inb(ahd, LASTPHASE);
 	saved_scbptr = ahd_get_scbptr(ahd);
 	active_scbptr = saved_scbptr;
-	if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
+	if (disconnected && ((last_phase != P_BUSFREE) || 
+			     (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0)) {
 		struct scb *bus_scb;
 
 		bus_scb = ahd_lookup_scb(ahd, active_scbptr);
@@ -2194,28 +2220,41 @@
 	 * bus or is in the disconnected state.
 	 */
 	saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
-	if (last_phase != P_BUSFREE
-	 && (SCB_GET_TAG(pending_scb) == active_scbptr
+	if (SCB_GET_TAG(pending_scb) == active_scbptr
 	     || (flag == SCB_DEVICE_RESET
-		 && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd)))) {
+		 && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd))) {
 
 		/*
 		 * We're active on the bus, so assert ATN
 		 * and hope that the target responds.
 		 */
 		pending_scb = ahd_lookup_scb(ahd, active_scbptr);
-		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET;
 		ahd_outb(ahd, MSG_OUT, HOST_MSG);
 		ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
-		scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n");
+		scmd_printk(KERN_INFO, cmd, "BDR message in message buffer\n");
 		wait = TRUE;
+	} else if (last_phase != P_BUSFREE
+		   && ahd_inb(ahd, SCSIPHASE) == 0) {
+		/*
+		 * SCB is not identified, there
+		 * is no pending REQ, and the sequencer
+		 * has not seen a busfree.  Looks like
+		 * a stuck connection waiting to
+		 * go busfree.  Reset the bus.
+		 */
+		found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
+					  /*Initiate Reset*/TRUE);
+		printf("%s: Issued Channel %c Bus Reset. "
+		       "%d SCBs aborted\n", ahd_name(ahd),
+		       cmd->device->channel + 'A', found);
 	} else if (disconnected) {
 
 		/*
 		 * Actually re-queue this SCB in an attempt
 		 * to select the device before it reconnects.
 		 */
-		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
+		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
 		ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
 		pending_scb->hscb->cdb_len = 0;
 		pending_scb->hscb->task_attribute = 0;
@@ -2296,16 +2335,17 @@
 		timer.expires = jiffies + (5 * HZ);
 		timer.function = ahd_linux_sem_timeout;
 		add_timer(&timer);
-		printf("Recovery code sleeping\n");
+		printf("%s: Recovery code sleeping\n", ahd_name(ahd));
 		down(&ahd->platform_data->eh_sem);
-		printf("Recovery code awake\n");
+		printf("%s: Recovery code awake\n", ahd_name(ahd));
         	ret = del_timer_sync(&timer);
 		if (ret == 0) {
-			printf("Timer Expired\n");
+			printf("%s: Timer Expired (active %d)\n",
+			       ahd_name(ahd), dev->active);
 			retval = FAILED;
 		}
 	}
-		ahd_unlock(ahd, &flags);
+	ahd_unlock(ahd, &flags);
 	return (retval);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index bc44222..cb74fcc 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -252,7 +252,7 @@
 /***************************** SMP support ************************************/
 #include <linux/spinlock.h>
 
-#define AIC79XX_DRIVER_VERSION "1.3.11"
+#define AIC79XX_DRIVER_VERSION "3.0"
 
 /*************************** Device Data Structures ***************************/
 /*
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 2131db6..196a634 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -38,9 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#77 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#89 $
  */
 
 #ifdef __linux__
@@ -114,6 +112,13 @@
 		"Adaptec 29320ALP Ultra320 SCSI adapter",
 		ahd_aic7901_setup
 	},
+	/* aic7901A based controllers */
+	{
+		ID_AHA_29320LP,
+		ID_ALL_MASK,
+		"Adaptec 29320LP Ultra320 SCSI adapter",
+		ahd_aic7901A_setup
+	},
 	/* aic7902 based controllers */	
 	{
 		ID_AHA_29320,
@@ -128,12 +133,6 @@
 		ahd_aic7902_setup
 	},
 	{
-		ID_AHA_29320LP,
-		ID_ALL_MASK,
-		"Adaptec 29320LP Ultra320 SCSI adapter",
-		ahd_aic7901A_setup
-	},
-	{
 		ID_AHA_39320,
 		ID_ALL_MASK,
 		"Adaptec 39320 Ultra320 SCSI adapter",
@@ -146,6 +145,12 @@
 		ahd_aic7902_setup
 	},
 	{
+		ID_AHA_39320_B_DELL,
+		ID_ALL_MASK,
+		"Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
 		ID_AHA_39320A,
 		ID_ALL_MASK,
 		"Adaptec 39320A Ultra320 SCSI adapter",
@@ -668,6 +673,7 @@
 	 * Now set the termination based on what we found.
 	 */
 	sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN;
+	ahd->flags &= ~AHD_TERM_ENB_A;
 	if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) {
 		ahd->flags |= AHD_TERM_ENB_A;
 		sxfrctl1 |= STPWEN;
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
index b5cfeab..da45153 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.h
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -53,14 +53,15 @@
 #define ID_AHA_29320ALP			0x8017900500449005ull
 
 #define ID_AIC7901A			0x801E9005FFFF9005ull
-#define ID_AHA_29320			0x8012900500429005ull
-#define ID_AHA_29320B			0x8013900500439005ull
 #define ID_AHA_29320LP			0x8014900500449005ull
 
 #define ID_AIC7902			0x801F9005FFFF9005ull
 #define ID_AIC7902_B			0x801D9005FFFF9005ull
 #define ID_AHA_39320			0x8010900500409005ull
+#define ID_AHA_29320			0x8012900500429005ull
+#define ID_AHA_29320B			0x8013900500439005ull
 #define ID_AHA_39320_B			0x8015900500409005ull
+#define ID_AHA_39320_B_DELL		0x8015900501681028ull
 #define ID_AHA_39320A			0x8016900500409005ull
 #define ID_AHA_39320D			0x8011900500419005ull
 #define ID_AHA_39320D_B			0x801C900500419005ull
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
index c01ac39..8763b15 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -83,13 +83,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrseqintstat_print;
-#else
-#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_seqintstat_print;
 #else
 #define ahd_seqintstat_print(regvalue, cur_col, wrap) \
@@ -97,6 +90,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrseqintstat_print;
+#else
+#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_swtimer_print;
 #else
 #define ahd_swtimer_print(regvalue, cur_col, wrap) \
@@ -412,13 +412,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_businitid_print;
-#else
-#define ahd_businitid_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dlcount_print;
 #else
 #define ahd_dlcount_print(regvalue, cur_col, wrap) \
@@ -426,6 +419,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_businitid_print;
+#else
+#define ahd_businitid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_sxfrctl1_print;
 #else
 #define ahd_sxfrctl1_print(regvalue, cur_col, wrap) \
@@ -517,13 +517,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sblkctl_print;
-#else
-#define ahd_sblkctl_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_optionmode_print;
 #else
 #define ahd_optionmode_print(regvalue, cur_col, wrap) \
@@ -531,10 +524,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sstat0_print;
+ahd_reg_print_t ahd_sblkctl_print;
 #else
-#define ahd_sstat0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap)
+#define ahd_sblkctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -545,6 +538,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat0_print;
+#else
+#define ahd_sstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_simode0_print;
 #else
 #define ahd_simode0_print(regvalue, cur_col, wrap) \
@@ -573,13 +573,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrsint2_print;
-#else
-#define ahd_clrsint2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_simode2_print;
 #else
 #define ahd_simode2_print(regvalue, cur_col, wrap) \
@@ -587,6 +580,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrsint2_print;
+#else
+#define ahd_clrsint2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_perrdiag_print;
 #else
 #define ahd_perrdiag_print(regvalue, cur_col, wrap) \
@@ -685,13 +685,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqomode0_print;
-#else
-#define ahd_lqomode0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat0_print;
 #else
 #define ahd_lqostat0_print(regvalue, cur_col, wrap) \
@@ -706,6 +699,20 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode0_print;
+#else
+#define ahd_lqomode0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode1_print;
+#else
+#define ahd_lqomode1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat1_print;
 #else
 #define ahd_lqostat1_print(regvalue, cur_col, wrap) \
@@ -720,13 +727,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqomode1_print;
-#else
-#define ahd_lqomode1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat2_print;
 #else
 #define ahd_lqostat2_print(regvalue, cur_col, wrap) \
@@ -909,13 +909,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scschkn_print;
-#else
-#define ahd_scschkn_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_annexdat_print;
 #else
 #define ahd_annexdat_print(regvalue, cur_col, wrap) \
@@ -923,6 +916,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scschkn_print;
+#else
+#define ahd_scschkn_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_iownid_print;
 #else
 #define ahd_iownid_print(regvalue, cur_col, wrap) \
@@ -1000,13 +1000,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll400cnt0_print;
-#else
-#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_unfairness_print;
 #else
 #define ahd_unfairness_print(regvalue, cur_col, wrap) \
@@ -1014,6 +1007,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll400cnt0_print;
+#else
+#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_haddr_print;
 #else
 #define ahd_haddr_print(regvalue, cur_col, wrap) \
@@ -1056,13 +1056,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghaddr_print;
-#else
-#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_scbhaddr_print;
 #else
 #define ahd_scbhaddr_print(regvalue, cur_col, wrap) \
@@ -1070,10 +1063,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghcnt_print;
+ahd_reg_print_t ahd_sghaddr_print;
 #else
-#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
+#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1084,6 +1077,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sghcnt_print;
+#else
+#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dff_thrsh_print;
 #else
 #define ahd_dff_thrsh_print(regvalue, cur_col, wrap) \
@@ -1154,13 +1154,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg1_print;
-#else
-#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcrxmsg1_print;
 #else
 #define ahd_cmcrxmsg1_print(regvalue, cur_col, wrap) \
@@ -1168,6 +1161,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchrxmsg1_print;
+#else
+#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchrxmsg2_print;
 #else
 #define ahd_dchrxmsg2_print(regvalue, cur_col, wrap) \
@@ -1175,13 +1175,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg2_print;
-#else
-#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcrxmsg2_print;
 #else
 #define ahd_cmcrxmsg2_print(regvalue, cur_col, wrap) \
@@ -1196,6 +1189,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg2_print;
+#else
+#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchrxmsg3_print;
 #else
 #define ahd_dchrxmsg3_print(regvalue, cur_col, wrap) \
@@ -1203,6 +1203,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg3_print;
+#else
+#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcrxmsg3_print;
 #else
 #define ahd_cmcrxmsg3_print(regvalue, cur_col, wrap) \
@@ -1217,13 +1224,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg3_print;
-#else
-#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_ovlyseqbcnt_print;
 #else
 #define ahd_ovlyseqbcnt_print(regvalue, cur_col, wrap) \
@@ -1231,13 +1231,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcseqbcnt_print;
-#else
-#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchseqbcnt_print;
 #else
 #define ahd_dchseqbcnt_print(regvalue, cur_col, wrap) \
@@ -1245,6 +1238,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcseqbcnt_print;
+#else
+#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcspltstat0_print;
 #else
 #define ahd_cmcspltstat0_print(regvalue, cur_col, wrap) \
@@ -1252,13 +1252,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyspltstat0_print;
-#else
-#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchspltstat0_print;
 #else
 #define ahd_dchspltstat0_print(regvalue, cur_col, wrap) \
@@ -1266,10 +1259,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchspltstat1_print;
+ahd_reg_print_t ahd_ovlyspltstat0_print;
 #else
-#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1287,6 +1280,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchspltstat1_print;
+#else
+#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_sgrxmsg0_print;
 #else
 #define ahd_sgrxmsg0_print(regvalue, cur_col, wrap) \
@@ -1378,13 +1378,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sfunct_print;
-#else
-#define ahd_sfunct_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_sgspltstat1_print;
 #else
 #define ahd_sgspltstat1_print(regvalue, cur_col, wrap) \
@@ -1392,6 +1385,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sfunct_print;
+#else
+#define ahd_sfunct_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_df0pcistat_print;
 #else
 #define ahd_df0pcistat_print(regvalue, cur_col, wrap) \
@@ -1504,13 +1504,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbaddr_print;
-#else
-#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_ccscbadr_bk_print;
 #else
 #define ahd_ccscbadr_bk_print(regvalue, cur_col, wrap) \
@@ -1518,6 +1511,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbaddr_print;
+#else
+#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmc_rambist_print;
 #else
 #define ahd_cmc_rambist_print(regvalue, cur_col, wrap) \
@@ -1525,13 +1525,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccsgctl_print;
-#else
-#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_ccscbctl_print;
 #else
 #define ahd_ccscbctl_print(regvalue, cur_col, wrap) \
@@ -1539,6 +1532,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccsgctl_print;
+#else
+#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_ccsgram_print;
 #else
 #define ahd_ccsgram_print(regvalue, cur_col, wrap) \
@@ -1707,13 +1707,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfptrs_print;
-#else
-#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_rcvrbiascalc_print;
 #else
 #define ahd_rcvrbiascalc_print(regvalue, cur_col, wrap) \
@@ -1721,10 +1714,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfbkptr_print;
+ahd_reg_print_t ahd_dfptrs_print;
 #else
-#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
+#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1735,6 +1728,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfbkptr_print;
+#else
+#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dfdbctl_print;
 #else
 #define ahd_dfdbctl_print(regvalue, cur_col, wrap) \
@@ -1826,13 +1826,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_brkaddr1_print;
-#else
-#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_brkaddr0_print;
 #else
 #define ahd_brkaddr0_print(regvalue, cur_col, wrap) \
@@ -1840,6 +1833,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_brkaddr1_print;
+#else
+#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_allones_print;
 #else
 #define ahd_allones_print(regvalue, cur_col, wrap) \
@@ -1889,13 +1889,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_curaddr_print;
-#else
-#define ahd_curaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_intvec1_addr_print;
 #else
 #define ahd_intvec1_addr_print(regvalue, cur_col, wrap) \
@@ -1903,10 +1896,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_intvec2_addr_print;
+ahd_reg_print_t ahd_curaddr_print;
 #else
-#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap)
+#define ahd_curaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1917,6 +1910,13 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intvec2_addr_print;
+#else
+#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_longjmp_addr_print;
 #else
 #define ahd_longjmp_addr_print(regvalue, cur_col, wrap) \
@@ -1994,192 +1994,213 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_dma_scb_tail_print;
+#else
+#define ahd_complete_dma_scb_tail_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_TAIL", 0x12e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_on_qfreeze_head_print;
+#else
+#define ahd_complete_on_qfreeze_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_ON_QFREEZE_HEAD", 0x130, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_qfreeze_count_print;
 #else
 #define ahd_qfreeze_count_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x12e, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x132, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_kernel_qfreeze_count_print;
+#else
+#define ahd_kernel_qfreeze_count_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT", 0x134, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_mode_print;
 #else
 #define ahd_saved_mode_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_MODE", 0x130, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_MODE", 0x136, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_msg_out_print;
 #else
 #define ahd_msg_out_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "MSG_OUT", 0x131, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "MSG_OUT", 0x137, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dmaparams_print;
 #else
 #define ahd_dmaparams_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DMAPARAMS", 0x132, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "DMAPARAMS", 0x138, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_seq_flags_print;
 #else
 #define ahd_seq_flags_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x133, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x139, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_scsiid_print;
 #else
 #define ahd_saved_scsiid_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_SCSIID", 0x134, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_SCSIID", 0x13a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_lun_print;
 #else
 #define ahd_saved_lun_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_LUN", 0x135, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_LUN", 0x13b, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lastphase_print;
 #else
 #define ahd_lastphase_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LASTPHASE", 0x136, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LASTPHASE", 0x13c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_qoutfifo_entry_valid_tag_print;
 #else
 #define ahd_qoutfifo_entry_valid_tag_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x137, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_shared_data_addr_print;
-#else
-#define ahd_shared_data_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x138, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_qoutfifo_next_addr_print;
-#else
-#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x13c, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x13d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_kernel_tqinpos_print;
 #else
 #define ahd_kernel_tqinpos_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x140, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x13e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_tqinpos_print;
 #else
 #define ahd_tqinpos_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "TQINPOS", 0x141, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "TQINPOS", 0x13f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_shared_data_addr_print;
+#else
+#define ahd_shared_data_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x140, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qoutfifo_next_addr_print;
+#else
+#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x144, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_arg_1_print;
 #else
 #define ahd_arg_1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ARG_1", 0x142, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ARG_1", 0x148, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_arg_2_print;
 #else
 #define ahd_arg_2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ARG_2", 0x143, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ARG_2", 0x149, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_last_msg_print;
 #else
 #define ahd_last_msg_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LAST_MSG", 0x144, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LAST_MSG", 0x14a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_scsiseq_template_print;
 #else
 #define ahd_scsiseq_template_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x145, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x14b, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_initiator_tag_print;
 #else
 #define ahd_initiator_tag_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x146, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x14c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_seq_flags2_print;
 #else
 #define ahd_seq_flags2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x147, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x14d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_allocfifo_scbptr_print;
 #else
 #define ahd_allocfifo_scbptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x148, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x14e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_timer_print;
 #else
 #define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x150, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_maxcmds_print;
 #else
 #define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x152, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_mincmds_print;
 #else
 #define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x153, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmds_pending_print;
 #else
 #define ahd_cmds_pending_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMDS_PENDING", 0x14e, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "CMDS_PENDING", 0x154, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_cmdcount_print;
 #else
 #define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x156, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_local_hs_mailbox_print;
 #else
 #define ahd_local_hs_mailbox_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x151, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x157, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmdsize_table_print;
 #else
 #define ahd_cmdsize_table_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x152, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x158, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2434,13 +2455,6 @@
 #define		HOST_TQINPOS    	0x80
 #define		ENINT_COALESCE  	0x40
 
-#define	CLRSEQINTSTAT   		0x0c
-#define		CLRSEQ_SWTMRTO  	0x10
-#define		CLRSEQ_SEQINT   	0x08
-#define		CLRSEQ_SCSIINT  	0x04
-#define		CLRSEQ_PCIINT   	0x02
-#define		CLRSEQ_SPLTINT  	0x01
-
 #define	SEQINTSTAT      		0x0c
 #define		SEQ_SWTMRTO     	0x10
 #define		SEQ_SEQINT      	0x08
@@ -2448,6 +2462,13 @@
 #define		SEQ_PCIINT      	0x02
 #define		SEQ_SPLTINT     	0x01
 
+#define	CLRSEQINTSTAT   		0x0c
+#define		CLRSEQ_SWTMRTO  	0x10
+#define		CLRSEQ_SEQINT   	0x08
+#define		CLRSEQ_SCSIINT  	0x04
+#define		CLRSEQ_PCIINT   	0x02
+#define		CLRSEQ_SPLTINT  	0x01
+
 #define	SWTIMER         		0x0e
 
 #define	SNSCB_QOFF      		0x10
@@ -2623,10 +2644,10 @@
 #define		BIOSCANCELEN    	0x10
 #define		SPIOEN          	0x08
 
-#define	BUSINITID       		0x3c
-
 #define	DLCOUNT         		0x3c
 
+#define	BUSINITID       		0x3c
+
 #define	SXFRCTL1        		0x3d
 #define		BITBUCKET       	0x80
 #define		ENSACHK         	0x40
@@ -2693,13 +2714,6 @@
 #define		SELID_MASK      	0xf0
 #define		ONEBIT          	0x08
 
-#define	SBLKCTL         		0x4a
-#define		DIAGLEDEN       	0x80
-#define		DIAGLEDON       	0x40
-#define		ENAB40          	0x08
-#define		ENAB20          	0x04
-#define		SELWIDE         	0x02
-
 #define	OPTIONMODE      		0x4a
 #define		OPTIONMODE_DEFAULTS	0x02
 #define		BIOSCANCTL      	0x80
@@ -2709,6 +2723,22 @@
 #define		ENDGFORMCHK     	0x04
 #define		AUTO_MSGOUT_DE  	0x02
 
+#define	SBLKCTL         		0x4a
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		ENAB40          	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+
+#define	CLRSINT0        		0x4b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRIOERR        	0x08
+#define		CLROVERRUN      	0x04
+#define		CLRSPIORDY      	0x02
+#define		CLRARBDO        	0x01
+
 #define	SSTAT0          		0x4b
 #define		TARGET          	0x80
 #define		SELDO           	0x40
@@ -2719,15 +2749,6 @@
 #define		SPIORDY         	0x02
 #define		ARBDO           	0x01
 
-#define	CLRSINT0        		0x4b
-#define		CLRSELDO        	0x40
-#define		CLRSELDI        	0x20
-#define		CLRSELINGO      	0x10
-#define		CLRIOERR        	0x08
-#define		CLROVERRUN      	0x04
-#define		CLRSPIORDY      	0x02
-#define		CLRARBDO        	0x01
-
 #define	SIMODE0         		0x4b
 #define		ENSELDO         	0x40
 #define		ENSELDI         	0x20
@@ -2768,17 +2789,17 @@
 #define		BUSFREE_DFF0    	0x80
 #define		BUSFREE_LQO     	0x40
 
+#define	SIMODE2         		0x4d
+#define		ENWIDE_RES      	0x04
+#define		ENSDONE         	0x02
+#define		ENDMADONE       	0x01
+
 #define	CLRSINT2        		0x4d
 #define		CLRNONPACKREQ   	0x20
 #define		CLRWIDE_RES     	0x04
 #define		CLRSDONE        	0x02
 #define		CLRDMADONE      	0x01
 
-#define	SIMODE2         		0x4d
-#define		ENWIDE_RES      	0x04
-#define		ENSDONE         	0x02
-#define		ENDMADONE       	0x01
-
 #define	PERRDIAG        		0x4e
 #define		HIZERO          	0x80
 #define		HIPERR          	0x40
@@ -2871,13 +2892,6 @@
 #define		CLRNTRAMPERR    	0x02
 #define		CLROSRAMPERR    	0x01
 
-#define	LQOMODE0        		0x54
-#define		ENLQOTARGSCBPERR	0x10
-#define		ENLQOSTOPT2     	0x08
-#define		ENLQOATNLQ      	0x04
-#define		ENLQOATNPKT     	0x02
-#define		ENLQOTCRC       	0x01
-
 #define	LQOSTAT0        		0x54
 #define		LQOTARGSCBPERR  	0x10
 #define		LQOSTOPT2       	0x08
@@ -2892,6 +2906,20 @@
 #define		CLRLQOATNPKT    	0x02
 #define		CLRLQOTCRC      	0x01
 
+#define	LQOMODE0        		0x54
+#define		ENLQOTARGSCBPERR	0x10
+#define		ENLQOSTOPT2     	0x08
+#define		ENLQOATNLQ      	0x04
+#define		ENLQOATNPKT     	0x02
+#define		ENLQOTCRC       	0x01
+
+#define	LQOMODE1        		0x55
+#define		ENLQOINITSCBPERR	0x10
+#define		ENLQOSTOPI2     	0x08
+#define		ENLQOBADQAS     	0x04
+#define		ENLQOBUSFREE    	0x02
+#define		ENLQOPHACHGINPKT	0x01
+
 #define	LQOSTAT1        		0x55
 #define		LQOINITSCBPERR  	0x10
 #define		LQOSTOPI2       	0x08
@@ -2906,13 +2934,6 @@
 #define		CLRLQOBUSFREE   	0x02
 #define		CLRLQOPHACHGINPKT	0x01
 
-#define	LQOMODE1        		0x55
-#define		ENLQOINITSCBPERR	0x10
-#define		ENLQOSTOPI2     	0x08
-#define		ENLQOBADQAS     	0x04
-#define		ENLQOBUSFREE    	0x02
-#define		ENLQOPHACHGINPKT	0x01
-
 #define	LQOSTAT2        		0x56
 #define		LQOPKT          	0xe0
 #define		LQOWAITFIFO     	0x10
@@ -3028,6 +3049,8 @@
 
 #define	ANNEXCOL        		0x65
 
+#define	ANNEXDAT        		0x66
+
 #define	SCSCHKN         		0x66
 #define		STSELSKIDDIS    	0x40
 #define		CURRFIFODEF     	0x20
@@ -3037,8 +3060,6 @@
 #define		SHVALIDSTDIS    	0x02
 #define		LSTSGCLRDIS     	0x01
 
-#define	ANNEXDAT        		0x66
-
 #define	IOWNID          		0x67
 
 #define	PLL960CTL0      		0x68
@@ -3071,10 +3092,10 @@
 #define		PLL_CNTCLR      	0x40
 #define		PLL_RST         	0x01
 
-#define	PLL400CNT0      		0x6e
-
 #define	UNFAIRNESS      		0x6e
 
+#define	PLL400CNT0      		0x6e
+
 #define	HADDR           		0x70
 
 #define	PLLDELAY        		0x70
@@ -3088,14 +3109,14 @@
 
 #define	HODMAEN         		0x7a
 
-#define	SGHADDR         		0x7c
-
 #define	SCBHADDR        		0x7c
 
-#define	SGHCNT          		0x84
+#define	SGHADDR         		0x7c
 
 #define	SCBHCNT         		0x84
 
+#define	SGHCNT          		0x84
+
 #define	DFF_THRSH       		0x88
 #define		WR_DFTHRSH      	0x70
 #define		RD_DFTHRSH      	0x07
@@ -3113,8 +3134,8 @@
 #define		RD_DFTHRSH_63   	0x03
 #define		RD_DFTHRSH_50   	0x02
 #define		RD_DFTHRSH_25   	0x01
-#define		WR_DFTHRSH_MIN  	0x00
 #define		RD_DFTHRSH_MIN  	0x00
+#define		WR_DFTHRSH_MIN  	0x00
 
 #define	ROMADDR         		0x8a
 
@@ -3150,20 +3171,22 @@
 #define		DCH1NSEN        	0x02
 #define		DCH0NSEN        	0x01
 
-#define	DCHRXMSG1       		0x91
-
 #define	CMCRXMSG1       		0x91
 
-#define	DCHRXMSG2       		0x92
+#define	DCHRXMSG1       		0x91
 
-#define	OVLYRXMSG2      		0x92
+#define	DCHRXMSG2       		0x92
 
 #define	CMCRXMSG2       		0x92
 
 #define	OST             		0x92
 
+#define	OVLYRXMSG2      		0x92
+
 #define	DCHRXMSG3       		0x93
 
+#define	OVLYRXMSG3      		0x93
+
 #define	CMCRXMSG3       		0x93
 
 #define	PCIXCTL         		0x93
@@ -3175,26 +3198,24 @@
 #define		TSCSERREN       	0x02
 #define		CMPABCDIS       	0x01
 
-#define	OVLYRXMSG3      		0x93
-
 #define	OVLYSEQBCNT     		0x94
 
-#define	CMCSEQBCNT      		0x94
-
 #define	DCHSEQBCNT      		0x94
 
-#define	CMCSPLTSTAT0    		0x96
+#define	CMCSEQBCNT      		0x94
 
-#define	OVLYSPLTSTAT0   		0x96
+#define	CMCSPLTSTAT0    		0x96
 
 #define	DCHSPLTSTAT0    		0x96
 
-#define	DCHSPLTSTAT1    		0x97
+#define	OVLYSPLTSTAT0   		0x96
 
 #define	CMCSPLTSTAT1    		0x97
 
 #define	OVLYSPLTSTAT1   		0x97
 
+#define	DCHSPLTSTAT1    		0x97
+
 #define	SGRXMSG0        		0x98
 #define		CDNUM           	0xf8
 #define		CFNUM           	0x07
@@ -3244,13 +3265,13 @@
 #define		RXSCEMSG        	0x02
 #define		RXSPLTRSP       	0x01
 
+#define	SGSPLTSTAT1     		0x9f
+#define		RXDATABUCKET    	0x01
+
 #define	SFUNCT          		0x9f
 #define		TEST_GROUP      	0xf0
 #define		TEST_NUM        	0x0f
 
-#define	SGSPLTSTAT1     		0x9f
-#define		RXDATABUCKET    	0x01
-
 #define	DF0PCISTAT      		0xa0
 
 #define	REG0            		0xa0
@@ -3299,10 +3320,10 @@
 
 #define	CCSGADDR        		0xac
 
-#define	CCSCBADDR       		0xac
-
 #define	CCSCBADR_BK     		0xac
 
+#define	CCSCBADDR       		0xac
+
 #define	CMC_RAMBIST     		0xad
 #define		SG_ELEMENT_SIZE 	0x80
 #define		SCBRAMBIST_FAIL 	0x40
@@ -3311,14 +3332,6 @@
 #define		CMC_BUFFER_BIST_FAIL	0x02
 #define		CMC_BUFFER_BIST_EN	0x01
 
-#define	CCSGCTL         		0xad
-#define		CCSGEN          	0x0c
-#define		CCSGDONE        	0x80
-#define		SG_CACHE_AVAIL  	0x10
-#define		CCSGENACK       	0x08
-#define		SG_FETCH_REQ    	0x02
-#define		CCSGRESET       	0x01
-
 #define	CCSCBCTL        		0xad
 #define		CCSCBDONE       	0x80
 #define		ARRDONE         	0x40
@@ -3327,6 +3340,14 @@
 #define		CCSCBDIR        	0x04
 #define		CCSCBRESET      	0x01
 
+#define	CCSGCTL         		0xad
+#define		CCSGEN          	0x0c
+#define		CCSGDONE        	0x80
+#define		SG_CACHE_AVAIL  	0x10
+#define		CCSGENACK       	0x08
+#define		SG_FETCH_REQ    	0x02
+#define		CCSGRESET       	0x01
+
 #define	CCSGRAM         		0xb0
 
 #define	FLEXADR         		0xb0
@@ -3356,8 +3377,8 @@
 #define	SEEDAT          		0xbc
 
 #define	SEECTL          		0xbe
-#define		SEEOP_EWEN      	0x40
 #define		SEEOP_WALL      	0x40
+#define		SEEOP_EWEN      	0x40
 #define		SEEOP_EWDS      	0x40
 #define		SEEOPCODE       	0x70
 #define		SEERST          	0x02
@@ -3414,14 +3435,14 @@
 
 #define	WRTBIASCALC     		0xc7
 
-#define	DFPTRS          		0xc8
-
 #define	RCVRBIASCALC    		0xc8
 
-#define	DFBKPTR         		0xc9
+#define	DFPTRS          		0xc8
 
 #define	SKEWCALC        		0xc9
 
+#define	DFBKPTR         		0xc9
+
 #define	DFDBCTL         		0xcb
 #define		DFF_CIO_WR_RDY  	0x20
 #define		DFF_CIO_RD_RDY  	0x10
@@ -3475,11 +3496,11 @@
 
 #define	DINDEX          		0xe4
 
+#define	BRKADDR0        		0xe6
+
 #define	BRKADDR1        		0xe6
 #define		BRKDIS          	0x80
 
-#define	BRKADDR0        		0xe6
-
 #define	ALLONES         		0xe8
 
 #define	ALLZEROS        		0xea
@@ -3494,14 +3515,14 @@
 
 #define	STACK           		0xf2
 
-#define	CURADDR         		0xf4
-
 #define	INTVEC1_ADDR    		0xf4
 
-#define	INTVEC2_ADDR    		0xf6
+#define	CURADDR         		0xf4
 
 #define	LASTADDR        		0xf6
 
+#define	INTVEC2_ADDR    		0xf6
+
 #define	LONGJMP_ADDR    		0xf8
 
 #define	ACCUM_SAVE      		0xfa
@@ -3524,25 +3545,31 @@
 
 #define	COMPLETE_DMA_SCB_HEAD		0x12c
 
-#define	QFREEZE_COUNT   		0x12e
+#define	COMPLETE_DMA_SCB_TAIL		0x12e
 
-#define	SAVED_MODE      		0x130
+#define	COMPLETE_ON_QFREEZE_HEAD		0x130
 
-#define	MSG_OUT         		0x131
+#define	QFREEZE_COUNT   		0x132
 
-#define	DMAPARAMS       		0x132
+#define	KERNEL_QFREEZE_COUNT		0x134
+
+#define	SAVED_MODE      		0x136
+
+#define	MSG_OUT         		0x137
+
+#define	DMAPARAMS       		0x138
 #define		PRELOADEN       	0x80
 #define		WIDEODD         	0x40
 #define		SCSIEN          	0x20
 #define		SDMAEN          	0x10
 #define		SDMAENACK       	0x10
-#define		HDMAENACK       	0x08
 #define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
 #define		DIRECTION       	0x04
 #define		FIFOFLUSH       	0x02
 #define		FIFORESET       	0x01
 
-#define	SEQ_FLAGS       		0x133
+#define	SEQ_FLAGS       		0x139
 #define		NOT_IDENTIFIED  	0x80
 #define		NO_CDB_SENT     	0x40
 #define		TARGET_CMD_IS_TAGGED	0x40
@@ -3553,11 +3580,11 @@
 #define		SPHASE_PENDING  	0x02
 #define		NO_DISCONNECT   	0x01
 
-#define	SAVED_SCSIID    		0x134
+#define	SAVED_SCSIID    		0x13a
 
-#define	SAVED_LUN       		0x135
+#define	SAVED_LUN       		0x13b
 
-#define	LASTPHASE       		0x136
+#define	LASTPHASE       		0x13c
 #define		PHASE_MASK      	0xe0
 #define		CDI             	0x80
 #define		IOI             	0x40
@@ -3572,18 +3599,18 @@
 #define		P_DATAOUT_DT    	0x20
 #define		P_DATAOUT       	0x00
 
-#define	QOUTFIFO_ENTRY_VALID_TAG		0x137
+#define	QOUTFIFO_ENTRY_VALID_TAG		0x13d
 
-#define	SHARED_DATA_ADDR		0x138
+#define	KERNEL_TQINPOS  		0x13e
 
-#define	QOUTFIFO_NEXT_ADDR		0x13c
+#define	TQINPOS         		0x13f
 
-#define	KERNEL_TQINPOS  		0x140
+#define	SHARED_DATA_ADDR		0x140
 
-#define	TQINPOS         		0x141
+#define	QOUTFIFO_NEXT_ADDR		0x144
 
-#define	ARG_1           		0x142
-#define	RETURN_1        		0x142
+#define	ARG_1           		0x148
+#define	RETURN_1        		0x148
 #define		SEND_MSG        	0x80
 #define		SEND_SENSE      	0x40
 #define		SEND_REJ        	0x20
@@ -3593,12 +3620,12 @@
 #define		CONT_MSG_LOOP_READ	0x03
 #define		CONT_MSG_LOOP_TARG	0x02
 
-#define	ARG_2           		0x143
-#define	RETURN_2        		0x143
+#define	ARG_2           		0x149
+#define	RETURN_2        		0x149
 
-#define	LAST_MSG        		0x144
+#define	LAST_MSG        		0x14a
 
-#define	SCSISEQ_TEMPLATE		0x145
+#define	SCSISEQ_TEMPLATE		0x14b
 #define		MANUALCTL       	0x40
 #define		ENSELI          	0x20
 #define		ENRSELI         	0x10
@@ -3606,27 +3633,27 @@
 #define		ENAUTOATNP      	0x02
 #define		ALTSTIM         	0x01
 
-#define	INITIATOR_TAG   		0x146
+#define	INITIATOR_TAG   		0x14c
 
-#define	SEQ_FLAGS2      		0x147
+#define	SEQ_FLAGS2      		0x14d
 #define		SELECTOUT_QFROZEN	0x04
 #define		TARGET_MSG_PENDING	0x02
 
-#define	ALLOCFIFO_SCBPTR		0x148
+#define	ALLOCFIFO_SCBPTR		0x14e
 
-#define	INT_COALESCING_TIMER		0x14a
+#define	INT_COALESCING_TIMER		0x150
 
-#define	INT_COALESCING_MAXCMDS		0x14c
+#define	INT_COALESCING_MAXCMDS		0x152
 
-#define	INT_COALESCING_MINCMDS		0x14d
+#define	INT_COALESCING_MINCMDS		0x153
 
-#define	CMDS_PENDING    		0x14e
+#define	CMDS_PENDING    		0x154
 
-#define	INT_COALESCING_CMDCOUNT		0x150
+#define	INT_COALESCING_CMDCOUNT		0x156
 
-#define	LOCAL_HS_MAILBOX		0x151
+#define	LOCAL_HS_MAILBOX		0x157
 
-#define	CMDSIZE_TABLE   		0x152
+#define	CMDSIZE_TABLE   		0x158
 
 #define	SCB_BASE        		0x180
 
@@ -3701,6 +3728,16 @@
 #define	SCB_DISCONNECTED_LISTS		0x1b8
 
 
+#define	AHD_TIMER_MAX_US	0x18ffe7
+#define	AHD_TIMER_MAX_TICKS	0xffff
+#define	AHD_SENSE_BUFSIZE	0x100
+#define	BUS_8_BIT	0x00
+#define	TARGET_CMD_CMPLT	0xfe
+#define	SEEOP_WRAL_ADDR	0x40
+#define	AHD_AMPLITUDE_DEF	0x07
+#define	AHD_PRECOMP_CUTBACK_37	0x07
+#define	AHD_PRECOMP_SHIFT	0x00
+#define	AHD_ANNEXCOL_PRECOMP_SLEW	0x04
 #define	AHD_TIMER_US_PER_TICK	0x19
 #define	SCB_TRANSFER_SIZE_FULL_LUN	0x38
 #define	STATUS_QUEUE_FULL	0x28
@@ -3724,28 +3761,18 @@
 #define	B_CURRFIFO_0	0x02
 #define	LUNLEN_SINGLE_LEVEL_LUN	0x0f
 #define	NVRAM_SCB_OFFSET	0x2c
-#define	AHD_TIMER_MAX_US	0x18ffe7
-#define	AHD_TIMER_MAX_TICKS	0xffff
 #define	STATUS_PKT_SENSE	0xff
 #define	CMD_GROUP_CODE_SHIFT	0x05
-#define	AHD_SENSE_BUFSIZE	0x100
 #define	MAX_OFFSET_PACED_BUG	0x7f
-#define	BUS_8_BIT	0x00
 #define	STIMESEL_BUG_ADJ	0x08
 #define	STIMESEL_MIN	0x18
 #define	STIMESEL_SHIFT	0x03
 #define	CCSGRAM_MAXSEGS	0x10
 #define	INVALID_ADDR	0x80
-#define	TARGET_CMD_CMPLT	0xfe
-#define	SEEOP_WRAL_ADDR	0x40
 #define	SEEOP_ERAL_ADDR	0x80
-#define	AHD_AMPLITUDE_DEF	0x07
 #define	AHD_SLEWRATE_DEF_REVB	0x08
-#define	AHD_PRECOMP_CUTBACK_37	0x07
 #define	AHD_PRECOMP_CUTBACK_17	0x04
-#define	AHD_PRECOMP_SHIFT	0x00
 #define	AHD_PRECOMP_MASK	0x07
-#define	AHD_ANNEXCOL_PRECOMP_SLEW	0x04
 #define	SRC_MODE_SHIFT	0x00
 #define	PKT_OVERRUN_BUFSIZE	0x200
 #define	SCB_TRANSFER_SIZE_1BYTE_LUN	0x30
@@ -3761,6 +3788,7 @@
 
 
 /* Downloaded Constant Definitions */
+#define	CACHELINE_MASK	0x07
 #define	SCB_TRANSFER_SIZE	0x06
 #define	PKT_OVERRUN_BUFOFFSET	0x05
 #define	SG_SIZEOF	0x04
@@ -3768,9 +3796,9 @@
 #define	SG_PREFETCH_ALIGN_MASK	0x02
 #define	SG_PREFETCH_CNT_LIMIT	0x01
 #define	SG_PREFETCH_CNT	0x00
-#define	DOWNLOAD_CONST_COUNT	0x07
+#define	DOWNLOAD_CONST_COUNT	0x08
 
 
 /* Exported Labels */
-#define	LABEL_seq_isr 	0x269
-#define	LABEL_timer_isr	0x265
+#define	LABEL_seq_isr 	0x285
+#define	LABEL_timer_isr	0x281
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
index 3098a75..a4137c9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#118 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#75 $
  */
 
 #include "aic79xx_osm.h"
@@ -172,21 +172,6 @@
 	    0x0b, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
-	{ "CLRSEQ_SPLTINT",	0x01, 0x01 },
-	{ "CLRSEQ_PCIINT",	0x02, 0x02 },
-	{ "CLRSEQ_SCSIINT",	0x04, 0x04 },
-	{ "CLRSEQ_SEQINT",	0x08, 0x08 },
-	{ "CLRSEQ_SWTMRTO",	0x10, 0x10 }
-};
-
-int
-ahd_clrseqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(CLRSEQINTSTAT_parse_table, 5, "CLRSEQINTSTAT",
-	    0x0c, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = {
 	{ "SEQ_SPLTINT",	0x01, 0x01 },
 	{ "SEQ_PCIINT",		0x02, 0x02 },
@@ -202,6 +187,21 @@
 	    0x0c, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
+	{ "CLRSEQ_SPLTINT",	0x01, 0x01 },
+	{ "CLRSEQ_PCIINT",	0x02, 0x02 },
+	{ "CLRSEQ_SCSIINT",	0x04, 0x04 },
+	{ "CLRSEQ_SEQINT",	0x08, 0x08 },
+	{ "CLRSEQ_SWTMRTO",	0x10, 0x10 }
+};
+
+int
+ahd_clrseqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSEQINTSTAT_parse_table, 5, "CLRSEQINTSTAT",
+	    0x0c, regvalue, cur_col, wrap));
+}
+
 int
 ahd_swtimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -670,16 +670,16 @@
 }
 
 int
-ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "BUSINITID",
+	return (ahd_print_register(NULL, 0, "DLCOUNT",
 	    0x3c, regvalue, cur_col, wrap));
 }
 
 int
-ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "DLCOUNT",
+	return (ahd_print_register(NULL, 0, "BUSINITID",
 	    0x3c, regvalue, cur_col, wrap));
 }
 
@@ -859,21 +859,6 @@
 	    0x49, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
-	{ "SELWIDE",		0x02, 0x02 },
-	{ "ENAB20",		0x04, 0x04 },
-	{ "ENAB40",		0x08, 0x08 },
-	{ "DIAGLEDON",		0x40, 0x40 },
-	{ "DIAGLEDEN",		0x80, 0x80 }
-};
-
-int
-ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(SBLKCTL_parse_table, 5, "SBLKCTL",
-	    0x4a, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t OPTIONMODE_parse_table[] = {
 	{ "AUTO_MSGOUT_DE",	0x02, 0x02 },
 	{ "ENDGFORMCHK",	0x04, 0x04 },
@@ -891,22 +876,19 @@
 	    0x4a, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
-	{ "ARBDO",		0x01, 0x01 },
-	{ "SPIORDY",		0x02, 0x02 },
-	{ "OVERRUN",		0x04, 0x04 },
-	{ "IOERR",		0x08, 0x08 },
-	{ "SELINGO",		0x10, 0x10 },
-	{ "SELDI",		0x20, 0x20 },
-	{ "SELDO",		0x40, 0x40 },
-	{ "TARGET",		0x80, 0x80 }
+static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
+	{ "SELWIDE",		0x02, 0x02 },
+	{ "ENAB20",		0x04, 0x04 },
+	{ "ENAB40",		0x08, 0x08 },
+	{ "DIAGLEDON",		0x40, 0x40 },
+	{ "DIAGLEDEN",		0x80, 0x80 }
 };
 
 int
-ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0",
-	    0x4b, regvalue, cur_col, wrap));
+	return (ahd_print_register(SBLKCTL_parse_table, 5, "SBLKCTL",
+	    0x4a, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t CLRSINT0_parse_table[] = {
@@ -926,6 +908,24 @@
 	    0x4b, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
+	{ "ARBDO",		0x01, 0x01 },
+	{ "SPIORDY",		0x02, 0x02 },
+	{ "OVERRUN",		0x04, 0x04 },
+	{ "IOERR",		0x08, 0x08 },
+	{ "SELINGO",		0x10, 0x10 },
+	{ "SELDI",		0x20, 0x20 },
+	{ "SELDO",		0x40, 0x40 },
+	{ "TARGET",		0x80, 0x80 }
+};
+
+int
+ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0",
+	    0x4b, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SIMODE0_parse_table[] = {
 	{ "ENARBDO",		0x01, 0x01 },
 	{ "ENSPIORDY",		0x02, 0x02 },
@@ -998,6 +998,19 @@
 	    0x4d, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
+	{ "ENDMADONE",		0x01, 0x01 },
+	{ "ENSDONE",		0x02, 0x02 },
+	{ "ENWIDE_RES",		0x04, 0x04 }
+};
+
+int
+ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
+	    0x4d, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
 	{ "CLRDMADONE",		0x01, 0x01 },
 	{ "CLRSDONE",		0x02, 0x02 },
@@ -1012,19 +1025,6 @@
 	    0x4d, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
-	{ "ENDMADONE",		0x01, 0x01 },
-	{ "ENSDONE",		0x02, 0x02 },
-	{ "ENWIDE_RES",		0x04, 0x04 }
-};
-
-int
-ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
-	    0x4d, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t PERRDIAG_parse_table[] = {
 	{ "DTERR",		0x01, 0x01 },
 	{ "DGFORMERR",		0x02, 0x02 },
@@ -1220,21 +1220,6 @@
 	    0x53, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
-	{ "ENLQOTCRC",		0x01, 0x01 },
-	{ "ENLQOATNPKT",	0x02, 0x02 },
-	{ "ENLQOATNLQ",		0x04, 0x04 },
-	{ "ENLQOSTOPT2",	0x08, 0x08 },
-	{ "ENLQOTARGSCBPERR",	0x10, 0x10 }
-};
-
-int
-ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(LQOMODE0_parse_table, 5, "LQOMODE0",
-	    0x54, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = {
 	{ "LQOTCRC",		0x01, 0x01 },
 	{ "LQOATNPKT",		0x02, 0x02 },
@@ -1265,6 +1250,36 @@
 	    0x54, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
+	{ "ENLQOTCRC",		0x01, 0x01 },
+	{ "ENLQOATNPKT",	0x02, 0x02 },
+	{ "ENLQOATNLQ",		0x04, 0x04 },
+	{ "ENLQOSTOPT2",	0x08, 0x08 },
+	{ "ENLQOTARGSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOMODE0_parse_table, 5, "LQOMODE0",
+	    0x54, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
+	{ "ENLQOPHACHGINPKT",	0x01, 0x01 },
+	{ "ENLQOBUSFREE",	0x02, 0x02 },
+	{ "ENLQOBADQAS",	0x04, 0x04 },
+	{ "ENLQOSTOPI2",	0x08, 0x08 },
+	{ "ENLQOINITSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOMODE1_parse_table, 5, "LQOMODE1",
+	    0x55, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = {
 	{ "LQOPHACHGINPKT",	0x01, 0x01 },
 	{ "LQOBUSFREE",		0x02, 0x02 },
@@ -1295,21 +1310,6 @@
 	    0x55, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
-	{ "ENLQOPHACHGINPKT",	0x01, 0x01 },
-	{ "ENLQOBUSFREE",	0x02, 0x02 },
-	{ "ENLQOBADQAS",	0x04, 0x04 },
-	{ "ENLQOSTOPI2",	0x08, 0x08 },
-	{ "ENLQOINITSCBPERR",	0x10, 0x10 }
-};
-
-int
-ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(LQOMODE1_parse_table, 5, "LQOMODE1",
-	    0x55, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = {
 	{ "LQOSTOP0",		0x01, 0x01 },
 	{ "LQOPHACHGOUTPKT",	0x02, 0x02 },
@@ -1594,6 +1594,13 @@
 	    0x65, regvalue, cur_col, wrap));
 }
 
+int
+ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ANNEXDAT",
+	    0x66, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SCSCHKN_parse_table[] = {
 	{ "LSTSGCLRDIS",	0x01, 0x01 },
 	{ "SHVALIDSTDIS",	0x02, 0x02 },
@@ -1612,13 +1619,6 @@
 }
 
 int
-ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "ANNEXDAT",
-	    0x66, regvalue, cur_col, wrap));
-}
-
-int
 ahd_iownid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "IOWNID",
@@ -1728,16 +1728,16 @@
 }
 
 int
-ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "PLL400CNT0",
+	return (ahd_print_register(NULL, 0, "UNFAIRNESS",
 	    0x6e, regvalue, cur_col, wrap));
 }
 
 int
-ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "UNFAIRNESS",
+	return (ahd_print_register(NULL, 0, "PLL400CNT0",
 	    0x6e, regvalue, cur_col, wrap));
 }
 
@@ -1788,13 +1788,6 @@
 }
 
 int
-ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SGHADDR",
-	    0x7c, regvalue, cur_col, wrap));
-}
-
-int
 ahd_scbhaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "SCBHADDR",
@@ -1802,10 +1795,10 @@
 }
 
 int
-ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "SGHCNT",
-	    0x84, regvalue, cur_col, wrap));
+	return (ahd_print_register(NULL, 0, "SGHADDR",
+	    0x7c, regvalue, cur_col, wrap));
 }
 
 int
@@ -1815,6 +1808,13 @@
 	    0x84, regvalue, cur_col, wrap));
 }
 
+int
+ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SGHCNT",
+	    0x84, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t DFF_THRSH_parse_table[] = {
 	{ "WR_DFTHRSH_MIN",	0x00, 0x70 },
 	{ "RD_DFTHRSH_MIN",	0x00, 0x07 },
@@ -1950,17 +1950,6 @@
 	    0x91, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
-	{ "CBNUM",		0xff, 0xff }
-};
-
-int
-ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
-	    0x91, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t CMCRXMSG1_parse_table[] = {
 	{ "CBNUM",		0xff, 0xff }
 };
@@ -1972,6 +1961,17 @@
 	    0x91, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
+	{ "CBNUM",		0xff, 0xff }
+};
+
+int
+ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
+	    0x91, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t DCHRXMSG2_parse_table[] = {
 	{ "MINDEX",		0xff, 0xff }
 };
@@ -1983,17 +1983,6 @@
 	    0x92, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
-	{ "MINDEX",		0xff, 0xff }
-};
-
-int
-ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
-	    0x92, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t CMCRXMSG2_parse_table[] = {
 	{ "MINDEX",		0xff, 0xff }
 };
@@ -2012,6 +2001,17 @@
 	    0x92, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
+	{ "MINDEX",		0xff, 0xff }
+};
+
+int
+ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
+	    0x92, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t DCHRXMSG3_parse_table[] = {
 	{ "MCLASS",		0x0f, 0x0f }
 };
@@ -2023,6 +2023,17 @@
 	    0x93, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
+	{ "MCLASS",		0x0f, 0x0f }
+};
+
+int
+ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
+	    0x93, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t CMCRXMSG3_parse_table[] = {
 	{ "MCLASS",		0x0f, 0x0f }
 };
@@ -2051,17 +2062,6 @@
 	    0x93, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
-	{ "MCLASS",		0x0f, 0x0f }
-};
-
-int
-ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
-	    0x93, regvalue, cur_col, wrap));
-}
-
 int
 ahd_ovlyseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -2070,16 +2070,16 @@
 }
 
 int
-ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
+	return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
 	    0x94, regvalue, cur_col, wrap));
 }
 
 int
-ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
+	return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
 	    0x94, regvalue, cur_col, wrap));
 }
 
@@ -2101,24 +2101,6 @@
 	    0x96, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
-	{ "RXSPLTRSP",		0x01, 0x01 },
-	{ "RXSCEMSG",		0x02, 0x02 },
-	{ "RXOVRUN",		0x04, 0x04 },
-	{ "CNTNOTCMPLT",	0x08, 0x08 },
-	{ "SCDATBUCKET",	0x10, 0x10 },
-	{ "SCADERR",		0x20, 0x20 },
-	{ "SCBCERR",		0x40, 0x40 },
-	{ "STAETERM",		0x80, 0x80 }
-};
-
-int
-ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
-	    0x96, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
 	{ "RXSPLTRSP",		0x01, 0x01 },
 	{ "RXSCEMSG",		0x02, 0x02 },
@@ -2137,15 +2119,22 @@
 	    0x96, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
-	{ "RXDATABUCKET",	0x01, 0x01 }
+static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
+	{ "RXSPLTRSP",		0x01, 0x01 },
+	{ "RXSCEMSG",		0x02, 0x02 },
+	{ "RXOVRUN",		0x04, 0x04 },
+	{ "CNTNOTCMPLT",	0x08, 0x08 },
+	{ "SCDATBUCKET",	0x10, 0x10 },
+	{ "SCADERR",		0x20, 0x20 },
+	{ "SCBCERR",		0x40, 0x40 },
+	{ "STAETERM",		0x80, 0x80 }
 };
 
 int
-ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(DCHSPLTSTAT1_parse_table, 1, "DCHSPLTSTAT1",
-	    0x97, regvalue, cur_col, wrap));
+	return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
+	    0x96, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t CMCSPLTSTAT1_parse_table[] = {
@@ -2170,6 +2159,17 @@
 	    0x97, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHSPLTSTAT1_parse_table, 1, "DCHSPLTSTAT1",
+	    0x97, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SGRXMSG0_parse_table[] = {
 	{ "CFNUM",		0x07, 0x07 },
 	{ "CDNUM",		0xf8, 0xf8 }
@@ -2320,6 +2320,17 @@
 	    0x9e, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGSPLTSTAT1_parse_table, 1, "SGSPLTSTAT1",
+	    0x9f, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SFUNCT_parse_table[] = {
 	{ "TEST_NUM",		0x0f, 0x0f },
 	{ "TEST_GROUP",		0xf0, 0xf0 }
@@ -2332,17 +2343,6 @@
 	    0x9f, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
-	{ "RXDATABUCKET",	0x01, 0x01 }
-};
-
-int
-ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(SGSPLTSTAT1_parse_table, 1, "SGSPLTSTAT1",
-	    0x9f, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t DF0PCISTAT_parse_table[] = {
 	{ "DPR",		0x01, 0x01 },
 	{ "TWATERR",		0x02, 0x02 },
@@ -2537,16 +2537,16 @@
 }
 
 int
-ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "CCSCBADDR",
+	return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
 	    0xac, regvalue, cur_col, wrap));
 }
 
 int
-ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
+	return (ahd_print_register(NULL, 0, "CCSCBADDR",
 	    0xac, regvalue, cur_col, wrap));
 }
 
@@ -2566,22 +2566,6 @@
 	    0xad, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
-	{ "CCSGRESET",		0x01, 0x01 },
-	{ "SG_FETCH_REQ",	0x02, 0x02 },
-	{ "CCSGENACK",		0x08, 0x08 },
-	{ "SG_CACHE_AVAIL",	0x10, 0x10 },
-	{ "CCSGDONE",		0x80, 0x80 },
-	{ "CCSGEN",		0x0c, 0x0c }
-};
-
-int
-ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL",
-	    0xad, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = {
 	{ "CCSCBRESET",		0x01, 0x01 },
 	{ "CCSCBDIR",		0x04, 0x04 },
@@ -2598,6 +2582,22 @@
 	    0xad, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
+	{ "CCSGRESET",		0x01, 0x01 },
+	{ "SG_FETCH_REQ",	0x02, 0x02 },
+	{ "CCSGENACK",		0x08, 0x08 },
+	{ "SG_CACHE_AVAIL",	0x10, 0x10 },
+	{ "CCSGDONE",		0x80, 0x80 },
+	{ "CCSGEN",		0x0c, 0x0c }
+};
+
+int
+ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL",
+	    0xad, regvalue, cur_col, wrap));
+}
+
 int
 ahd_ccsgram_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -2841,13 +2841,6 @@
 }
 
 int
-ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "DFPTRS",
-	    0xc8, regvalue, cur_col, wrap));
-}
-
-int
 ahd_rcvrbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "RCVRBIASCALC",
@@ -2855,10 +2848,10 @@
 }
 
 int
-ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "DFBKPTR",
-	    0xc9, regvalue, cur_col, wrap));
+	return (ahd_print_register(NULL, 0, "DFPTRS",
+	    0xc8, regvalue, cur_col, wrap));
 }
 
 int
@@ -2868,6 +2861,13 @@
 	    0xc9, regvalue, cur_col, wrap));
 }
 
+int
+ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFBKPTR",
+	    0xc9, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t DFDBCTL_parse_table[] = {
 	{ "DFF_RAMBIST_EN",	0x01, 0x01 },
 	{ "DFF_RAMBIST_DONE",	0x02, 0x02 },
@@ -3001,6 +3001,13 @@
 	    0xe4, regvalue, cur_col, wrap));
 }
 
+int
+ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "BRKADDR0",
+	    0xe6, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t BRKADDR1_parse_table[] = {
 	{ "BRKDIS",		0x80, 0x80 }
 };
@@ -3013,13 +3020,6 @@
 }
 
 int
-ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "BRKADDR0",
-	    0xe6, regvalue, cur_col, wrap));
-}
-
-int
 ahd_allones_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "ALLONES",
@@ -3069,13 +3069,6 @@
 }
 
 int
-ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "CURADDR",
-	    0xf4, regvalue, cur_col, wrap));
-}
-
-int
 ahd_intvec1_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INTVEC1_ADDR",
@@ -3083,10 +3076,10 @@
 }
 
 int
-ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
-	    0xf6, regvalue, cur_col, wrap));
+	return (ahd_print_register(NULL, 0, "CURADDR",
+	    0xf4, regvalue, cur_col, wrap));
 }
 
 int
@@ -3097,6 +3090,13 @@
 }
 
 int
+ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
+	    0xf6, regvalue, cur_col, wrap));
+}
+
+int
 ahd_longjmp_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "LONGJMP_ADDR",
@@ -3174,24 +3174,45 @@
 }
 
 int
+ahd_complete_dma_scb_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_TAIL",
+	    0x12e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_complete_on_qfreeze_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "COMPLETE_ON_QFREEZE_HEAD",
+	    0x130, regvalue, cur_col, wrap));
+}
+
+int
 ahd_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "QFREEZE_COUNT",
-	    0x12e, regvalue, cur_col, wrap));
+	    0x132, regvalue, cur_col, wrap));
+}
+
+int
+ahd_kernel_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT",
+	    0x134, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_mode_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "SAVED_MODE",
-	    0x130, regvalue, cur_col, wrap));
+	    0x136, regvalue, cur_col, wrap));
 }
 
 int
 ahd_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "MSG_OUT",
-	    0x131, regvalue, cur_col, wrap));
+	    0x137, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t DMAPARAMS_parse_table[] = {
@@ -3211,7 +3232,7 @@
 ahd_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(DMAPARAMS_parse_table, 10, "DMAPARAMS",
-	    0x132, regvalue, cur_col, wrap));
+	    0x138, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
@@ -3230,21 +3251,21 @@
 ahd_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS",
-	    0x133, regvalue, cur_col, wrap));
+	    0x139, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "SAVED_SCSIID",
-	    0x134, regvalue, cur_col, wrap));
+	    0x13a, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "SAVED_LUN",
-	    0x135, regvalue, cur_col, wrap));
+	    0x13b, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t LASTPHASE_parse_table[] = {
@@ -3267,42 +3288,42 @@
 ahd_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(LASTPHASE_parse_table, 13, "LASTPHASE",
-	    0x136, regvalue, cur_col, wrap));
+	    0x13c, regvalue, cur_col, wrap));
 }
 
 int
 ahd_qoutfifo_entry_valid_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG",
-	    0x137, regvalue, cur_col, wrap));
-}
-
-int
-ahd_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SHARED_DATA_ADDR",
-	    0x138, regvalue, cur_col, wrap));
-}
-
-int
-ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR",
-	    0x13c, regvalue, cur_col, wrap));
+	    0x13d, regvalue, cur_col, wrap));
 }
 
 int
 ahd_kernel_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "KERNEL_TQINPOS",
-	    0x140, regvalue, cur_col, wrap));
+	    0x13e, regvalue, cur_col, wrap));
 }
 
 int
 ahd_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "TQINPOS",
-	    0x141, regvalue, cur_col, wrap));
+	    0x13f, regvalue, cur_col, wrap));
+}
+
+int
+ahd_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SHARED_DATA_ADDR",
+	    0x140, regvalue, cur_col, wrap));
+}
+
+int
+ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR",
+	    0x144, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t ARG_1_parse_table[] = {
@@ -3320,21 +3341,21 @@
 ahd_arg_1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(ARG_1_parse_table, 8, "ARG_1",
-	    0x142, regvalue, cur_col, wrap));
+	    0x148, regvalue, cur_col, wrap));
 }
 
 int
 ahd_arg_2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "ARG_2",
-	    0x143, regvalue, cur_col, wrap));
+	    0x149, regvalue, cur_col, wrap));
 }
 
 int
 ahd_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "LAST_MSG",
-	    0x144, regvalue, cur_col, wrap));
+	    0x14a, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
@@ -3350,14 +3371,14 @@
 ahd_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(SCSISEQ_TEMPLATE_parse_table, 6, "SCSISEQ_TEMPLATE",
-	    0x145, regvalue, cur_col, wrap));
+	    0x14b, regvalue, cur_col, wrap));
 }
 
 int
 ahd_initiator_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INITIATOR_TAG",
-	    0x146, regvalue, cur_col, wrap));
+	    0x14c, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
@@ -3369,63 +3390,63 @@
 ahd_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(SEQ_FLAGS2_parse_table, 2, "SEQ_FLAGS2",
-	    0x147, regvalue, cur_col, wrap));
+	    0x14d, regvalue, cur_col, wrap));
 }
 
 int
 ahd_allocfifo_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR",
-	    0x148, regvalue, cur_col, wrap));
+	    0x14e, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER",
-	    0x14a, regvalue, cur_col, wrap));
+	    0x150, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS",
-	    0x14c, regvalue, cur_col, wrap));
+	    0x152, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS",
-	    0x14d, regvalue, cur_col, wrap));
+	    0x153, regvalue, cur_col, wrap));
 }
 
 int
 ahd_cmds_pending_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "CMDS_PENDING",
-	    0x14e, regvalue, cur_col, wrap));
+	    0x154, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT",
-	    0x150, regvalue, cur_col, wrap));
+	    0x156, regvalue, cur_col, wrap));
 }
 
 int
 ahd_local_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX",
-	    0x151, regvalue, cur_col, wrap));
+	    0x157, regvalue, cur_col, wrap));
 }
 
 int
 ahd_cmdsize_table_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "CMDSIZE_TABLE",
-	    0x152, regvalue, cur_col, wrap));
+	    0x158, regvalue, cur_col, wrap));
 }
 
 int
diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
index 77c471f..b1e5365 100644
--- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
@@ -2,215 +2,228 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
  */
 static uint8_t seqprog[] = {
 	0xff, 0x02, 0x06, 0x78,
-	0x00, 0xea, 0x50, 0x59,
+	0x00, 0xea, 0x64, 0x59,
 	0x01, 0xea, 0x04, 0x30,
 	0xff, 0x04, 0x0c, 0x78,
-	0x19, 0xea, 0x50, 0x59,
+	0x19, 0xea, 0x64, 0x59,
 	0x19, 0xea, 0x04, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x60, 0x3a, 0x1a, 0x68,
-	0x04, 0x47, 0x1b, 0x68,
-	0xff, 0x21, 0x1b, 0x70,
-	0x40, 0x4b, 0x92, 0x69,
-	0x00, 0xe2, 0x54, 0x59,
-	0x40, 0x4b, 0x92, 0x69,
-	0x20, 0x4b, 0x82, 0x69,
-	0xfc, 0x42, 0x24, 0x78,
-	0x10, 0x40, 0x24, 0x78,
-	0x00, 0xe2, 0xc4, 0x5d,
-	0x20, 0x4d, 0x28, 0x78,
-	0x00, 0xe2, 0xc4, 0x5d,
+	0x60, 0x3a, 0x3a, 0x68,
+	0x04, 0x4d, 0x35, 0x78,
+	0x01, 0x34, 0xc1, 0x31,
+	0x00, 0x32, 0x21, 0x60,
+	0x01, 0x35, 0xc1, 0x31,
+	0x00, 0x33, 0x21, 0x60,
+	0xfb, 0x4d, 0x9b, 0x0a,
+	0x00, 0xe2, 0x34, 0x40,
+	0x50, 0x4b, 0x3a, 0x68,
+	0xff, 0x31, 0x3b, 0x70,
+	0x02, 0x30, 0x51, 0x31,
+	0xff, 0x8d, 0x2d, 0x70,
+	0x02, 0x8c, 0x51, 0x31,
+	0xff, 0x8d, 0x29, 0x60,
+	0x02, 0x28, 0x19, 0x33,
+	0x02, 0x30, 0x51, 0x32,
+	0xff, 0xea, 0x62, 0x02,
+	0x00, 0xe2, 0x3a, 0x40,
+	0xff, 0x21, 0x3b, 0x70,
+	0x40, 0x4b, 0xaa, 0x69,
+	0x00, 0xe2, 0x68, 0x59,
+	0x40, 0x4b, 0xaa, 0x69,
+	0x20, 0x4b, 0x96, 0x69,
+	0xfc, 0x42, 0x44, 0x78,
+	0x10, 0x40, 0x44, 0x78,
+	0x00, 0xe2, 0xfc, 0x5d,
+	0x20, 0x4d, 0x48, 0x78,
+	0x00, 0xe2, 0xfc, 0x5d,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x30, 0x60,
+	0x30, 0xe0, 0x50, 0x60,
 	0x7f, 0x4a, 0x94, 0x08,
-	0x00, 0xe2, 0x32, 0x40,
+	0x00, 0xe2, 0x52, 0x40,
 	0xc0, 0x4a, 0x94, 0x00,
-	0x00, 0xe2, 0x3e, 0x58,
-	0x00, 0xe2, 0x56, 0x58,
-	0x00, 0xe2, 0x66, 0x58,
+	0x00, 0xe2, 0x5e, 0x58,
+	0x00, 0xe2, 0x76, 0x58,
+	0x00, 0xe2, 0x86, 0x58,
 	0x00, 0xe2, 0x06, 0x40,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x01, 0x52, 0x64, 0x78,
+	0x01, 0x52, 0x84, 0x78,
 	0x02, 0x58, 0x50, 0x31,
 	0xff, 0xea, 0x10, 0x0b,
-	0xff, 0x97, 0x4f, 0x78,
-	0x50, 0x4b, 0x4a, 0x68,
+	0xff, 0x97, 0x6f, 0x78,
+	0x50, 0x4b, 0x6a, 0x68,
 	0xbf, 0x3a, 0x74, 0x08,
-	0x14, 0xea, 0x50, 0x59,
+	0x14, 0xea, 0x64, 0x59,
 	0x14, 0xea, 0x04, 0x00,
 	0x08, 0x92, 0x25, 0x03,
-	0xff, 0x90, 0x3f, 0x68,
-	0x00, 0xe2, 0x56, 0x5b,
-	0x00, 0xe2, 0x3e, 0x40,
-	0x00, 0xea, 0x44, 0x59,
+	0xff, 0x90, 0x5f, 0x68,
+	0x00, 0xe2, 0x76, 0x5b,
+	0x00, 0xe2, 0x5e, 0x40,
+	0x00, 0xea, 0x5e, 0x59,
 	0x01, 0xea, 0x00, 0x30,
-	0x80, 0xf9, 0x5e, 0x68,
-	0x00, 0xe2, 0x42, 0x59,
-	0x11, 0xea, 0x44, 0x59,
+	0x80, 0xf9, 0x7e, 0x68,
+	0x00, 0xe2, 0x5c, 0x59,
+	0x11, 0xea, 0x5e, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x80, 0xf9, 0x42, 0x79,
+	0x80, 0xf9, 0x5c, 0x79,
 	0xff, 0xea, 0xd4, 0x0d,
-	0x22, 0xea, 0x44, 0x59,
+	0x22, 0xea, 0x5e, 0x59,
 	0x22, 0xea, 0x00, 0x00,
-	0x10, 0x16, 0x70, 0x78,
-	0x01, 0x0b, 0xa2, 0x32,
+	0x10, 0x16, 0x90, 0x78,
 	0x10, 0x16, 0x2c, 0x00,
-	0x18, 0xad, 0x00, 0x79,
-	0x04, 0xad, 0xca, 0x68,
-	0x80, 0xad, 0x64, 0x78,
-	0x10, 0xad, 0x98, 0x78,
-	0xff, 0x88, 0x83, 0x68,
+	0x01, 0x0b, 0xae, 0x32,
+	0x18, 0xad, 0x12, 0x79,
+	0x04, 0xad, 0xdc, 0x68,
+	0x80, 0xad, 0x84, 0x78,
+	0x10, 0xad, 0xaa, 0x78,
 	0xe7, 0xad, 0x5a, 0x09,
 	0x02, 0x8c, 0x59, 0x32,
+	0xff, 0x8d, 0xa1, 0x60,
+	0xff, 0xea, 0x5e, 0x02,
+	0xff, 0x88, 0xa7, 0x78,
+	0x02, 0x30, 0x19, 0x33,
+	0x02, 0xa8, 0x60, 0x36,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0x33, 0xea, 0x44, 0x59,
-	0x33, 0xea, 0x00, 0x00,
-	0x40, 0x3a, 0x64, 0x68,
-	0x50, 0x4b, 0x64, 0x68,
-	0x22, 0xea, 0x44, 0x59,
-	0x22, 0xea, 0x00, 0x00,
 	0xe7, 0xad, 0x5a, 0x09,
-	0x02, 0x8c, 0x59, 0x32,
-	0x1a, 0xea, 0x50, 0x59,
-	0x1a, 0xea, 0x04, 0x00,
-	0xff, 0xea, 0xd4, 0x0d,
-	0xe7, 0xad, 0x5a, 0x09,
-	0x00, 0xe2, 0xa6, 0x58,
+	0x00, 0xe2, 0xb8, 0x58,
 	0xff, 0xea, 0x56, 0x02,
-	0x04, 0x7c, 0x78, 0x32,
-	0x20, 0x16, 0x64, 0x78,
-	0x04, 0x38, 0x79, 0x32,
-	0x80, 0x37, 0x6f, 0x16,
-	0xff, 0x2d, 0xb5, 0x60,
-	0xff, 0x29, 0xb5, 0x60,
-	0x40, 0x51, 0xc5, 0x78,
-	0xff, 0x4f, 0xb5, 0x68,
-	0xff, 0x4d, 0xc1, 0x19,
-	0x00, 0x4e, 0xd5, 0x19,
-	0x00, 0xe2, 0xc4, 0x50,
-	0x01, 0x4c, 0xc1, 0x31,
-	0x00, 0x50, 0xd5, 0x19,
-	0x00, 0xe2, 0xc4, 0x48,
-	0x80, 0x18, 0x64, 0x78,
-	0x02, 0x4a, 0x1d, 0x30,
+	0x04, 0x7c, 0x88, 0x32,
+	0x20, 0x16, 0x84, 0x78,
+	0x04, 0x40, 0x89, 0x32,
+	0x80, 0x3d, 0x7b, 0x16,
+	0xff, 0x2d, 0xc7, 0x60,
+	0xff, 0x29, 0xc7, 0x60,
+	0x40, 0x57, 0xd7, 0x78,
+	0xff, 0x55, 0xc7, 0x68,
+	0xff, 0x53, 0xc1, 0x19,
+	0x00, 0x54, 0xd5, 0x19,
+	0x00, 0xe2, 0xd6, 0x50,
+	0x01, 0x52, 0xc1, 0x31,
+	0x00, 0x56, 0xd5, 0x19,
+	0x00, 0xe2, 0xd6, 0x48,
+	0x80, 0x18, 0x84, 0x78,
+	0x02, 0x50, 0x1d, 0x30,
 	0x10, 0xea, 0x18, 0x00,
 	0x60, 0x18, 0x30, 0x00,
 	0x7f, 0x18, 0x30, 0x0c,
 	0x02, 0xea, 0x02, 0x00,
-	0xff, 0xea, 0xa0, 0x0a,
+	0xff, 0xea, 0xac, 0x0a,
 	0x80, 0x18, 0x30, 0x04,
-	0x40, 0xad, 0x64, 0x78,
+	0x40, 0xad, 0x84, 0x78,
 	0xe7, 0xad, 0x5a, 0x09,
 	0x02, 0xa8, 0x40, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
-	0x01, 0x4e, 0x9d, 0x1a,
-	0x00, 0x4f, 0x9f, 0x22,
+	0x01, 0x54, 0xa9, 0x1a,
+	0x00, 0x55, 0xab, 0x22,
 	0x01, 0x94, 0x6d, 0x33,
-	0x01, 0xea, 0x20, 0x33,
+	0xff, 0xea, 0x20, 0x0b,
 	0x04, 0xac, 0x49, 0x32,
 	0xff, 0xea, 0x5a, 0x03,
 	0xff, 0xea, 0x5e, 0x03,
 	0x01, 0x10, 0xd4, 0x31,
-	0x10, 0x92, 0xf5, 0x68,
+	0x10, 0x92, 0x07, 0x69,
 	0x3d, 0x93, 0xc5, 0x29,
 	0xfe, 0xe2, 0xc4, 0x09,
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x50, 0x31,
 	0x02, 0xa0, 0xda, 0x31,
-	0xff, 0xa9, 0xf4, 0x70,
+	0xff, 0xa9, 0x06, 0x71,
 	0x02, 0xa0, 0x58, 0x37,
-	0xff, 0x21, 0xfd, 0x70,
+	0xff, 0x21, 0x0f, 0x71,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x5c, 0x33,
 	0x02, 0xa0, 0x44, 0x36,
 	0x02, 0xa0, 0x40, 0x32,
 	0x02, 0xa0, 0x44, 0x36,
-	0x04, 0x47, 0x05, 0x69,
-	0x40, 0x16, 0x30, 0x69,
-	0xff, 0x2d, 0x35, 0x61,
-	0xff, 0x29, 0x65, 0x70,
-	0x01, 0x37, 0xc1, 0x31,
+	0x04, 0x4d, 0x17, 0x69,
+	0x40, 0x16, 0x48, 0x69,
+	0xff, 0x2d, 0x4d, 0x61,
+	0xff, 0x29, 0x85, 0x70,
 	0x02, 0x28, 0x55, 0x32,
 	0x01, 0xea, 0x5a, 0x01,
-	0x04, 0x3c, 0xf9, 0x30,
+	0x04, 0x44, 0xf9, 0x30,
+	0x01, 0x44, 0xc1, 0x31,
 	0x02, 0x28, 0x51, 0x31,
-	0x01, 0xa8, 0x60, 0x31,
-	0x00, 0xa9, 0x60, 0x01,
+	0x02, 0xa8, 0x60, 0x31,
+	0x01, 0xa4, 0x61, 0x31,
+	0x01, 0x3d, 0x61, 0x31,
 	0x01, 0x14, 0xd4, 0x31,
-	0x01, 0x50, 0xa1, 0x1a,
-	0xff, 0x4e, 0x9d, 0x1a,
-	0xff, 0x4f, 0x9f, 0x22,
-	0xff, 0x8d, 0x29, 0x71,
-	0x80, 0xac, 0x28, 0x71,
-	0x20, 0x16, 0x28, 0x69,
+	0x01, 0x56, 0xad, 0x1a,
+	0xff, 0x54, 0xa9, 0x1a,
+	0xff, 0x55, 0xab, 0x22,
+	0xff, 0x8d, 0x41, 0x71,
+	0x80, 0xac, 0x40, 0x71,
+	0x20, 0x16, 0x40, 0x69,
+	0x00, 0xac, 0xc4, 0x19,
+	0x07, 0xe2, 0x40, 0xf9,
 	0x02, 0x8c, 0x51, 0x31,
-	0x00, 0xe2, 0x12, 0x41,
+	0x00, 0xe2, 0x24, 0x41,
 	0x01, 0xac, 0x08, 0x31,
 	0x09, 0xea, 0x5a, 0x01,
 	0x02, 0x8c, 0x51, 0x32,
 	0xff, 0xea, 0x1a, 0x07,
 	0x04, 0x24, 0xf9, 0x30,
-	0x1d, 0xea, 0x3a, 0x41,
+	0x1d, 0xea, 0x52, 0x41,
 	0x02, 0x2c, 0x51, 0x31,
 	0x04, 0xa8, 0xf9, 0x30,
-	0x19, 0xea, 0x3a, 0x41,
+	0x19, 0xea, 0x52, 0x41,
 	0x06, 0xea, 0x08, 0x81,
 	0x01, 0xe2, 0x5a, 0x35,
-	0x02, 0xf2, 0xf0, 0x35,
+	0x02, 0xf2, 0xf0, 0x31,
+	0xff, 0xea, 0xd4, 0x0d,
 	0x02, 0xf2, 0xf0, 0x31,
 	0x02, 0xf8, 0xe4, 0x35,
 	0x80, 0xea, 0xb2, 0x01,
 	0x01, 0xe2, 0x00, 0x30,
 	0xff, 0xea, 0xb2, 0x0d,
-	0x80, 0xea, 0xb2, 0x01,
-	0x11, 0x00, 0x00, 0x10,
-	0xff, 0xea, 0xb2, 0x0d,
 	0x01, 0xe2, 0x04, 0x30,
 	0x01, 0xea, 0x04, 0x34,
 	0x02, 0x20, 0xbd, 0x30,
 	0x02, 0x20, 0xb9, 0x30,
 	0x02, 0x20, 0x51, 0x31,
 	0x4c, 0x93, 0xd7, 0x28,
-	0x10, 0x92, 0x63, 0x79,
+	0x10, 0x92, 0x77, 0x79,
 	0x01, 0x6b, 0xc0, 0x30,
 	0x02, 0x64, 0xc8, 0x00,
 	0x40, 0x3a, 0x74, 0x04,
-	0x00, 0xe2, 0x56, 0x58,
-	0x33, 0xea, 0x44, 0x59,
+	0x00, 0xe2, 0x76, 0x58,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x64, 0x61,
-	0x20, 0x3f, 0x7a, 0x69,
-	0x10, 0x3f, 0x64, 0x79,
+	0x30, 0xe0, 0x78, 0x61,
+	0x20, 0x3f, 0x8e, 0x69,
+	0x10, 0x3f, 0x78, 0x79,
 	0x02, 0xea, 0x7e, 0x00,
-	0x00, 0xea, 0x44, 0x59,
+	0x00, 0xea, 0x5e, 0x59,
 	0x01, 0xea, 0x00, 0x30,
-	0x02, 0x48, 0x51, 0x35,
+	0x02, 0x4e, 0x51, 0x35,
 	0x01, 0xea, 0x7e, 0x00,
-	0x11, 0xea, 0x44, 0x59,
+	0x11, 0xea, 0x5e, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x02, 0x48, 0x51, 0x35,
+	0x02, 0x4e, 0x51, 0x35,
+	0xc0, 0x4a, 0x94, 0x00,
+	0x04, 0x41, 0x9c, 0x79,
 	0x08, 0xea, 0x98, 0x00,
 	0x08, 0x57, 0xae, 0x00,
 	0x08, 0x3c, 0x78, 0x00,
-	0xf0, 0x49, 0x68, 0x0a,
+	0xf0, 0x49, 0x74, 0x0a,
 	0x0f, 0x67, 0xc0, 0x09,
-	0x00, 0x34, 0x69, 0x02,
+	0x00, 0x3a, 0x75, 0x02,
 	0x20, 0xea, 0x96, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x40, 0x3a, 0xae, 0x69,
+	0x00, 0xe2, 0x14, 0x42,
+	0xc0, 0x4a, 0x94, 0x00,
+	0x40, 0x3a, 0xc8, 0x69,
 	0x02, 0x55, 0x06, 0x68,
-	0x02, 0x56, 0xae, 0x69,
-	0xff, 0x5b, 0xae, 0x61,
+	0x02, 0x56, 0xc8, 0x69,
+	0xff, 0x5b, 0xc8, 0x61,
 	0x02, 0x20, 0x51, 0x31,
 	0x80, 0xea, 0xb2, 0x01,
 	0x44, 0xea, 0x00, 0x00,
@@ -218,237 +231,246 @@
 	0x33, 0xea, 0x00, 0x00,
 	0xff, 0xea, 0xb2, 0x09,
 	0xff, 0xe0, 0xc0, 0x19,
-	0xff, 0xe0, 0xb0, 0x79,
+	0xff, 0xe0, 0xca, 0x79,
 	0x02, 0xac, 0x51, 0x31,
-	0x00, 0xe2, 0xa6, 0x41,
+	0x00, 0xe2, 0xc0, 0x41,
 	0x02, 0x5e, 0x50, 0x31,
 	0x02, 0xa8, 0xb8, 0x30,
 	0x02, 0x5c, 0x50, 0x31,
-	0xff, 0xad, 0xc1, 0x71,
+	0xff, 0xad, 0xdb, 0x71,
 	0x02, 0xac, 0x41, 0x31,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x5c, 0x33,
 	0x02, 0xa0, 0x44, 0x32,
-	0x00, 0xe2, 0xca, 0x41,
-	0x10, 0x92, 0xcb, 0x69,
+	0x00, 0xe2, 0xe4, 0x41,
+	0x10, 0x92, 0xe5, 0x69,
 	0x3d, 0x93, 0xc9, 0x29,
 	0x01, 0xe4, 0xc8, 0x01,
 	0x01, 0xea, 0xca, 0x01,
 	0xff, 0xea, 0xda, 0x01,
 	0x02, 0x20, 0x51, 0x31,
 	0x02, 0xae, 0x41, 0x32,
-	0xff, 0x21, 0xd3, 0x61,
+	0xff, 0x21, 0xed, 0x61,
 	0xff, 0xea, 0x46, 0x02,
 	0x02, 0x5c, 0x50, 0x31,
 	0x40, 0xea, 0x96, 0x00,
-	0x02, 0x56, 0xcc, 0x6d,
-	0x01, 0x55, 0xcc, 0x6d,
-	0x10, 0x92, 0xdf, 0x79,
-	0x10, 0x40, 0xe8, 0x69,
-	0x01, 0x56, 0xe8, 0x79,
+	0x02, 0x56, 0x04, 0x6e,
+	0x01, 0x55, 0x04, 0x6e,
+	0x10, 0x92, 0xf9, 0x79,
+	0x10, 0x40, 0x02, 0x6a,
+	0x01, 0x56, 0x02, 0x7a,
 	0xff, 0x97, 0x07, 0x78,
-	0x13, 0xea, 0x50, 0x59,
+	0x13, 0xea, 0x64, 0x59,
 	0x13, 0xea, 0x04, 0x00,
 	0x00, 0xe2, 0x06, 0x40,
 	0xbf, 0x3a, 0x74, 0x08,
+	0x04, 0x41, 0x08, 0x7a,
 	0x08, 0xea, 0x98, 0x00,
 	0x08, 0x57, 0xae, 0x00,
-	0x01, 0x93, 0x69, 0x32,
-	0x01, 0x94, 0x6b, 0x32,
-	0x40, 0xea, 0x66, 0x02,
+	0x01, 0x93, 0x75, 0x32,
+	0x01, 0x94, 0x77, 0x32,
+	0x40, 0xea, 0x72, 0x02,
 	0x08, 0x3c, 0x78, 0x00,
-	0x80, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0x01, 0x36, 0xc1, 0x31,
-	0x9f, 0xe0, 0x4c, 0x7c,
-	0x80, 0xe0, 0x0c, 0x72,
-	0xa0, 0xe0, 0x44, 0x72,
-	0xc0, 0xe0, 0x3a, 0x72,
-	0xe0, 0xe0, 0x74, 0x72,
-	0x01, 0xea, 0x50, 0x59,
+	0x80, 0xea, 0x6e, 0x02,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0x01, 0x3c, 0xc1, 0x31,
+	0x9f, 0xe0, 0x84, 0x7c,
+	0x80, 0xe0, 0x28, 0x72,
+	0xa0, 0xe0, 0x64, 0x72,
+	0xc0, 0xe0, 0x5a, 0x72,
+	0xe0, 0xe0, 0x94, 0x72,
+	0x01, 0xea, 0x64, 0x59,
 	0x01, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x80, 0x33, 0x13, 0x7a,
-	0x03, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x14, 0x42,
+	0x80, 0x39, 0x2f, 0x7a,
+	0x03, 0xea, 0x64, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0xee, 0x00, 0x1a, 0x6a,
+	0xee, 0x00, 0x36, 0x6a,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x6a, 0x59,
+	0x02, 0xa8, 0x9c, 0x32,
+	0x00, 0xe2, 0x7e, 0x59,
 	0xef, 0x96, 0xd5, 0x19,
-	0x00, 0xe2, 0x2a, 0x52,
+	0x00, 0xe2, 0x46, 0x52,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x30, 0x42,
+	0x00, 0xe2, 0x4c, 0x42,
 	0x01, 0x96, 0xd1, 0x30,
 	0x10, 0x80, 0x89, 0x31,
 	0x20, 0xea, 0x32, 0x00,
-	0xbf, 0x33, 0x67, 0x0a,
-	0x20, 0x19, 0x32, 0x6a,
-	0x02, 0x4d, 0xf8, 0x69,
-	0x40, 0x33, 0x67, 0x02,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x80, 0x33, 0xb5, 0x6a,
+	0xbf, 0x39, 0x73, 0x0a,
+	0x10, 0x4c, 0x56, 0x6a,
+	0x20, 0x19, 0x4e, 0x6a,
+	0x20, 0x19, 0x52, 0x6a,
+	0x02, 0x4d, 0x14, 0x6a,
+	0x40, 0x39, 0x73, 0x02,
+	0x00, 0xe2, 0x14, 0x42,
+	0x80, 0x39, 0xd5, 0x6a,
 	0x01, 0x44, 0x10, 0x33,
 	0x08, 0x92, 0x25, 0x03,
-	0x00, 0xe2, 0xf8, 0x41,
+	0x00, 0xe2, 0x14, 0x42,
 	0x10, 0xea, 0x80, 0x00,
-	0x01, 0x31, 0xc5, 0x31,
-	0x80, 0xe2, 0x60, 0x62,
-	0x10, 0x92, 0x85, 0x6a,
+	0x01, 0x37, 0xc5, 0x31,
+	0x80, 0xe2, 0x80, 0x62,
+	0x10, 0x92, 0xa5, 0x6a,
 	0xc0, 0x94, 0xc5, 0x01,
-	0x40, 0x92, 0x51, 0x6a,
+	0x40, 0x92, 0x71, 0x6a,
 	0xbf, 0xe2, 0xc4, 0x09,
-	0x20, 0x92, 0x65, 0x7a,
+	0x20, 0x92, 0x85, 0x7a,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0xa0, 0x36, 0x6d, 0x62,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0xa0, 0x3c, 0x8d, 0x62,
 	0x23, 0x92, 0x89, 0x08,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0xa0, 0x36, 0x6d, 0x62,
-	0x00, 0xa8, 0x64, 0x42,
-	0xff, 0xe2, 0x64, 0x62,
-	0x00, 0xe2, 0x84, 0x42,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0xa0, 0x3c, 0x8d, 0x62,
+	0x00, 0xa8, 0x84, 0x42,
+	0xff, 0xe2, 0x84, 0x62,
+	0x00, 0xe2, 0xa4, 0x42,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0xa0, 0x36, 0x43, 0x72,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0xa0, 0x3c, 0x63, 0x72,
 	0x40, 0xea, 0x98, 0x00,
-	0x01, 0x31, 0x89, 0x32,
-	0x08, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xf8, 0x41,
-	0xe0, 0xea, 0xd4, 0x5b,
-	0x80, 0xe0, 0xc0, 0x6a,
-	0x04, 0xe0, 0x66, 0x73,
-	0x02, 0xe0, 0x96, 0x73,
-	0x00, 0xea, 0x1e, 0x73,
-	0x03, 0xe0, 0xa6, 0x73,
-	0x23, 0xe0, 0x96, 0x72,
-	0x08, 0xe0, 0xbc, 0x72,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0x07, 0xea, 0x50, 0x59,
+	0x01, 0x37, 0x95, 0x32,
+	0x08, 0xea, 0x6e, 0x02,
+	0x00, 0xe2, 0x14, 0x42,
+	0xe0, 0xea, 0xfe, 0x5b,
+	0x80, 0xe0, 0xe0, 0x6a,
+	0x04, 0xe0, 0x92, 0x73,
+	0x02, 0xe0, 0xc4, 0x73,
+	0x00, 0xea, 0x3e, 0x73,
+	0x03, 0xe0, 0xd4, 0x73,
+	0x23, 0xe0, 0xb6, 0x72,
+	0x08, 0xe0, 0xdc, 0x72,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0x07, 0xea, 0x64, 0x59,
 	0x07, 0xea, 0x04, 0x00,
-	0x08, 0x42, 0xf9, 0x71,
-	0x04, 0x42, 0x93, 0x62,
-	0x01, 0x43, 0x89, 0x30,
-	0x00, 0xe2, 0x84, 0x42,
+	0x08, 0x48, 0x15, 0x72,
+	0x04, 0x48, 0xb3, 0x62,
+	0x01, 0x49, 0x89, 0x30,
+	0x00, 0xe2, 0xa4, 0x42,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0x84, 0x42,
-	0x01, 0x00, 0x60, 0x32,
-	0x33, 0xea, 0x44, 0x59,
+	0x00, 0xe2, 0xa4, 0x42,
+	0x01, 0x00, 0x6c, 0x32,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x4c, 0x34, 0xc1, 0x28,
+	0x4c, 0x3a, 0xc1, 0x28,
 	0x01, 0x64, 0xc0, 0x31,
-	0x00, 0x30, 0x45, 0x59,
-	0x01, 0x30, 0x01, 0x30,
-	0x01, 0xe0, 0xba, 0x7a,
-	0xa0, 0xea, 0xca, 0x5b,
-	0x01, 0xa0, 0xba, 0x62,
-	0x01, 0x84, 0xaf, 0x7a,
-	0x01, 0x95, 0xbd, 0x6a,
-	0x05, 0xea, 0x50, 0x59,
+	0x00, 0x36, 0x5f, 0x59,
+	0x01, 0x36, 0x01, 0x30,
+	0x01, 0xe0, 0xda, 0x7a,
+	0xa0, 0xea, 0xf4, 0x5b,
+	0x01, 0xa0, 0xda, 0x62,
+	0x01, 0x84, 0xcf, 0x7a,
+	0x01, 0x95, 0xdd, 0x6a,
+	0x05, 0xea, 0x64, 0x59,
 	0x05, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xbc, 0x42,
-	0x03, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xdc, 0x42,
+	0x03, 0xea, 0x64, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xbc, 0x42,
-	0x07, 0xea, 0xdc, 0x5b,
+	0x00, 0xe2, 0xdc, 0x42,
+	0x07, 0xea, 0x06, 0x5c,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x3f, 0xe0, 0x6a, 0x0a,
-	0xc0, 0x34, 0xc1, 0x09,
-	0x00, 0x35, 0x51, 0x01,
+	0x00, 0xe2, 0x14, 0x42,
+	0x3f, 0xe0, 0x76, 0x0a,
+	0xc0, 0x3a, 0xc1, 0x09,
+	0x00, 0x3b, 0x51, 0x01,
 	0xff, 0xea, 0x52, 0x09,
-	0x30, 0x34, 0xc5, 0x09,
+	0x30, 0x3a, 0xc5, 0x09,
 	0x3d, 0xe2, 0xc4, 0x29,
 	0xb8, 0xe2, 0xc4, 0x19,
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x40, 0x31,
-	0xff, 0xa1, 0xdc, 0x72,
+	0xff, 0xa1, 0xfc, 0x72,
 	0x02, 0xe8, 0xda, 0x31,
 	0x02, 0xa0, 0x50, 0x31,
-	0x00, 0xe2, 0xfe, 0x42,
-	0x80, 0x33, 0x67, 0x02,
+	0x00, 0xe2, 0x1e, 0x43,
+	0x80, 0x39, 0x73, 0x02,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xb8, 0x5b,
-	0x01, 0x33, 0x67, 0x02,
-	0xe0, 0x36, 0x19, 0x63,
-	0x02, 0x33, 0x67, 0x02,
-	0x20, 0x46, 0x12, 0x63,
+	0x00, 0xe2, 0xe2, 0x5b,
+	0x01, 0x39, 0x73, 0x02,
+	0xe0, 0x3c, 0x39, 0x63,
+	0x02, 0x39, 0x73, 0x02,
+	0x20, 0x46, 0x32, 0x63,
 	0xff, 0xea, 0x52, 0x09,
-	0xa8, 0xea, 0xca, 0x5b,
-	0x04, 0x92, 0xf9, 0x7a,
-	0x01, 0x34, 0xc1, 0x31,
-	0x00, 0x93, 0xf9, 0x62,
-	0x01, 0x35, 0xc1, 0x31,
-	0x00, 0x94, 0x03, 0x73,
+	0xa8, 0xea, 0xf4, 0x5b,
+	0x04, 0x92, 0x19, 0x7b,
+	0x01, 0x3a, 0xc1, 0x31,
+	0x00, 0x93, 0x19, 0x63,
+	0x01, 0x3b, 0xc1, 0x31,
+	0x00, 0x94, 0x23, 0x73,
 	0x01, 0xa9, 0x52, 0x11,
-	0xff, 0xa9, 0xee, 0x6a,
-	0x00, 0xe2, 0x12, 0x43,
-	0x10, 0x33, 0x67, 0x02,
-	0x04, 0x92, 0x13, 0x7b,
+	0xff, 0xa9, 0x0e, 0x6b,
+	0x00, 0xe2, 0x32, 0x43,
+	0x10, 0x39, 0x73, 0x02,
+	0x04, 0x92, 0x33, 0x7b,
 	0xfb, 0x92, 0x25, 0x0b,
-	0xff, 0xea, 0x66, 0x0a,
-	0x01, 0xa4, 0x0d, 0x6b,
-	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x6a, 0x59,
-	0x10, 0x92, 0xbd, 0x7a,
-	0xff, 0xea, 0xdc, 0x5b,
-	0x00, 0xe2, 0xbc, 0x42,
-	0x04, 0xea, 0x50, 0x59,
+	0xff, 0xea, 0x72, 0x0a,
+	0x01, 0xa4, 0x2d, 0x6b,
+	0x02, 0xa8, 0x9c, 0x32,
+	0x00, 0xe2, 0x7e, 0x59,
+	0x10, 0x92, 0xdd, 0x7a,
+	0xff, 0xea, 0x06, 0x5c,
+	0x00, 0xe2, 0xdc, 0x42,
+	0x04, 0xea, 0x64, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xbc, 0x42,
-	0x04, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xdc, 0x42,
+	0x04, 0xea, 0x64, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x08, 0x92, 0xb5, 0x7a,
-	0xc0, 0x33, 0x29, 0x7b,
-	0x80, 0x33, 0xb5, 0x6a,
-	0xff, 0x88, 0x29, 0x6b,
-	0x40, 0x33, 0xb5, 0x6a,
-	0x10, 0x92, 0x2f, 0x7b,
-	0x0a, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x14, 0x42,
+	0x08, 0x92, 0xd5, 0x7a,
+	0xc0, 0x39, 0x49, 0x7b,
+	0x80, 0x39, 0xd5, 0x6a,
+	0xff, 0x88, 0x49, 0x6b,
+	0x40, 0x39, 0xd5, 0x6a,
+	0x10, 0x92, 0x4f, 0x7b,
+	0x0a, 0xea, 0x64, 0x59,
 	0x0a, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x4e, 0x5b,
-	0x00, 0xe2, 0x82, 0x43,
-	0x50, 0x4b, 0x36, 0x6b,
+	0x00, 0xe2, 0x6e, 0x5b,
+	0x00, 0xe2, 0xae, 0x43,
+	0x50, 0x4b, 0x56, 0x6b,
 	0xbf, 0x3a, 0x74, 0x08,
 	0x01, 0xe0, 0xf4, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
-	0x01, 0x2e, 0x5d, 0x1a,
-	0x00, 0x2f, 0x5f, 0x22,
-	0x04, 0x47, 0x8f, 0x02,
+	0x01, 0x32, 0x65, 0x1a,
+	0x00, 0x33, 0x67, 0x22,
+	0x04, 0x4d, 0x9b, 0x02,
 	0x01, 0xfa, 0xc0, 0x35,
-	0x02, 0xa8, 0x84, 0x32,
+	0x02, 0xa8, 0x90, 0x32,
 	0x02, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x02, 0x42, 0x51, 0x31,
-	0xff, 0x90, 0x65, 0x68,
-	0xff, 0x88, 0x5b, 0x6b,
-	0x01, 0xa4, 0x57, 0x6b,
-	0x02, 0xa4, 0x5f, 0x6b,
-	0x01, 0x84, 0x5f, 0x7b,
+	0x02, 0x48, 0x51, 0x31,
+	0xff, 0x90, 0x85, 0x68,
+	0xff, 0x88, 0x7b, 0x6b,
+	0x01, 0xa4, 0x77, 0x6b,
+	0x02, 0xa4, 0x7f, 0x6b,
+	0x01, 0x84, 0x7f, 0x7b,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0xff, 0x88, 0x5f, 0x73,
-	0x00, 0xe2, 0x32, 0x5b,
+	0xff, 0x88, 0x7f, 0x73,
+	0x00, 0xe2, 0x52, 0x5b,
 	0x02, 0xa8, 0x20, 0x33,
-	0x02, 0x2c, 0x19, 0x33,
+	0x04, 0xa4, 0x49, 0x03,
+	0xff, 0xea, 0x1a, 0x03,
+	0xff, 0x2d, 0x8b, 0x63,
 	0x02, 0xa8, 0x58, 0x32,
-	0x04, 0xa4, 0x49, 0x07,
-	0xc0, 0x33, 0xb5, 0x6a,
-	0x04, 0x92, 0x25, 0x03,
-	0x20, 0x92, 0x83, 0x6b,
+	0x02, 0xa8, 0x5c, 0x36,
 	0x02, 0xa8, 0x40, 0x31,
-	0xc0, 0x34, 0xc1, 0x09,
-	0x00, 0x35, 0x51, 0x01,
+	0x02, 0x2e, 0x51, 0x31,
+	0x02, 0xa0, 0x18, 0x33,
+	0x02, 0xa0, 0x5c, 0x36,
+	0xc0, 0x39, 0xd5, 0x6a,
+	0x04, 0x92, 0x25, 0x03,
+	0x20, 0x92, 0xaf, 0x6b,
+	0x02, 0xa8, 0x40, 0x31,
+	0xc0, 0x3a, 0xc1, 0x09,
+	0x00, 0x3b, 0x51, 0x01,
 	0xff, 0xea, 0x52, 0x09,
-	0x30, 0x34, 0xc5, 0x09,
+	0x30, 0x3a, 0xc5, 0x09,
 	0x3d, 0xe2, 0xc4, 0x29,
 	0xb8, 0xe2, 0xc4, 0x19,
 	0x01, 0xea, 0xc6, 0x01,
@@ -458,69 +480,75 @@
 	0xf7, 0x57, 0xae, 0x08,
 	0x08, 0xea, 0x98, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0xee, 0x00, 0x8c, 0x6b,
+	0xee, 0x00, 0xb8, 0x6b,
 	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0xb4, 0x5b,
-	0x09, 0x4c, 0x8e, 0x7b,
+	0xc0, 0xea, 0x72, 0x02,
+	0x09, 0x4c, 0xba, 0x7b,
+	0x01, 0xea, 0x78, 0x02,
 	0x08, 0x4c, 0x06, 0x68,
-	0x0b, 0xea, 0x50, 0x59,
+	0x0b, 0xea, 0x64, 0x59,
 	0x0b, 0xea, 0x04, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0x20, 0x33, 0xf9, 0x79,
-	0x00, 0xe2, 0x9e, 0x5b,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x01, 0x84, 0xa3, 0x7b,
+	0x20, 0x39, 0x15, 0x7a,
+	0x00, 0xe2, 0xcc, 0x5b,
+	0x00, 0xe2, 0x14, 0x42,
+	0x01, 0x84, 0xd1, 0x7b,
 	0x01, 0xa4, 0x49, 0x07,
 	0x08, 0x60, 0x30, 0x33,
 	0x08, 0x80, 0x41, 0x37,
-	0xdf, 0x33, 0x67, 0x0a,
-	0xee, 0x00, 0xb0, 0x6b,
+	0xdf, 0x39, 0x73, 0x0a,
+	0xee, 0x00, 0xde, 0x6b,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x6a, 0x59,
-	0x00, 0xe2, 0xbc, 0x42,
-	0x01, 0xea, 0x6c, 0x02,
-	0xc0, 0xea, 0x66, 0x06,
-	0xff, 0x42, 0xc4, 0x6b,
-	0x01, 0x41, 0xb8, 0x6b,
-	0x02, 0x41, 0xb8, 0x7b,
-	0xff, 0x42, 0xc4, 0x6b,
-	0x01, 0x41, 0xb8, 0x6b,
-	0x02, 0x41, 0xb8, 0x7b,
-	0xff, 0x42, 0xc4, 0x7b,
-	0x04, 0x4c, 0xb8, 0x6b,
-	0xe0, 0x41, 0x6c, 0x0e,
+	0x00, 0xe2, 0x7e, 0x59,
+	0x00, 0xe2, 0xdc, 0x42,
+	0xff, 0x42, 0xee, 0x6b,
+	0x01, 0x41, 0xe2, 0x6b,
+	0x02, 0x41, 0xe2, 0x7b,
+	0xff, 0x42, 0xee, 0x6b,
+	0x01, 0x41, 0xe2, 0x6b,
+	0x02, 0x41, 0xe2, 0x7b,
+	0xff, 0x42, 0xee, 0x7b,
+	0x04, 0x4c, 0xe2, 0x6b,
+	0xe0, 0x41, 0x78, 0x0e,
 	0x01, 0x44, 0xd4, 0x31,
-	0xff, 0x42, 0xcc, 0x7b,
-	0x04, 0x4c, 0xcc, 0x6b,
-	0xe0, 0x41, 0x6c, 0x0a,
-	0xe0, 0x36, 0xf9, 0x61,
+	0xff, 0x42, 0xf6, 0x7b,
+	0x04, 0x4c, 0xf6, 0x6b,
+	0xe0, 0x41, 0x78, 0x0a,
+	0xe0, 0x3c, 0x15, 0x62,
 	0xff, 0xea, 0xca, 0x09,
 	0x01, 0xe2, 0xc8, 0x31,
 	0x01, 0x46, 0xda, 0x35,
 	0x01, 0x44, 0xd4, 0x35,
 	0x10, 0xea, 0x80, 0x00,
-	0x01, 0xe2, 0x62, 0x36,
-	0x04, 0xa6, 0xe4, 0x7b,
+	0x01, 0xe2, 0x6e, 0x36,
+	0x04, 0xa6, 0x0e, 0x7c,
 	0xff, 0xea, 0x5a, 0x09,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x01, 0xa6, 0x02, 0x6c,
-	0x10, 0xad, 0x64, 0x78,
-	0x80, 0xad, 0xfa, 0x6b,
-	0x08, 0xad, 0x64, 0x68,
+	0x01, 0xa6, 0x3a, 0x6c,
+	0x10, 0xad, 0x84, 0x78,
+	0x80, 0xad, 0x32, 0x6c,
+	0x08, 0xad, 0x84, 0x68,
+	0x20, 0x19, 0x26, 0x7c,
+	0x80, 0xea, 0xb2, 0x01,
+	0x11, 0x00, 0x00, 0x10,
+	0x02, 0xa6, 0x22, 0x7c,
+	0xff, 0xea, 0xb2, 0x0d,
+	0x11, 0x00, 0x00, 0x10,
+	0xff, 0xea, 0xb2, 0x09,
 	0x04, 0x84, 0xf9, 0x30,
 	0x00, 0xea, 0x08, 0x81,
 	0xff, 0xea, 0xd4, 0x09,
 	0x02, 0x84, 0xf9, 0x88,
 	0x0d, 0xea, 0x5a, 0x01,
 	0x04, 0xa6, 0x4c, 0x05,
-	0x04, 0xa6, 0x64, 0x78,
+	0x04, 0xa6, 0x84, 0x78,
 	0xff, 0xea, 0x5a, 0x09,
 	0x03, 0x84, 0x59, 0x89,
 	0x03, 0xea, 0x4c, 0x01,
-	0x80, 0x1a, 0x64, 0x78,
-	0x08, 0x19, 0x64, 0x78,
+	0x80, 0x1a, 0x84, 0x78,
+	0x08, 0x19, 0x84, 0x78,
 	0x08, 0xb0, 0xe0, 0x30,
 	0x04, 0xb0, 0xe0, 0x30,
 	0x03, 0xb0, 0xf0, 0x30,
@@ -533,259 +561,259 @@
 	0x00, 0x86, 0x0d, 0x23,
 	0x00, 0x87, 0x0f, 0x23,
 	0x01, 0x84, 0xc5, 0x31,
-	0x80, 0x83, 0x25, 0x7c,
+	0x80, 0x83, 0x5d, 0x7c,
 	0x02, 0xe2, 0xc4, 0x01,
 	0xff, 0xea, 0x4c, 0x09,
 	0x01, 0xe2, 0x36, 0x30,
 	0xc8, 0x19, 0x32, 0x00,
 	0x88, 0x19, 0x32, 0x00,
 	0x01, 0xac, 0xd4, 0x99,
-	0x00, 0xe2, 0x64, 0x50,
+	0x00, 0xe2, 0x84, 0x50,
 	0xfe, 0xa6, 0x4c, 0x0d,
 	0x0b, 0x98, 0xe1, 0x30,
 	0xfd, 0xa4, 0x49, 0x09,
-	0x80, 0xa3, 0x39, 0x7c,
+	0x80, 0xa3, 0x71, 0x7c,
 	0x02, 0xa4, 0x48, 0x01,
 	0x01, 0xa4, 0x36, 0x30,
 	0xa8, 0xea, 0x32, 0x00,
 	0xfd, 0xa4, 0x49, 0x0b,
 	0x05, 0xa3, 0x07, 0x33,
-	0x80, 0x83, 0x45, 0x6c,
+	0x80, 0x83, 0x7d, 0x6c,
 	0x02, 0xea, 0x4c, 0x05,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x02, 0xa6, 0xe6, 0x6b,
+	0x00, 0xe2, 0x56, 0x59,
+	0x02, 0xa6, 0x10, 0x6c,
 	0x80, 0xf9, 0xf2, 0x05,
-	0xc0, 0x33, 0x53, 0x7c,
-	0x03, 0xea, 0x50, 0x59,
+	0xc0, 0x39, 0x8b, 0x7c,
+	0x03, 0xea, 0x64, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x20, 0x33, 0x77, 0x7c,
-	0x01, 0x84, 0x5d, 0x6c,
-	0x06, 0xea, 0x50, 0x59,
+	0x20, 0x39, 0xaf, 0x7c,
+	0x01, 0x84, 0x95, 0x6c,
+	0x06, 0xea, 0x64, 0x59,
 	0x06, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x7a, 0x44,
-	0x01, 0x00, 0x60, 0x32,
-	0xee, 0x00, 0x66, 0x6c,
+	0x00, 0xe2, 0xb2, 0x44,
+	0x01, 0x00, 0x6c, 0x32,
+	0xee, 0x00, 0x9e, 0x6c,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x5e, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x80, 0x3d, 0x7a, 0x00,
-	0xfc, 0x42, 0x68, 0x7c,
+	0xfc, 0x42, 0xa0, 0x7c,
 	0x7f, 0x3d, 0x7a, 0x08,
-	0x00, 0x30, 0x45, 0x59,
-	0x01, 0x30, 0x01, 0x30,
-	0x09, 0xea, 0x50, 0x59,
+	0x00, 0x36, 0x5f, 0x59,
+	0x01, 0x36, 0x01, 0x30,
+	0x09, 0xea, 0x64, 0x59,
 	0x09, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x01, 0xa4, 0x5d, 0x6c,
-	0x00, 0xe2, 0x30, 0x5c,
-	0x20, 0x33, 0x67, 0x02,
-	0x01, 0x00, 0x60, 0x32,
-	0x02, 0xa6, 0x82, 0x7c,
-	0x00, 0xe2, 0x46, 0x5c,
-	0x00, 0xe2, 0x56, 0x58,
-	0x00, 0xe2, 0x66, 0x58,
-	0x00, 0xe2, 0x3a, 0x58,
-	0x00, 0x30, 0x45, 0x59,
-	0x01, 0x30, 0x01, 0x30,
-	0x20, 0x19, 0x82, 0x6c,
-	0x00, 0xe2, 0xb2, 0x5c,
-	0x04, 0x19, 0x9c, 0x6c,
+	0x00, 0xe2, 0x14, 0x42,
+	0x01, 0xa4, 0x95, 0x6c,
+	0x00, 0xe2, 0x68, 0x5c,
+	0x20, 0x39, 0x73, 0x02,
+	0x01, 0x00, 0x6c, 0x32,
+	0x02, 0xa6, 0xba, 0x7c,
+	0x00, 0xe2, 0x7e, 0x5c,
+	0x00, 0xe2, 0x76, 0x58,
+	0x00, 0xe2, 0x86, 0x58,
+	0x00, 0xe2, 0x5a, 0x58,
+	0x00, 0x36, 0x5f, 0x59,
+	0x01, 0x36, 0x01, 0x30,
+	0x20, 0x19, 0xba, 0x6c,
+	0x00, 0xe2, 0xea, 0x5c,
+	0x04, 0x19, 0xd4, 0x6c,
 	0x02, 0x19, 0x32, 0x00,
-	0x01, 0x84, 0x9d, 0x7c,
-	0x01, 0x1b, 0x96, 0x7c,
-	0x01, 0x1a, 0x9c, 0x6c,
-	0x00, 0xe2, 0x4c, 0x44,
-	0x80, 0x4b, 0xa2, 0x6c,
-	0x01, 0x4c, 0x9e, 0x7c,
-	0x03, 0x42, 0x4c, 0x6c,
-	0x00, 0xe2, 0xe0, 0x5b,
+	0x01, 0x84, 0xd5, 0x7c,
+	0x01, 0x1b, 0xce, 0x7c,
+	0x01, 0x1a, 0xd4, 0x6c,
+	0x00, 0xe2, 0x84, 0x44,
+	0x80, 0x4b, 0xda, 0x6c,
+	0x01, 0x4c, 0xd6, 0x7c,
+	0x03, 0x42, 0x84, 0x6c,
+	0x00, 0xe2, 0x0a, 0x5c,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x04, 0x33, 0xf9, 0x79,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x08, 0x5d, 0xba, 0x6c,
-	0x00, 0xe2, 0x56, 0x58,
-	0x00, 0x30, 0x45, 0x59,
-	0x01, 0x30, 0x01, 0x30,
-	0x02, 0x1b, 0xaa, 0x7c,
-	0x08, 0x5d, 0xb8, 0x7c,
+	0x04, 0x39, 0x15, 0x7a,
+	0x00, 0xe2, 0x14, 0x42,
+	0x08, 0x5d, 0xf2, 0x6c,
+	0x00, 0xe2, 0x76, 0x58,
+	0x00, 0x36, 0x5f, 0x59,
+	0x01, 0x36, 0x01, 0x30,
+	0x02, 0x1b, 0xe2, 0x7c,
+	0x08, 0x5d, 0xf0, 0x7c,
 	0x03, 0x68, 0x00, 0x37,
 	0x01, 0x84, 0x09, 0x07,
-	0x80, 0x1b, 0xc4, 0x7c,
-	0x80, 0x84, 0xc5, 0x6c,
+	0x80, 0x1b, 0xfc, 0x7c,
+	0x80, 0x84, 0xfd, 0x6c,
 	0xff, 0x85, 0x0b, 0x1b,
 	0xff, 0x86, 0x0d, 0x23,
 	0xff, 0x87, 0x0f, 0x23,
 	0xf8, 0x1b, 0x08, 0x0b,
 	0xff, 0xea, 0x06, 0x0b,
 	0x03, 0x68, 0x00, 0x37,
-	0x00, 0xe2, 0xc4, 0x58,
+	0x00, 0xe2, 0xd6, 0x58,
 	0x10, 0xea, 0x18, 0x00,
 	0xf9, 0xd9, 0xb2, 0x0d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x01, 0x52, 0x48, 0x31,
-	0x20, 0xa4, 0xee, 0x7c,
-	0x20, 0x5b, 0xee, 0x7c,
-	0x80, 0xf9, 0xfc, 0x7c,
+	0x20, 0xa4, 0x26, 0x7d,
+	0x20, 0x5b, 0x26, 0x7d,
+	0x80, 0xf9, 0x34, 0x7d,
 	0x02, 0xea, 0xb4, 0x00,
 	0x11, 0x00, 0x00, 0x10,
-	0x04, 0x19, 0x08, 0x7d,
+	0x04, 0x19, 0x40, 0x7d,
 	0xdf, 0x19, 0x32, 0x08,
-	0x60, 0x5b, 0xe6, 0x6c,
-	0x01, 0x4c, 0xe2, 0x7c,
+	0x60, 0x5b, 0x40, 0x6d,
+	0x01, 0x4c, 0x1a, 0x7d,
 	0x20, 0x19, 0x32, 0x00,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x02, 0xea, 0xb4, 0x00,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x10, 0x5b, 0x00, 0x6d,
-	0x08, 0x5b, 0x0a, 0x6d,
-	0x20, 0x5b, 0xfa, 0x6c,
-	0x02, 0x5b, 0x2a, 0x6d,
-	0x0e, 0xea, 0x50, 0x59,
+	0x10, 0x5b, 0x38, 0x6d,
+	0x08, 0x5b, 0x42, 0x6d,
+	0x20, 0x5b, 0x32, 0x6d,
+	0x02, 0x5b, 0x62, 0x6d,
+	0x0e, 0xea, 0x64, 0x59,
 	0x0e, 0xea, 0x04, 0x00,
-	0x80, 0xf9, 0xea, 0x6c,
+	0x80, 0xf9, 0x22, 0x6d,
 	0xdf, 0x5c, 0xb8, 0x08,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x01, 0xa4, 0xe5, 0x6d,
-	0x00, 0xe2, 0x30, 0x5c,
-	0x00, 0xe2, 0x34, 0x5d,
+	0x01, 0xa4, 0x1d, 0x6e,
+	0x00, 0xe2, 0x68, 0x5c,
+	0x00, 0xe2, 0x6c, 0x5d,
 	0x01, 0x90, 0x21, 0x1b,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x00, 0xe2, 0x32, 0x5b,
+	0x00, 0xe2, 0x52, 0x5b,
 	0xf3, 0x96, 0xd5, 0x19,
-	0x00, 0xe2, 0x18, 0x55,
-	0x80, 0x96, 0x19, 0x6d,
-	0x0f, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x50, 0x55,
+	0x80, 0x96, 0x51, 0x6d,
+	0x0f, 0xea, 0x64, 0x59,
 	0x0f, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x20, 0x45,
+	0x00, 0xe2, 0x58, 0x45,
 	0x04, 0x8c, 0xe1, 0x30,
 	0x01, 0xea, 0xf2, 0x00,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0xff, 0x97, 0x27, 0x7d,
-	0x14, 0xea, 0x50, 0x59,
+	0xff, 0x97, 0x5f, 0x7d,
+	0x14, 0xea, 0x64, 0x59,
 	0x14, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x96, 0x5d,
+	0x00, 0xe2, 0xce, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x8e, 0x5d,
+	0x00, 0xe2, 0xc6, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x02, 0xa6, 0x44, 0x7d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x20, 0x5b, 0x52, 0x6d,
-	0xfc, 0x42, 0x3e, 0x7d,
-	0x10, 0x40, 0x40, 0x6d,
-	0x20, 0x4d, 0x42, 0x7d,
-	0x08, 0x5d, 0x52, 0x6d,
-	0x02, 0xa6, 0xe6, 0x6b,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x20, 0x5b, 0x52, 0x6d,
-	0x01, 0x1b, 0x72, 0x6d,
-	0xfc, 0x42, 0x4e, 0x7d,
-	0x10, 0x40, 0x50, 0x6d,
-	0x20, 0x4d, 0x64, 0x78,
-	0x08, 0x5d, 0x64, 0x78,
+	0x02, 0xa6, 0x7c, 0x7d,
+	0x00, 0xe2, 0x56, 0x59,
+	0x20, 0x5b, 0x8a, 0x6d,
+	0xfc, 0x42, 0x76, 0x7d,
+	0x10, 0x40, 0x78, 0x6d,
+	0x20, 0x4d, 0x7a, 0x7d,
+	0x08, 0x5d, 0x8a, 0x6d,
+	0x02, 0xa6, 0x10, 0x6c,
+	0x00, 0xe2, 0x56, 0x59,
+	0x20, 0x5b, 0x8a, 0x6d,
+	0x01, 0x1b, 0xaa, 0x6d,
+	0xfc, 0x42, 0x86, 0x7d,
+	0x10, 0x40, 0x88, 0x6d,
+	0x20, 0x4d, 0x84, 0x78,
+	0x08, 0x5d, 0x84, 0x78,
 	0x02, 0x19, 0x32, 0x00,
 	0x01, 0x5b, 0x40, 0x31,
-	0x00, 0xe2, 0xb2, 0x5c,
-	0x00, 0xe2, 0x9e, 0x5b,
+	0x00, 0xe2, 0xea, 0x5c,
+	0x00, 0xe2, 0xcc, 0x5b,
 	0x20, 0xea, 0xb6, 0x00,
-	0x00, 0xe2, 0xe0, 0x5b,
+	0x00, 0xe2, 0x0a, 0x5c,
 	0x20, 0x5c, 0xb8, 0x00,
-	0x04, 0x19, 0x68, 0x6d,
-	0x01, 0x1a, 0x68, 0x6d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x01, 0x1a, 0x64, 0x78,
+	0x04, 0x19, 0xa0, 0x6d,
+	0x01, 0x1a, 0xa0, 0x6d,
+	0x00, 0xe2, 0x56, 0x59,
+	0x01, 0x1a, 0x84, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x20, 0xa0, 0xcc, 0x7d,
+	0x20, 0xa0, 0x04, 0x7e,
 	0xff, 0x90, 0x21, 0x1b,
-	0x08, 0x92, 0x43, 0x6b,
+	0x08, 0x92, 0x63, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
 	0x01, 0xa4, 0x49, 0x03,
-	0x40, 0x5b, 0x82, 0x6d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x40, 0x5b, 0x82, 0x6d,
-	0x04, 0x5d, 0xe6, 0x7d,
-	0x01, 0x1a, 0xe6, 0x7d,
-	0x20, 0x4d, 0x64, 0x78,
-	0x40, 0x5b, 0xcc, 0x7d,
-	0x04, 0x5d, 0xe6, 0x7d,
-	0x01, 0x1a, 0xe6, 0x7d,
+	0x40, 0x5b, 0xba, 0x6d,
+	0x00, 0xe2, 0x56, 0x59,
+	0x40, 0x5b, 0xba, 0x6d,
+	0x04, 0x5d, 0x1e, 0x7e,
+	0x01, 0x1a, 0x1e, 0x7e,
+	0x20, 0x4d, 0x84, 0x78,
+	0x40, 0x5b, 0x04, 0x7e,
+	0x04, 0x5d, 0x1e, 0x7e,
+	0x01, 0x1a, 0x1e, 0x7e,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0x90, 0x21, 0x1b,
-	0x08, 0x92, 0x43, 0x6b,
+	0x08, 0x92, 0x63, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x01, 0x1b, 0x64, 0x78,
+	0x00, 0xe2, 0x56, 0x59,
+	0x01, 0x1b, 0x84, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
 	0x02, 0xea, 0xb4, 0x04,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x01, 0x1b, 0xaa, 0x6d,
-	0x40, 0x5b, 0xb8, 0x7d,
-	0x01, 0x1b, 0xaa, 0x6d,
+	0x00, 0xe2, 0x56, 0x59,
+	0x01, 0x1b, 0xe2, 0x6d,
+	0x40, 0x5b, 0xf0, 0x7d,
+	0x01, 0x1b, 0xe2, 0x6d,
 	0x02, 0x19, 0x32, 0x00,
-	0x01, 0x1a, 0x64, 0x78,
+	0x01, 0x1a, 0x84, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xea, 0x10, 0x03,
 	0x08, 0x92, 0x25, 0x03,
-	0x00, 0xe2, 0x42, 0x43,
-	0x01, 0x1a, 0xb4, 0x7d,
-	0x40, 0x5b, 0xb0, 0x7d,
-	0x01, 0x1a, 0x9e, 0x6d,
-	0xfc, 0x42, 0x64, 0x78,
-	0x01, 0x1a, 0xb8, 0x6d,
-	0x10, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x62, 0x43,
+	0x01, 0x1a, 0xec, 0x7d,
+	0x40, 0x5b, 0xe8, 0x7d,
+	0x01, 0x1a, 0xd6, 0x6d,
+	0xfc, 0x42, 0x84, 0x78,
+	0x01, 0x1a, 0xf0, 0x6d,
+	0x10, 0xea, 0x64, 0x59,
 	0x10, 0xea, 0x04, 0x00,
-	0xfc, 0x42, 0x64, 0x78,
-	0x10, 0x40, 0xbe, 0x6d,
-	0x20, 0x4d, 0x64, 0x78,
-	0x40, 0x5b, 0x9e, 0x6d,
-	0x01, 0x1a, 0x64, 0x78,
+	0xfc, 0x42, 0x84, 0x78,
+	0x10, 0x40, 0xf6, 0x6d,
+	0x20, 0x4d, 0x84, 0x78,
+	0x40, 0x5b, 0xd6, 0x6d,
+	0x01, 0x1a, 0x84, 0x78,
 	0x01, 0x90, 0x21, 0x1b,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x64, 0x60,
-	0x40, 0x4b, 0x64, 0x68,
+	0x30, 0xe0, 0x84, 0x60,
+	0x40, 0x4b, 0x84, 0x68,
 	0xff, 0xea, 0x52, 0x01,
-	0xee, 0x00, 0xd2, 0x6d,
+	0xee, 0x00, 0x0c, 0x6e,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0x90, 0x21, 0x1b,
 	0x02, 0xea, 0xb4, 0x00,
 	0x20, 0xea, 0x9a, 0x00,
-	0xf3, 0x42, 0xde, 0x6d,
-	0x12, 0xea, 0x50, 0x59,
+	0xf3, 0x42, 0x16, 0x6e,
+	0x12, 0xea, 0x64, 0x59,
 	0x12, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x0d, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x14, 0x42,
+	0x0d, 0xea, 0x64, 0x59,
 	0x0d, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
+	0x00, 0xe2, 0x14, 0x42,
 	0x01, 0x90, 0x21, 0x1b,
-	0x11, 0xea, 0x50, 0x59,
+	0x11, 0xea, 0x64, 0x59,
 	0x11, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x32, 0x5b,
+	0x00, 0xe2, 0x52, 0x5b,
 	0x08, 0x5a, 0xb4, 0x00,
-	0x00, 0xe2, 0x0c, 0x5e,
+	0x00, 0xe2, 0x44, 0x5e,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x80, 0x1a, 0xfa, 0x7d,
-	0x00, 0xe2, 0x0c, 0x5e,
+	0x00, 0xe2, 0x56, 0x59,
+	0x80, 0x1a, 0x32, 0x7e,
+	0x00, 0xe2, 0x44, 0x5e,
 	0x80, 0x19, 0x32, 0x00,
-	0x40, 0x5b, 0x00, 0x6e,
-	0x08, 0x5a, 0x00, 0x7e,
-	0x20, 0x4d, 0x64, 0x78,
+	0x40, 0x5b, 0x38, 0x6e,
+	0x08, 0x5a, 0x38, 0x7e,
+	0x20, 0x4d, 0x84, 0x78,
 	0x02, 0x84, 0x09, 0x03,
-	0x40, 0x5b, 0xcc, 0x7d,
+	0x40, 0x5b, 0x04, 0x7e,
 	0xff, 0x90, 0x21, 0x1b,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x08, 0x92, 0x43, 0x6b,
+	0x08, 0x92, 0x63, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
-	0x01, 0x38, 0xe1, 0x30,
-	0x05, 0x39, 0xe3, 0x98,
+	0x01, 0x40, 0xe1, 0x30,
+	0x05, 0x41, 0xe3, 0x98,
 	0x01, 0xe0, 0xf4, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
-	0x00, 0x3a, 0xe5, 0x20,
-	0x00, 0x3b, 0xe7, 0x20,
+	0x00, 0x42, 0xe5, 0x20,
+	0x00, 0x43, 0xe7, 0x20,
 	0x01, 0xfa, 0xc0, 0x31,
 	0x04, 0xea, 0xe8, 0x30,
 	0xff, 0xea, 0xf0, 0x08,
@@ -794,12 +822,20 @@
 };
 
 typedef int ahd_patch_func_t (struct ahd_softc *ahd);
+static ahd_patch_func_t ahd_patch23_func;
+
+static int
+ahd_patch23_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+}
+
 static ahd_patch_func_t ahd_patch22_func;
 
 static int
 ahd_patch22_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch21_func;
@@ -807,7 +843,7 @@
 static int
 ahd_patch21_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+	return ((ahd->flags & AHD_INITIATORROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch20_func;
@@ -815,7 +851,7 @@
 static int
 ahd_patch20_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_RTI) == 0);
+	return ((ahd->flags & AHD_TARGETROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch19_func;
@@ -823,7 +859,7 @@
 static int
 ahd_patch19_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_INITIATORROLE) != 0);
+	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch18_func;
@@ -831,7 +867,7 @@
 static int
 ahd_patch18_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_TARGETROLE) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
 }
 
 static ahd_patch_func_t ahd_patch17_func;
@@ -839,7 +875,7 @@
 static int
 ahd_patch17_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
+	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch16_func;
@@ -847,7 +883,7 @@
 static int
 ahd_patch16_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
+	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch15_func;
@@ -855,7 +891,7 @@
 static int
 ahd_patch15_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
 }
 
 static ahd_patch_func_t ahd_patch14_func;
@@ -863,7 +899,7 @@
 static int
 ahd_patch14_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
+	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch13_func;
@@ -871,7 +907,7 @@
 static int
 ahd_patch13_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
+	return ((ahd->features & AHD_RTI) == 0);
 }
 
 static ahd_patch_func_t ahd_patch12_func;
@@ -879,7 +915,7 @@
 static int
 ahd_patch12_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
+	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch11_func;
@@ -887,7 +923,7 @@
 static int
 ahd_patch11_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch10_func;
@@ -895,7 +931,7 @@
 static int
 ahd_patch10_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
+	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch9_func;
@@ -903,7 +939,7 @@
 static int
 ahd_patch9_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
+	return ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0);
 }
 
 static ahd_patch_func_t ahd_patch8_func;
@@ -992,147 +1028,149 @@
 	{ ahd_patch0_func, 5, 1, 1 },
 	{ ahd_patch2_func, 6, 1, 2 },
 	{ ahd_patch0_func, 7, 1, 1 },
-	{ ahd_patch3_func, 20, 5, 1 },
-	{ ahd_patch2_func, 29, 1, 2 },
-	{ ahd_patch0_func, 30, 1, 1 },
-	{ ahd_patch1_func, 37, 1, 2 },
-	{ ahd_patch0_func, 38, 1, 1 },
-	{ ahd_patch2_func, 43, 1, 2 },
-	{ ahd_patch0_func, 44, 1, 1 },
-	{ ahd_patch2_func, 47, 1, 2 },
-	{ ahd_patch0_func, 48, 1, 1 },
-	{ ahd_patch2_func, 51, 1, 2 },
-	{ ahd_patch0_func, 52, 1, 1 },
-	{ ahd_patch2_func, 65, 1, 2 },
-	{ ahd_patch0_func, 66, 1, 1 },
-	{ ahd_patch2_func, 69, 1, 2 },
-	{ ahd_patch0_func, 70, 1, 1 },
-	{ ahd_patch1_func, 73, 1, 2 },
-	{ ahd_patch0_func, 74, 1, 1 },
-	{ ahd_patch4_func, 107, 1, 1 },
-	{ ahd_patch2_func, 162, 6, 1 },
-	{ ahd_patch1_func, 168, 2, 1 },
-	{ ahd_patch5_func, 170, 1, 1 },
-	{ ahd_patch2_func, 179, 1, 2 },
-	{ ahd_patch0_func, 180, 1, 1 },
-	{ ahd_patch6_func, 181, 2, 2 },
-	{ ahd_patch0_func, 183, 6, 3 },
-	{ ahd_patch2_func, 186, 1, 2 },
-	{ ahd_patch0_func, 187, 1, 1 },
-	{ ahd_patch2_func, 190, 1, 2 },
-	{ ahd_patch0_func, 191, 1, 1 },
-	{ ahd_patch7_func, 193, 2, 1 },
-	{ ahd_patch5_func, 201, 16, 2 },
-	{ ahd_patch0_func, 217, 1, 1 },
-	{ ahd_patch8_func, 237, 2, 1 },
-	{ ahd_patch1_func, 241, 1, 2 },
-	{ ahd_patch0_func, 242, 1, 1 },
-	{ ahd_patch7_func, 245, 2, 1 },
-	{ ahd_patch1_func, 259, 1, 2 },
-	{ ahd_patch0_func, 260, 1, 1 },
-	{ ahd_patch1_func, 263, 1, 2 },
-	{ ahd_patch0_func, 264, 1, 1 },
-	{ ahd_patch2_func, 267, 1, 2 },
-	{ ahd_patch0_func, 268, 1, 1 },
-	{ ahd_patch1_func, 323, 1, 2 },
-	{ ahd_patch0_func, 324, 1, 1 },
-	{ ahd_patch2_func, 332, 1, 2 },
-	{ ahd_patch0_func, 333, 1, 1 },
-	{ ahd_patch2_func, 336, 1, 2 },
-	{ ahd_patch0_func, 337, 1, 1 },
-	{ ahd_patch1_func, 343, 1, 2 },
-	{ ahd_patch0_func, 344, 1, 1 },
-	{ ahd_patch1_func, 346, 1, 2 },
-	{ ahd_patch0_func, 347, 1, 1 },
-	{ ahd_patch9_func, 366, 1, 1 },
-	{ ahd_patch9_func, 369, 1, 1 },
-	{ ahd_patch9_func, 371, 1, 1 },
-	{ ahd_patch9_func, 383, 1, 1 },
-	{ ahd_patch1_func, 393, 1, 2 },
-	{ ahd_patch0_func, 394, 1, 1 },
-	{ ahd_patch1_func, 396, 1, 2 },
-	{ ahd_patch0_func, 397, 1, 1 },
-	{ ahd_patch1_func, 405, 1, 2 },
-	{ ahd_patch0_func, 406, 1, 1 },
-	{ ahd_patch2_func, 419, 1, 2 },
-	{ ahd_patch0_func, 420, 1, 1 },
-	{ ahd_patch10_func, 450, 1, 1 },
-	{ ahd_patch1_func, 457, 1, 2 },
-	{ ahd_patch0_func, 458, 1, 1 },
-	{ ahd_patch2_func, 470, 1, 2 },
-	{ ahd_patch0_func, 471, 1, 1 },
-	{ ahd_patch11_func, 476, 6, 2 },
-	{ ahd_patch0_func, 482, 1, 1 },
-	{ ahd_patch12_func, 505, 1, 1 },
-	{ ahd_patch13_func, 514, 1, 1 },
-	{ ahd_patch14_func, 515, 1, 2 },
-	{ ahd_patch0_func, 516, 1, 1 },
-	{ ahd_patch15_func, 519, 1, 1 },
-	{ ahd_patch14_func, 520, 1, 1 },
-	{ ahd_patch16_func, 531, 1, 2 },
-	{ ahd_patch0_func, 532, 1, 1 },
-	{ ahd_patch1_func, 551, 1, 2 },
-	{ ahd_patch0_func, 552, 1, 1 },
-	{ ahd_patch1_func, 555, 1, 2 },
-	{ ahd_patch0_func, 556, 1, 1 },
-	{ ahd_patch2_func, 561, 1, 2 },
-	{ ahd_patch0_func, 562, 1, 1 },
-	{ ahd_patch2_func, 566, 1, 2 },
-	{ ahd_patch0_func, 567, 1, 1 },
-	{ ahd_patch1_func, 568, 1, 2 },
-	{ ahd_patch0_func, 569, 1, 1 },
-	{ ahd_patch2_func, 580, 1, 2 },
-	{ ahd_patch0_func, 581, 1, 1 },
-	{ ahd_patch17_func, 585, 1, 1 },
-	{ ahd_patch18_func, 590, 1, 1 },
-	{ ahd_patch19_func, 591, 2, 1 },
-	{ ahd_patch18_func, 595, 1, 2 },
-	{ ahd_patch0_func, 596, 1, 1 },
-	{ ahd_patch2_func, 599, 1, 2 },
-	{ ahd_patch0_func, 600, 1, 1 },
-	{ ahd_patch2_func, 615, 1, 2 },
-	{ ahd_patch0_func, 616, 1, 1 },
-	{ ahd_patch20_func, 617, 14, 1 },
-	{ ahd_patch1_func, 635, 1, 2 },
-	{ ahd_patch0_func, 636, 1, 1 },
-	{ ahd_patch20_func, 637, 1, 1 },
-	{ ahd_patch1_func, 649, 1, 2 },
-	{ ahd_patch0_func, 650, 1, 1 },
-	{ ahd_patch1_func, 657, 1, 2 },
-	{ ahd_patch0_func, 658, 1, 1 },
-	{ ahd_patch17_func, 681, 1, 1 },
-	{ ahd_patch17_func, 719, 1, 1 },
-	{ ahd_patch1_func, 730, 1, 2 },
-	{ ahd_patch0_func, 731, 1, 1 },
-	{ ahd_patch1_func, 748, 1, 2 },
-	{ ahd_patch0_func, 749, 1, 1 },
-	{ ahd_patch1_func, 751, 1, 2 },
-	{ ahd_patch0_func, 752, 1, 1 },
-	{ ahd_patch1_func, 755, 1, 2 },
-	{ ahd_patch0_func, 756, 1, 1 },
-	{ ahd_patch21_func, 758, 1, 2 },
-	{ ahd_patch0_func, 759, 2, 1 },
-	{ ahd_patch22_func, 762, 4, 2 },
-	{ ahd_patch0_func, 766, 1, 1 },
-	{ ahd_patch22_func, 774, 11, 1 }
+	{ ahd_patch3_func, 36, 5, 1 },
+	{ ahd_patch2_func, 45, 1, 2 },
+	{ ahd_patch0_func, 46, 1, 1 },
+	{ ahd_patch1_func, 53, 1, 2 },
+	{ ahd_patch0_func, 54, 1, 1 },
+	{ ahd_patch2_func, 59, 1, 2 },
+	{ ahd_patch0_func, 60, 1, 1 },
+	{ ahd_patch2_func, 63, 1, 2 },
+	{ ahd_patch0_func, 64, 1, 1 },
+	{ ahd_patch2_func, 67, 1, 2 },
+	{ ahd_patch0_func, 68, 1, 1 },
+	{ ahd_patch4_func, 116, 1, 1 },
+	{ ahd_patch2_func, 175, 3, 1 },
+	{ ahd_patch1_func, 178, 2, 1 },
+	{ ahd_patch5_func, 180, 1, 1 },
+	{ ahd_patch2_func, 189, 1, 2 },
+	{ ahd_patch0_func, 190, 1, 1 },
+	{ ahd_patch6_func, 191, 2, 2 },
+	{ ahd_patch0_func, 193, 6, 3 },
+	{ ahd_patch2_func, 196, 1, 2 },
+	{ ahd_patch0_func, 197, 1, 1 },
+	{ ahd_patch2_func, 200, 1, 2 },
+	{ ahd_patch0_func, 201, 1, 1 },
+	{ ahd_patch3_func, 203, 1, 1 },
+	{ ahd_patch7_func, 204, 3, 1 },
+	{ ahd_patch3_func, 213, 1, 1 },
+	{ ahd_patch5_func, 214, 16, 2 },
+	{ ahd_patch0_func, 230, 1, 1 },
+	{ ahd_patch8_func, 250, 2, 1 },
+	{ ahd_patch1_func, 254, 1, 2 },
+	{ ahd_patch0_func, 255, 1, 1 },
+	{ ahd_patch7_func, 258, 3, 1 },
+	{ ahd_patch1_func, 273, 1, 2 },
+	{ ahd_patch0_func, 274, 1, 1 },
+	{ ahd_patch1_func, 277, 1, 2 },
+	{ ahd_patch0_func, 278, 1, 1 },
+	{ ahd_patch2_func, 281, 1, 2 },
+	{ ahd_patch0_func, 282, 1, 1 },
+	{ ahd_patch9_func, 295, 2, 2 },
+	{ ahd_patch0_func, 297, 1, 1 },
+	{ ahd_patch1_func, 339, 1, 2 },
+	{ ahd_patch0_func, 340, 1, 1 },
+	{ ahd_patch2_func, 348, 1, 2 },
+	{ ahd_patch0_func, 349, 1, 1 },
+	{ ahd_patch2_func, 352, 1, 2 },
+	{ ahd_patch0_func, 353, 1, 1 },
+	{ ahd_patch1_func, 359, 1, 2 },
+	{ ahd_patch0_func, 360, 1, 1 },
+	{ ahd_patch1_func, 362, 1, 2 },
+	{ ahd_patch0_func, 363, 1, 1 },
+	{ ahd_patch10_func, 382, 1, 1 },
+	{ ahd_patch10_func, 385, 1, 1 },
+	{ ahd_patch10_func, 387, 1, 1 },
+	{ ahd_patch10_func, 399, 1, 1 },
+	{ ahd_patch1_func, 409, 1, 2 },
+	{ ahd_patch0_func, 410, 1, 1 },
+	{ ahd_patch1_func, 412, 1, 2 },
+	{ ahd_patch0_func, 413, 1, 1 },
+	{ ahd_patch1_func, 421, 1, 2 },
+	{ ahd_patch0_func, 422, 1, 1 },
+	{ ahd_patch2_func, 435, 1, 2 },
+	{ ahd_patch0_func, 436, 1, 1 },
+	{ ahd_patch11_func, 472, 1, 1 },
+	{ ahd_patch1_func, 480, 1, 2 },
+	{ ahd_patch0_func, 481, 1, 1 },
+	{ ahd_patch2_func, 493, 1, 2 },
+	{ ahd_patch0_func, 494, 1, 1 },
+	{ ahd_patch12_func, 497, 6, 2 },
+	{ ahd_patch0_func, 503, 1, 1 },
+	{ ahd_patch13_func, 524, 7, 1 },
+	{ ahd_patch14_func, 533, 1, 1 },
+	{ ahd_patch15_func, 542, 1, 1 },
+	{ ahd_patch16_func, 543, 1, 2 },
+	{ ahd_patch0_func, 544, 1, 1 },
+	{ ahd_patch17_func, 547, 1, 1 },
+	{ ahd_patch16_func, 548, 1, 1 },
+	{ ahd_patch18_func, 559, 1, 2 },
+	{ ahd_patch0_func, 560, 1, 1 },
+	{ ahd_patch1_func, 579, 1, 2 },
+	{ ahd_patch0_func, 580, 1, 1 },
+	{ ahd_patch1_func, 583, 1, 2 },
+	{ ahd_patch0_func, 584, 1, 1 },
+	{ ahd_patch2_func, 589, 1, 2 },
+	{ ahd_patch0_func, 590, 1, 1 },
+	{ ahd_patch2_func, 594, 1, 2 },
+	{ ahd_patch0_func, 595, 1, 1 },
+	{ ahd_patch1_func, 596, 1, 2 },
+	{ ahd_patch0_func, 597, 1, 1 },
+	{ ahd_patch2_func, 608, 1, 2 },
+	{ ahd_patch0_func, 609, 1, 1 },
+	{ ahd_patch19_func, 613, 1, 1 },
+	{ ahd_patch20_func, 618, 1, 1 },
+	{ ahd_patch21_func, 619, 2, 1 },
+	{ ahd_patch20_func, 623, 1, 2 },
+	{ ahd_patch0_func, 624, 1, 1 },
+	{ ahd_patch2_func, 627, 1, 2 },
+	{ ahd_patch0_func, 628, 1, 1 },
+	{ ahd_patch2_func, 643, 1, 2 },
+	{ ahd_patch0_func, 644, 1, 1 },
+	{ ahd_patch13_func, 645, 14, 1 },
+	{ ahd_patch1_func, 663, 1, 2 },
+	{ ahd_patch0_func, 664, 1, 1 },
+	{ ahd_patch13_func, 665, 1, 1 },
+	{ ahd_patch1_func, 677, 1, 2 },
+	{ ahd_patch0_func, 678, 1, 1 },
+	{ ahd_patch1_func, 685, 1, 2 },
+	{ ahd_patch0_func, 686, 1, 1 },
+	{ ahd_patch19_func, 709, 1, 1 },
+	{ ahd_patch19_func, 747, 1, 1 },
+	{ ahd_patch1_func, 758, 1, 2 },
+	{ ahd_patch0_func, 759, 1, 1 },
+	{ ahd_patch1_func, 776, 1, 2 },
+	{ ahd_patch0_func, 777, 1, 1 },
+	{ ahd_patch1_func, 779, 1, 2 },
+	{ ahd_patch0_func, 780, 1, 1 },
+	{ ahd_patch1_func, 783, 1, 2 },
+	{ ahd_patch0_func, 784, 1, 1 },
+	{ ahd_patch22_func, 786, 1, 2 },
+	{ ahd_patch0_func, 787, 2, 1 },
+	{ ahd_patch23_func, 790, 4, 2 },
+	{ ahd_patch0_func, 794, 1, 1 },
+	{ ahd_patch23_func, 802, 11, 1 }
 };
 
 static struct cs {
 	uint16_t	begin;
 	uint16_t	end;
 } critical_sections[] = {
-	{ 11, 12 },
-	{ 13, 14 },
-	{ 29, 42 },
-	{ 56, 59 },
-	{ 101, 128 },
-	{ 129, 157 },
-	{ 159, 162 },
-	{ 170, 178 },
-	{ 201, 250 },
-	{ 681, 697 },
-	{ 697, 711 },
-	{ 721, 725 }
+	{ 17, 28 },
+	{ 29, 30 },
+	{ 47, 58 },
+	{ 61, 63 },
+	{ 65, 66 },
+	{ 72, 92 },
+	{ 110, 137 },
+	{ 138, 175 },
+	{ 180, 188 },
+	{ 213, 264 },
+	{ 425, 433 },
+	{ 443, 445 },
+	{ 448, 457 },
+	{ 709, 739 },
+	{ 749, 753 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index fd389e9..051970e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -375,7 +375,7 @@
 					 struct scsi_cmnd *cmd);
 static void ahc_linux_sem_timeout(u_long arg);
 static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
-static void ahc_linux_release_simq(u_long arg);
+static void ahc_linux_release_simq(struct ahc_softc *ahc);
 static int  ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
 static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
@@ -1073,7 +1073,6 @@
 		return (ENOMEM);
 
 	*((struct ahc_softc **)host->hostdata) = ahc;
-	ahc_lock(ahc, &s);
 	ahc->platform_data->host = host;
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
@@ -1084,7 +1083,9 @@
 	host->max_lun = AHC_NUM_LUNS;
 	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
 	host->sg_tablesize = AHC_NSEG;
+	ahc_lock(ahc, &s);
 	ahc_set_unit(ahc, ahc_linux_unit++);
+	ahc_unlock(ahc, &s);
 	sprintf(buf, "scsi%d", host->host_no);
 	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
 	if (new_name != NULL) {
@@ -1094,7 +1095,6 @@
 	host->unique_id = ahc->unit;
 	ahc_linux_initialize_scsi_bus(ahc);
 	ahc_intr_enable(ahc, TRUE);
-	ahc_unlock(ahc, &s);
 
 	host->transportt = ahc_linux_transport_template;
 
@@ -1120,10 +1120,13 @@
 {
 	int i;
 	int numtarg;
+	unsigned long s;
 
 	i = 0;
 	numtarg = 0;
 
+	ahc_lock(ahc, &s);
+
 	if (aic7xxx_no_reset != 0)
 		ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B);
 
@@ -1170,16 +1173,12 @@
 		ahc_update_neg_request(ahc, &devinfo, tstate,
 				       tinfo, AHC_NEG_ALWAYS);
 	}
+	ahc_unlock(ahc, &s);
 	/* Give the bus some time to recover */
 	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
 		ahc_linux_freeze_simq(ahc);
-		init_timer(&ahc->platform_data->reset_timer);
-		ahc->platform_data->reset_timer.data = (u_long)ahc;
-		ahc->platform_data->reset_timer.expires =
-		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
-		ahc->platform_data->reset_timer.function =
-		    ahc_linux_release_simq;
-		add_timer(&ahc->platform_data->reset_timer);
+		msleep(AIC7XXX_RESET_DELAY);
+		ahc_linux_release_simq(ahc);
 	}
 }
 
@@ -2059,6 +2058,9 @@
 static void
 ahc_linux_freeze_simq(struct ahc_softc *ahc)
 {
+	unsigned long s;
+
+	ahc_lock(ahc, &s);
 	ahc->platform_data->qfrozen++;
 	if (ahc->platform_data->qfrozen == 1) {
 		scsi_block_requests(ahc->platform_data->host);
@@ -2068,17 +2070,15 @@
 					CAM_LUN_WILDCARD, SCB_LIST_NULL,
 					ROLE_INITIATOR, CAM_REQUEUE_REQ);
 	}
+	ahc_unlock(ahc, &s);
 }
 
 static void
-ahc_linux_release_simq(u_long arg)
+ahc_linux_release_simq(struct ahc_softc *ahc)
 {
-	struct ahc_softc *ahc;
 	u_long s;
 	int    unblock_reqs;
 
-	ahc = (struct ahc_softc *)arg;
-
 	unblock_reqs = 0;
 	ahc_lock(ahc, &s);
 	if (ahc->platform_data->qfrozen > 0)
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index f2a9544..e0edaca 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -223,9 +223,6 @@
  */
 #define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op)
 
-/************************** Timer DataStructures ******************************/
-typedef struct timer_list ahc_timer_t;
-
 /********************************** Includes **********************************/
 #ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT
 #define AIC_DEBUG_REGISTERS 1
@@ -235,30 +232,9 @@
 #include "aic7xxx.h"
 
 /***************************** Timer Facilities *******************************/
-#define ahc_timer_init init_timer
-#define ahc_timer_stop del_timer_sync
-typedef void ahc_linux_callback_t (u_long);  
-static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec,
-				     ahc_callback_t *func, void *arg);
-static __inline void ahc_scb_timer_reset(struct scb *scb, u_int usec);
-
-static __inline void
-ahc_timer_reset(ahc_timer_t *timer, int usec, ahc_callback_t *func, void *arg)
-{
-	struct ahc_softc *ahc;
-
-	ahc = (struct ahc_softc *)arg;
-	del_timer(timer);
-	timer->data = (u_long)arg;
-	timer->expires = jiffies + (usec * HZ)/1000000;
-	timer->function = (ahc_linux_callback_t*)func;
-	add_timer(timer);
-}
-
 static __inline void
 ahc_scb_timer_reset(struct scb *scb, u_int usec)
 {
-	mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000);
 }
 
 /***************************** SMP support ************************************/
@@ -393,7 +369,6 @@
 
 	spinlock_t		 spin_lock;
 	u_int			 qfrozen;
-	struct timer_list	 reset_timer;
 	struct semaphore	 eh_sem;
 	struct Scsi_Host        *host;		/* pointer to scsi host */
 #define AHC_LINUX_NOIRQ	((uint32_t)~0)
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index b3b2e22..5f58614 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -39,9 +39,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#69 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#79 $
  */
 
 #ifdef __linux__
@@ -393,6 +391,12 @@
 		"Adaptec aic7892 Ultra160 SCSI adapter (ARO)",
 		ahc_aic7892_setup
 	},
+	{
+		ID_AHA_2915_30LP,
+		ID_ALL_MASK,
+		"Adaptec 2915/30LP Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
 	/* aic7895 based controllers */	
 	{
 		ID_AHA_2940U_DUAL,
@@ -1193,9 +1197,19 @@
 	 * use for this test.
 	 */
 	hcntrl = ahc_inb(ahc, HCNTRL);
+
 	if (hcntrl == 0xFF)
 		goto fail;
 
+	if ((hcntrl & CHIPRST) != 0) {
+		/*
+		 * The chip has not been initialized since
+		 * PCI/EISA/VLB bus reset.  Don't trust
+		 * "left over BIOS data".
+		 */
+		ahc->flags |= AHC_NO_BIOS_INIT;
+	}
+
 	/*
 	 * Next create a situation where write combining
 	 * or read prefetching could be initiated by the
@@ -1307,6 +1321,10 @@
 			sd.sd_chip = C56_66;
 		}
 		ahc_release_seeprom(&sd);
+
+		/* Remember the SEEPROM type for later */
+		if (sd.sd_chip == C56_66)
+			ahc->flags |= AHC_LARGE_SEEPROM;
 	}
 
 	if (!have_seeprom) {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.h b/drivers/scsi/aic7xxx/aic7xxx_pci.h
index be27fcb..263f85d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.h
@@ -105,6 +105,7 @@
 #define ID_AHA_29160C			0x0080900562209005ull
 #define ID_AHA_29160B			0x00809005E2209005ull
 #define ID_AHA_19160B			0x0081900562A19005ull
+#define ID_AHA_2915_30LP		0x0082900502109005ull
 
 #define ID_AIC7896			0x005F9005FFFF9005ull
 #define ID_AIC7896_ARO			0x00539005FFFF9005ull
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 33d56c3..770f164 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -1290,7 +1290,7 @@
  *
  ***************************************************************************/
 
-static inline unsigned char
+static unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
 #ifdef MMAPIO
@@ -1309,7 +1309,7 @@
 #endif
 }
 
-static inline void
+static void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
 #ifdef MMAPIO
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 4299fab..c3f2728 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -22,6 +22,7 @@
 #include <linux/completion.h>
 #include <linux/compat.h>
 #include <linux/chio.h>			/* here are all the ioctls */
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -111,7 +112,7 @@
 	u_int               counts[CH_TYPES];
 	u_int               unit_attention;
 	u_int		    voltags;
-	struct semaphore    lock;
+	struct mutex	    lock;
 } scsi_changer;
 
 static LIST_HEAD(ch_devlist);
@@ -565,7 +566,7 @@
 	u_char data[16];
 	unsigned int i;
 	
-	down(&ch->lock);
+	mutex_lock(&ch->lock);
 	for (i = 0; i < ch->counts[type]; i++) {
 		if (0 != ch_read_element_status
 		    (ch, ch->firsts[type]+i,data)) {
@@ -582,7 +583,7 @@
 		if (0 != retval)
 			break;
 	}
-	up(&ch->lock);
+	mutex_unlock(&ch->lock);
 	return retval;
 }
 
@@ -687,11 +688,11 @@
 			dprintk("CHIOPOSITION: invalid parameter\n");
 			return -EBADSLT;
 		}
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		retval = ch_position(ch,0,
 				     ch->firsts[pos.cp_type] + pos.cp_unit,
 				     pos.cp_flags & CP_INVERT);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		return retval;
 	}
 	
@@ -708,12 +709,12 @@
 			return -EBADSLT;
 		}
 		
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		retval = ch_move(ch,0,
 				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
 				 ch->firsts[mv.cm_totype]   + mv.cm_tounit,
 				 mv.cm_flags & CM_INVERT);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		return retval;
 	}
 
@@ -731,14 +732,14 @@
 			return -EBADSLT;
 		}
 		
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		retval = ch_exchange
 			(ch,0,
 			 ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
 			 ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
 			 ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
 			 mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		return retval;
 	}
 
@@ -772,7 +773,7 @@
 		buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 		if (!buffer)
 			return -ENOMEM;
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		
 	voltag_retry:
 		memset(cmd,0,sizeof(cmd));
@@ -823,7 +824,7 @@
 			goto voltag_retry;
 		}
 		kfree(buffer);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		
 		if (copy_to_user(argp, &cge, sizeof (cge)))
 			return -EFAULT;
@@ -832,9 +833,9 @@
 
 	case CHIOINITELEM:
 	{
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		retval = ch_init_elem(ch);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		return retval;
 	}
 		
@@ -851,12 +852,12 @@
 			return -EBADSLT;
 		}
 		elem = ch->firsts[csv.csv_type] + csv.csv_unit;
-		down(&ch->lock);
+		mutex_lock(&ch->lock);
 		retval = ch_set_voltag(ch, elem,
 				       csv.csv_flags & CSV_AVOLTAG,
 				       csv.csv_flags & CSV_CLEARTAG,
 				       csv.csv_voltag);
-		up(&ch->lock);
+		mutex_unlock(&ch->lock);
 		return retval;
 	}
 
@@ -929,7 +930,7 @@
 	memset(ch,0,sizeof(*ch));
 	ch->minor = ch_devcount;
 	sprintf(ch->name,"ch%d",ch->minor);
-	init_MUTEX(&ch->lock);
+	mutex_init(&ch->lock);
 	ch->device = sd;
 	ch_readconfig(ch);
 	if (init)
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 6252b9d..6e6b293 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -61,6 +61,7 @@
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/mutex.h>
 
 #include <asm/processor.h>	/* for boot_cpu_data */
 #include <asm/pgtable.h>
@@ -106,7 +107,7 @@
  *============================================================================
  */
 
-static DECLARE_MUTEX(adpt_configuration_lock);
+static DEFINE_MUTEX(adpt_configuration_lock);
 
 static struct i2o_sys_tbl *sys_tbl = NULL;
 static int sys_tbl_ind = 0;
@@ -537,13 +538,13 @@
 	 */
 
 	// Find HBA (host bus adapter) we are looking for
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
 		if (pHba->host == host) {
 			break;	/* found adapter */
 		}
 	}
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 	if (pHba == NULL) {
 		return 0;
 	}
@@ -898,6 +899,12 @@
 	if(pci_enable_device(pDev)) {
 		return -EINVAL;
 	}
+
+	if (pci_request_regions(pDev, "dpt_i2o")) {
+		PERROR("dpti: adpt_config_hba: pci request region failed\n");
+		return -EINVAL;
+	}
+
 	pci_set_master(pDev);
 	if (pci_set_dma_mask(pDev, 0xffffffffffffffffULL) &&
 	    pci_set_dma_mask(pDev, 0xffffffffULL))
@@ -923,10 +930,6 @@
 		raptorFlag = TRUE;
 	}
 
-	if (pci_request_regions(pDev, "dpt_i2o")) {
-		PERROR("dpti: adpt_config_hba: pci request region failed\n");
-		return -EINVAL;
-	}
 	base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
 	if (!base_addr_virt) {
 		pci_release_regions(pDev);
@@ -958,7 +961,7 @@
 	}
 	memset(pHba, 0, sizeof(adpt_hba));
 
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 
 	if(hba_chain != NULL){
 		for(p = hba_chain; p->next; p = p->next);
@@ -971,7 +974,7 @@
 	sprintf(pHba->name, "dpti%d", hba_count);
 	hba_count++;
 	
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 
 	pHba->pDev = pDev;
 	pHba->base_addr_phys = base_addr0_phys;
@@ -1027,7 +1030,7 @@
 	struct adpt_device* pNext;
 
 
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	// scsi_unregister calls our adpt_release which
 	// does a quiese
 	if(pHba->host){
@@ -1046,7 +1049,7 @@
 	}
 
 	hba_count--;
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 
 	iounmap(pHba->base_addr_virt);
 	pci_release_regions(pHba->pDev);
@@ -1549,7 +1552,7 @@
  
 static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d)
 {
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	d->controller=pHba;
 	d->owner=NULL;
 	d->next=pHba->devices;
@@ -1560,7 +1563,7 @@
 	pHba->devices=d;
 	*d->dev_name = 0;
 
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 	return 0;
 }
 
@@ -1575,24 +1578,24 @@
 	if (minor >= hba_count) {
 		return -ENXIO;
 	}
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
 		if (pHba->unit == minor) {
 			break;	/* found adapter */
 		}
 	}
 	if (pHba == NULL) {
-		up(&adpt_configuration_lock);
+		mutex_unlock(&adpt_configuration_lock);
 		return -ENXIO;
 	}
 
 //	if(pHba->in_use){
-	//	up(&adpt_configuration_lock);
+	//	mutex_unlock(&adpt_configuration_lock);
 //		return -EBUSY;
 //	}
 
 	pHba->in_use = 1;
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 
 	return 0;
 }
@@ -1606,13 +1609,13 @@
 	if (minor >= hba_count) {
 		return -ENXIO;
 	}
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
 		if (pHba->unit == minor) {
 			break;	/* found adapter */
 		}
 	}
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 	if (pHba == NULL) {
 		return -ENXIO;
 	}
@@ -1910,13 +1913,13 @@
 	if (minor >= DPTI_MAX_HBA){
 		return -ENXIO;
 	}
-	down(&adpt_configuration_lock);
+	mutex_lock(&adpt_configuration_lock);
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
 		if (pHba->unit == minor) {
 			break;	/* found adapter */
 		}
 	}
-	up(&adpt_configuration_lock);
+	mutex_unlock(&adpt_configuration_lock);
 	if(pHba == NULL){
 		return -ENXIO;
 	}
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 66783c8..5881079 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -156,16 +156,16 @@
 void scsi_remove_host(struct Scsi_Host *shost)
 {
 	unsigned long flags;
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	spin_lock_irqsave(shost->host_lock, flags);
 	if (scsi_host_set_state(shost, SHOST_CANCEL))
 		if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
 			spin_unlock_irqrestore(shost->host_lock, flags);
-			up(&shost->scan_mutex);
+			mutex_unlock(&shost->scan_mutex);
 			return;
 		}
 	spin_unlock_irqrestore(shost->host_lock, flags);
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 	scsi_forget_host(shost);
 	scsi_proc_host_rm(shost);
 
@@ -320,7 +320,7 @@
 	INIT_LIST_HEAD(&shost->starved_list);
 	init_waitqueue_head(&shost->host_wait);
 
-	init_MUTEX(&shost->scan_mutex);
+	mutex_init(&shost->scan_mutex);
 
 	shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
 	shost->dma_channel = 0xff;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 3882d48..e5e1ca4 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1319,6 +1319,9 @@
 			min = ha->max_cmds - 1;
 		scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
 	}
+
+	SDptr->skip_ms_page_8 = 1;
+	SDptr->skip_ms_page_3f = 1;
 	return 0;
 }
 #endif
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 10bcf42..780bfcc 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/kfifo.h>
 #include <linux/scatterlist.h>
+#include <linux/mutex.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -86,35 +87,32 @@
 {
 	sg_init_one(&ibuf->sg, (u8 *)vbuf, size);
 	ibuf->sent = 0;
+	ibuf->use_sendmsg = 0;
 }
 
 static inline void
 iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
 {
-	ibuf->sg.page = (void*)vbuf;
-	ibuf->sg.offset = (unsigned int)-1;
+	ibuf->sg.page = virt_to_page(vbuf);
+	ibuf->sg.offset = offset_in_page(vbuf);
 	ibuf->sg.length = size;
 	ibuf->sent = 0;
-}
-
-static inline void*
-iscsi_buf_iov_base(struct iscsi_buf *ibuf)
-{
-	return (char*)ibuf->sg.page + ibuf->sent;
+	ibuf->use_sendmsg = 1;
 }
 
 static inline void
 iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
 {
+	ibuf->sg.page = sg->page;
+	ibuf->sg.offset = sg->offset;
+	ibuf->sg.length = sg->length;
 	/*
 	 * Fastpath: sg element fits into single page
 	 */
-	if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) {
-		ibuf->sg.page = sg->page;
-		ibuf->sg.offset = sg->offset;
-		ibuf->sg.length = sg->length;
-	} else
-		iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length);
+	if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page))
+		ibuf->use_sendmsg = 0;
+	else
+		ibuf->use_sendmsg = 1;
 	ibuf->sent = 0;
 }
 
@@ -356,7 +354,7 @@
 		struct scsi_cmnd *sc = ctask->sc;
 
 		conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-		if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+		if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
 			int res_count = be32_to_cpu(rhdr->residual_count);
 
 			if (res_count > 0 &&
@@ -366,9 +364,7 @@
 			} else
 				sc->result = (DID_BAD_TARGET << 16) |
 					rhdr->cmd_status;
-		} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
-			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-		else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) {
+		} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
 			sc->resid = be32_to_cpu(rhdr->residual_count);
 			sc->result = (DID_OK << 16) | rhdr->cmd_status;
 		} else
@@ -529,7 +525,7 @@
 	__kfifo_put(ctask->r2tqueue, (void*)&r2t, sizeof(void*));
 	__kfifo_put(conn->writequeue, (void*)&ctask, sizeof(void*));
 
-	schedule_work(&conn->xmitwork);
+	scsi_queue_work(session->host, &conn->xmitwork);
 	conn->r2t_pdus_cnt++;
 	spin_unlock(&session->lock);
 
@@ -686,7 +682,7 @@
 		switch(conn->in.opcode) {
 		case ISCSI_OP_LOGIN_RSP:
 		case ISCSI_OP_TEXT_RSP:
-		case ISCSI_OP_LOGOUT_RSP: 
+		case ISCSI_OP_LOGOUT_RSP:
 			rc = iscsi_check_assign_cmdsn(session,
 						 (struct iscsi_nopin*)hdr);
 			if (rc)
@@ -727,12 +723,12 @@
 			}
 			spin_unlock(&session->lock);
 			break;
-		case ISCSI_OP_NOOP_IN: 
+		case ISCSI_OP_NOOP_IN:
 			if (hdr->ttt != ISCSI_RESERVED_TAG) {
 				rc = ISCSI_ERR_PROTO;
 				break;
 			}
-			rc = iscsi_check_assign_cmdsn(session, 
+			rc = iscsi_check_assign_cmdsn(session,
 						(struct iscsi_nopin*)hdr);
 			if (rc)
 				break;
@@ -767,7 +763,7 @@
 				if (!rc && hdr->ttt != ISCSI_RESERVED_TAG)
 					rc = iscsi_recv_pdu(iscsi_handle(conn),
 							    hdr, NULL, 0);
-			} else 
+			} else
 				rc = ISCSI_ERR_PROTO;
 			break;
 		case ISCSI_OP_REJECT:
@@ -929,7 +925,7 @@
 				      sc->request_bufflen, ctask->data_offset);
 		if (rc == -EAGAIN)
 			return rc;
-		if (conn->datadgst_en) 
+		if (conn->datadgst_en)
 			iscsi_recv_digest_update(conn, sc->request_buffer, i);
 		rc = 0;
 		goto done;
@@ -1024,7 +1020,7 @@
 		conn->in.hdr = &conn->hdr;
 		conn->senselen = (conn->data[0] << 8) | conn->data[1];
 		rc = iscsi_cmd_rsp(conn, conn->in.ctask);
-		if (!rc && conn->datadgst_en) 
+		if (!rc && conn->datadgst_en)
 			iscsi_recv_digest_update(conn, conn->data,
 						 conn->in.datalen);
 	}
@@ -1051,7 +1047,7 @@
 		rc = iscsi_recv_pdu(iscsi_handle(conn), conn->in.hdr,
 				    conn->data, conn->in.datalen);
 
-		if (!rc && conn->datadgst_en && 
+		if (!rc && conn->datadgst_en &&
 			conn->in.opcode != ISCSI_OP_LOGIN_RSP)
 			iscsi_recv_digest_update(conn, conn->data,
 			  			conn->in.datalen);
@@ -1271,7 +1267,7 @@
 	conn->old_write_space(sk);
 	debug_tcp("iscsi_write_space: cid %d\n", conn->id);
 	clear_bit(SUSPEND_BIT, &conn->suspend_tx);
-	schedule_work(&conn->xmitwork);
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
 static void
@@ -1312,35 +1308,25 @@
  * @buf: buffer to write from
  * @size: actual size to write
  * @flags: socket's flags
- *
- * Notes:
- *	depending on buffer will use tcp_sendpage() or tcp_sendmsg().
- *	buf->sg.offset == -1 tells us that buffer is non S/G and forces
- *	to use tcp_sendmsg().
  */
 static inline int
-iscsi_send(struct socket *sk, struct iscsi_buf *buf, int size, int flags)
+iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
 {
-	int res;
+	struct socket *sk = conn->sock;
+	int offset = buf->sg.offset + buf->sent;
 
-	if ((int)buf->sg.offset >= 0) {
-		int offset = buf->sg.offset + buf->sent;
-
-		/* tcp_sendpage */
-		res = sk->ops->sendpage(sk, buf->sg.page, offset, size, flags);
-	} else {
-		struct msghdr msg;
-
-		buf->iov.iov_base = iscsi_buf_iov_base(buf);
-		buf->iov.iov_len = size;
-
-		memset(&msg, 0, sizeof(struct msghdr));
-
-		/* tcp_sendmsg */
-		res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size);
-	}
-
-	return res;
+	/*
+	 * if we got use_sg=0 or are sending something we kmallocd
+	 * then we did not have to do kmap (kmap returns page_address)
+	 *
+	 * if we got use_sg > 0, but had to drop down, we do not
+	 * set clustering so this should only happen for that
+	 * slab case.
+	 */
+	if (buf->use_sendmsg)
+		return sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+	else
+		return conn->sendpage(sk, buf->sg.page, offset, size, flags);
 }
 
 /**
@@ -1355,7 +1341,6 @@
 static inline int
 iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
 {
-	struct socket *sk = conn->sock;
 	int flags = 0; /* MSG_DONTWAIT; */
 	int res, size;
 
@@ -1364,7 +1349,7 @@
 	if (buf->sent + size != buf->sg.length || datalen)
 		flags |= MSG_MORE;
 
-	res = iscsi_send(sk, buf, size, flags);
+	res = iscsi_send(conn, buf, size, flags);
 	debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
 	if (res >= 0) {
 		conn->txdata_octets += res;
@@ -1395,7 +1380,6 @@
 iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
 	       int *count, int *sent)
 {
-	struct socket *sk = conn->sock;
 	int flags = 0; /* MSG_DONTWAIT; */
 	int res, size;
 
@@ -1406,7 +1390,7 @@
 	if (buf->sent + size != buf->sg.length || *count != size)
 		flags |= MSG_MORE;
 
-	res = iscsi_send(sk, buf, size, flags);
+	res = iscsi_send(conn, buf, size, flags);
 	debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
 		  size, buf->sent, *count, *sent, res);
 	if (res >= 0) {
@@ -1434,20 +1418,7 @@
 	ctask->digest_count = 4;
 }
 
-static inline void
-iscsi_buf_data_digest_update(struct iscsi_conn *conn, struct iscsi_buf *buf)
-{
-	struct scatterlist sg;
-
-	if (buf->sg.offset != -1)
-		crypto_digest_update(conn->data_tx_tfm, &buf->sg, 1);
-	else {
-		sg_init_one(&sg, (char *)buf->sg.page, buf->sg.length);
-		crypto_digest_update(conn->data_tx_tfm, &sg, 1);
-	}
-}
-
-static inline int
+static int
 iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 			struct iscsi_buf *buf, uint32_t *digest, int final)
 {
@@ -1680,7 +1651,7 @@
 		zero_data(ctask->hdr.dlength);
 	}
 
-	iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr, 
+	iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr,
 			    sizeof(struct iscsi_hdr));
 	conn->scsicmd_pdus_cnt++;
 }
@@ -1746,7 +1717,7 @@
 handle_xmstate_r_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
 	ctask->xmstate &= ~XMSTATE_R_HDR;
-	if (conn->hdrdgst_en) 
+	if (conn->hdrdgst_en)
 		iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext);
 	if (!iscsi_sendhdr(conn, &ctask->headbuf, 0)) {
 		BUG_ON(ctask->xmstate != XMSTATE_IDLE);
@@ -1760,7 +1731,7 @@
 handle_xmstate_w_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
 	ctask->xmstate &= ~XMSTATE_W_HDR;
-	if (conn->hdrdgst_en) 
+	if (conn->hdrdgst_en)
 		iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext);
 	if (iscsi_sendhdr(conn, &ctask->headbuf, ctask->imm_count)) {
 		ctask->xmstate |= XMSTATE_W_HDR;
@@ -1809,7 +1780,8 @@
 			return -EAGAIN;
 		}
 		if (conn->datadgst_en)
-			iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+			crypto_digest_update(conn->data_tx_tfm,
+					     &ctask->sendbuf.sg, 1);
 
 		if (!ctask->imm_count)
 			break;
@@ -1894,7 +1866,8 @@
 		 * so pass it
 		 */
 		if (conn->datadgst_en && ctask->sent - start > 0)
-			iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+			crypto_digest_update(conn->data_tx_tfm,
+					     &ctask->sendbuf.sg, 1);
 
 		if (!ctask->data_count)
 			break;
@@ -1972,7 +1945,7 @@
 
 	BUG_ON(r2t->data_count < 0);
 	if (conn->datadgst_en)
-		iscsi_buf_data_digest_update(conn, &r2t->sendbuf);
+		crypto_digest_update(conn->data_tx_tfm, &r2t->sendbuf.sg, 1);
 
 	if (r2t->data_count) {
 		BUG_ON(ctask->sc->use_sg == 0);
@@ -2054,7 +2027,7 @@
 	}
 
 	if (conn->datadgst_en) {
-		iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+		crypto_digest_update(conn->data_tx_tfm, &ctask->sendbuf.sg, 1);
 		/* imm data? */
 		if (!dtask) {
 			if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf,
@@ -2148,7 +2121,7 @@
 solicit_head_again:
 		r2t = ctask->r2t;
 		if (conn->hdrdgst_en)
-			iscsi_hdr_digest(conn, &r2t->headbuf, 
+			iscsi_hdr_digest(conn, &r2t->headbuf,
 					(u8*)r2t->dtask->hdrext);
 		if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) {
 			ctask->xmstate &= ~XMSTATE_SOL_DATA;
@@ -2300,10 +2273,10 @@
 	/*
 	 * serialize Xmit worker on a per-connection basis.
 	 */
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 	if (iscsi_data_xmit(conn))
-		schedule_work(&conn->xmitwork);
-	up(&conn->xmitsema);
+		scsi_queue_work(conn->session->host, &conn->xmitwork);
+	mutex_unlock(&conn->xmitmutex);
 }
 
 #define FAILURE_BAD_HOST		1
@@ -2367,15 +2340,7 @@
 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
 	spin_unlock(&session->lock);
 
-        if (!in_interrupt() && !down_trylock(&conn->xmitsema)) {
-		spin_unlock_irq(host->host_lock);
-		if (iscsi_data_xmit(conn))
-			schedule_work(&conn->xmitwork);
-		up(&conn->xmitsema);
-		spin_lock_irq(host->host_lock);
-	} else
-		schedule_work(&conn->xmitwork);
-
+	scsi_queue_work(host, &conn->xmitwork);
 	return 0;
 
 reject:
@@ -2462,17 +2427,20 @@
 	kfree(items);
 }
 
-static iscsi_connh_t
-iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
+static struct iscsi_cls_conn *
+iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx)
 {
-	struct iscsi_session *session = iscsi_ptr(sessionh);
-	struct iscsi_conn *conn = NULL;
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+	struct iscsi_conn *conn;
+	struct iscsi_cls_conn *cls_conn;
 
-	conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
-	if (conn == NULL)
-		goto conn_alloc_fail;
+	cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata),
+				     conn_idx);
+	if (!cls_conn)
+		return NULL;
+	conn = cls_conn->dd_data;
+
 	memset(conn, 0, sizeof(struct iscsi_conn));
-
 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
 	conn->in_progress = IN_PROGRESS_WAIT_HEADER;
 	conn->id = conn_idx;
@@ -2531,10 +2499,10 @@
 		goto max_recv_dlenght_alloc_fail;
 
 	init_timer(&conn->tmabort_timer);
-	init_MUTEX(&conn->xmitsema);
+	mutex_init(&conn->xmitmutex);
 	init_waitqueue_head(&conn->ehwait);
 
-	return iscsi_handle(conn);
+	return cls_conn;
 
 max_recv_dlenght_alloc_fail:
 	spin_lock_bh(&session->lock);
@@ -2550,18 +2518,18 @@
 writequeue_alloc_fail:
 	kfifo_free(conn->xmitqueue);
 xmitqueue_alloc_fail:
-	kfree(conn);
-conn_alloc_fail:
-	return iscsi_handle(NULL);
+	iscsi_destroy_conn(cls_conn);
+	return NULL;
 }
 
 static void
-iscsi_conn_destroy(iscsi_connh_t connh)
+iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn)
 {
-	struct iscsi_conn *conn = iscsi_ptr(connh);
+	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iscsi_session *session = conn->session;
+	unsigned long flags;
 
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 	set_bit(SUSPEND_BIT, &conn->suspend_tx);
 	if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE && conn->sock) {
 		struct sock *sk = conn->sock->sk;
@@ -2592,19 +2560,19 @@
 	}
 	spin_unlock_bh(&session->lock);
 
-	up(&conn->xmitsema);
+	mutex_unlock(&conn->xmitmutex);
 
 	/*
 	 * Block until all in-progress commands for this connection
 	 * time out or fail.
 	 */
 	for (;;) {
-		spin_lock_bh(&conn->lock);
+		spin_lock_irqsave(session->host->host_lock, flags);
 		if (!session->host->host_busy) { /* OK for ERL == 0 */
-			spin_unlock_bh(&conn->lock);
+			spin_unlock_irqrestore(session->host->host_lock, flags);
 			break;
 		}
-		spin_unlock_bh(&conn->lock);
+		spin_unlock_irqrestore(session->host->host_lock, flags);
 		msleep_interruptible(500);
 		printk("conn_destroy(): host_busy %d host_failed %d\n",
 			session->host->host_busy, session->host->host_failed);
@@ -2652,7 +2620,8 @@
 	kfifo_free(conn->writequeue);
 	kfifo_free(conn->immqueue);
 	kfifo_free(conn->mgmtqueue);
-	kfree(conn);
+
+	iscsi_destroy_conn(cls_conn);
 }
 
 static int
@@ -2713,6 +2682,8 @@
 		 */
 		iscsi_conn_set_callbacks(conn);
 
+		conn->sendpage = conn->sock->ops->sendpage;
+
 		/*
 		 * set receive state machine into initial state
 		 */
@@ -2796,7 +2767,7 @@
 	set_bit(SUSPEND_BIT, &conn->suspend_rx);
 	write_unlock_bh(&sk->sk_callback_lock);
 
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 
 	spin_lock_irqsave(session->host->host_lock, flags);
 	spin_lock(&session->lock);
@@ -2878,7 +2849,7 @@
 			conn->datadgst_en = 0;
 		}
 	}
-	up(&conn->xmitsema);
+	mutex_unlock(&conn->xmitmutex);
 }
 
 static int
@@ -2963,8 +2934,7 @@
 	else
 	        __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
 
-	schedule_work(&conn->xmitwork);
-
+	scsi_queue_work(session->host, &conn->xmitwork);
 	return 0;
 }
 
@@ -3029,12 +2999,12 @@
 	 * 1) connection-level failure;
 	 * 2) recovery due protocol error;
 	 */
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 	spin_lock_bh(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		if (session->state == ISCSI_STATE_TERMINATE) {
 			spin_unlock_bh(&session->lock);
-			up(&conn->xmitsema);
+			mutex_unlock(&conn->xmitmutex);
 			goto failed;
 		}
 		spin_unlock_bh(&session->lock);
@@ -3052,7 +3022,7 @@
 			 * 2) session was re-open during time out of ctask.
 			 */
 			spin_unlock_bh(&session->lock);
-			up(&conn->xmitsema);
+			mutex_unlock(&conn->xmitmutex);
 			goto success;
 		}
 		conn->tmabort_state = TMABORT_INITIAL;
@@ -3107,7 +3077,7 @@
 				    conn->tmabort_state == TMABORT_SUCCESS) {
 					conn->tmabort_state = TMABORT_INITIAL;
 					spin_unlock_bh(&session->lock);
-					up(&conn->xmitsema);
+					mutex_unlock(&conn->xmitmutex);
 					goto success;
 				}
 				conn->tmabort_state = TMABORT_INITIAL;
@@ -3116,7 +3086,7 @@
 			spin_unlock_bh(&session->lock);
 		}
 	}
-	up(&conn->xmitsema);
+	mutex_unlock(&conn->xmitmutex);
 
 
 	/*
@@ -3182,7 +3152,7 @@
 exit:
 	del_timer_sync(&conn->tmabort_timer);
 
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 	if (conn->sock) {
 		struct sock *sk = conn->sock->sk;
 
@@ -3190,7 +3160,7 @@
 		iscsi_ctask_cleanup(conn, ctask);
 		write_unlock_bh(&sk->sk_callback_lock);
 	}
-	up(&conn->xmitsema);
+	mutex_unlock(&conn->xmitmutex);
 	return rc;
 }
 
@@ -3281,17 +3251,23 @@
 	.this_id		= -1,
 };
 
-static iscsi_sessionh_t
-iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
+static struct iscsi_transport iscsi_tcp_transport;
+
+static struct Scsi_Host *
+iscsi_session_create(struct scsi_transport_template *scsit,
+		     uint32_t initial_cmdsn)
 {
-	int cmd_i;
+	struct Scsi_Host *shost;
 	struct iscsi_session *session;
+	int cmd_i;
 
-	session = iscsi_hostdata(host->hostdata);
+	shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport);
+	if (!shost)
+		return NULL; 
+
+	session = iscsi_hostdata(shost->hostdata);
 	memset(session, 0, sizeof(struct iscsi_session));
-
-	session->host = host;
-	session->id = host->host_no;
+	session->host = shost;
 	session->state = ISCSI_STATE_LOGGED_IN;
 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
 	session->cmds_max = ISCSI_XMIT_CMDS_MAX;
@@ -3335,7 +3311,7 @@
 	if (iscsi_r2tpool_alloc(session))
 		goto r2tpool_alloc_fail;
 
-	return iscsi_handle(session);
+	return shost;
 
 r2tpool_alloc_fail:
 	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
@@ -3345,15 +3321,15 @@
 mgmtpool_alloc_fail:
 	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
 cmdpool_alloc_fail:
-	return iscsi_handle(NULL);
+	return NULL;
 }
 
 static void
-iscsi_session_destroy(iscsi_sessionh_t sessionh)
+iscsi_session_destroy(struct Scsi_Host *shost)
 {
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	int cmd_i;
 	struct iscsi_data_task *dtask, *n;
-	struct iscsi_session *session = iscsi_ptr(sessionh);
 
 	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
 		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
@@ -3369,6 +3345,8 @@
 	iscsi_r2tpool_free(session);
 	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
 	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+
+	iscsi_transport_destroy_session(shost);
 }
 
 static int
@@ -3467,6 +3445,8 @@
 			if (conn->data_rx_tfm)
 				crypto_free_tfm(conn->data_rx_tfm);
 		}
+		conn->sendpage = conn->datadgst_en ?
+			sock_no_sendpage : conn->sock->ops->sendpage;
 		break;
 	case ISCSI_PARAM_INITIAL_R2T_EN:
 		session->initial_r2t_en = value;
@@ -3515,25 +3495,12 @@
 }
 
 static int
-iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
-		     uint32_t *value)
+iscsi_session_get_param(struct Scsi_Host *shost,
+			enum iscsi_param param, uint32_t *value)
 {
-	struct iscsi_conn *conn = iscsi_ptr(connh);
-	struct iscsi_session *session = conn->session;
+	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 
 	switch(param) {
-	case ISCSI_PARAM_MAX_RECV_DLENGTH:
-		*value = conn->max_recv_dlength;
-		break;
-	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
-		*value = conn->max_xmit_dlength;
-		break;
-	case ISCSI_PARAM_HDRDGST_EN:
-		*value = conn->hdrdgst_en;
-		break;
-	case ISCSI_PARAM_DATADGST_EN:
-		*value = conn->datadgst_en;
-		break;
 	case ISCSI_PARAM_INITIAL_R2T_EN:
 		*value = session->initial_r2t_en;
 		break;
@@ -3571,6 +3538,31 @@
 	return 0;
 }
 
+static int
+iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value)
+{
+	struct iscsi_conn *conn = data;
+
+	switch(param) {
+	case ISCSI_PARAM_MAX_RECV_DLENGTH:
+		*value = conn->max_recv_dlength;
+		break;
+	case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+		*value = conn->max_xmit_dlength;
+		break;
+	case ISCSI_PARAM_HDRDGST_EN:
+		*value = conn->hdrdgst_en;
+		break;
+	case ISCSI_PARAM_DATADGST_EN:
+		*value = conn->datadgst_en;
+		break;
+	default:
+		return ISCSI_ERR_PARAM_NOT_FOUND;
+	}
+
+	return 0;
+}
+
 static void
 iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats)
 {
@@ -3601,9 +3593,9 @@
 	struct iscsi_conn *conn = iscsi_ptr(connh);
 	int rc;
 
-	down(&conn->xmitsema);
+	mutex_lock(&conn->xmitmutex);
 	rc = iscsi_conn_send_generic(conn, hdr, data, data_size);
-	up(&conn->xmitsema);
+	mutex_unlock(&conn->xmitmutex);
 
 	return rc;
 }
@@ -3615,6 +3607,7 @@
 				  | CAP_DATADGST,
 	.host_template		= &iscsi_sht,
 	.hostdata_size		= sizeof(struct iscsi_session),
+	.conndata_size		= sizeof(struct iscsi_conn),
 	.max_conn		= 1,
 	.max_cmd_len		= ISCSI_TCP_MAX_CMD_LEN,
 	.create_session		= iscsi_session_create,
@@ -3623,7 +3616,8 @@
 	.bind_conn		= iscsi_conn_bind,
 	.destroy_conn		= iscsi_conn_destroy,
 	.set_param		= iscsi_conn_set_param,
-	.get_param		= iscsi_conn_get_param,
+	.get_conn_param		= iscsi_conn_get_param,
+	.get_session_param	= iscsi_session_get_param,
 	.start_conn		= iscsi_conn_start,
 	.stop_conn		= iscsi_conn_stop,
 	.send_pdu		= iscsi_conn_send_pdu,
@@ -3633,8 +3627,6 @@
 static int __init
 iscsi_tcp_init(void)
 {
-	int error;
-
 	if (iscsi_max_lun < 1) {
 		printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
 		return -EINVAL;
@@ -3647,11 +3639,10 @@
 	if (!taskcache)
 		return -ENOMEM;
 
-	error = iscsi_register_transport(&iscsi_tcp_transport);
-	if (error)
+	if (!iscsi_register_transport(&iscsi_tcp_transport))
 		kmem_cache_destroy(taskcache);
 
-	return error;
+	return 0;
 }
 
 static void __exit
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 855f2df..f95e61b 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -158,7 +158,7 @@
 	struct kfifo		*mgmtqueue;	/* mgmt (control) xmit queue */
 	struct kfifo		*xmitqueue;	/* data-path cmd queue */
 	struct work_struct	xmitwork;	/* per-conn. xmit workqueue */
-	struct semaphore	xmitsema;	/* serializes connection xmit,
+	struct mutex		xmitmutex;	/* serializes connection xmit,
 						 * access to kfifos:	  *
 						 * xmitqueue, writequeue, *
 						 * immqueue, mgmtqueue    */
@@ -191,6 +191,8 @@
 	uint32_t		sendpage_failures_cnt;
 	uint32_t		discontiguous_hdr_cnt;
 	uint32_t		eh_abort_cnt;
+
+	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
 };
 
 struct iscsi_session {
@@ -240,8 +242,8 @@
 
 struct iscsi_buf {
 	struct scatterlist	sg;
-	struct kvec		iov;
 	unsigned int		sent;
+	char			use_sendmsg;
 };
 
 struct iscsi_data_task {
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f55b9b3..99bae83 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1747,7 +1747,7 @@
 	{ ATA_SHIFT_PIO,	XFER_PIO_0 },
 };
 
-static inline u8 base_from_shift(unsigned int shift)
+static u8 base_from_shift(unsigned int shift)
 {
 	int i;
 
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 9ee8218..dafabee 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -150,7 +150,7 @@
 	return psb;
 }
 
-struct  lpfc_scsi_buf*
+static struct lpfc_scsi_buf*
 lpfc_get_scsi_buf(struct lpfc_hba * phba)
 {
 	struct  lpfc_scsi_buf * lpfc_cmd = NULL;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 4a6feb1..d101a8a 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4479,7 +4479,7 @@
 	 * serialized. This is so because we want to reserve maximum number of
 	 * available command ids for the I/O commands.
 	 */
-	down(&adapter->int_mtx);
+	mutex_lock(&adapter->int_mtx);
 
 	scb = &adapter->int_scb;
 	memset(scb, 0, sizeof(scb_t));
@@ -4527,7 +4527,7 @@
 			mc->cmd, mc->opcode, mc->subopcode, scmd->result);
 	}
 
-	up(&adapter->int_mtx);
+	mutex_unlock(&adapter->int_mtx);
 
 	return rval;
 }
@@ -4866,7 +4866,7 @@
 		adapter->has_64bit_addr = 0;
 	}
 		
-	init_MUTEX(&adapter->int_mtx);
+	mutex_init(&adapter->int_mtx);
 	init_completion(&adapter->int_waitq);
 
 	adapter->this_id = DEFAULT_INITIATOR_ID;
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 6f90780..4b3e0d6 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -2,7 +2,7 @@
 #define __MEGARAID_H__
 
 #include <linux/spinlock.h>
-
+#include <linux/mutex.h>
 
 #define MEGARAID_VERSION	\
 	"v2.00.3 (Release Date: Wed Feb 19 08:51:30 EST 2003)\n"
@@ -889,7 +889,7 @@
 
 	scb_t			int_scb;
 	Scsi_Cmnd		int_scmd;
-	struct semaphore	int_mtx;	/* To synchronize the internal
+	struct mutex		int_mtx;	/* To synchronize the internal
 						commands */
 	struct completion	int_waitq;	/* wait queue for internal
 						 cmds */
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index d18a4bc..bf9f7f7 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -1266,7 +1266,7 @@
  * return the scb from the head of the free list. NULL if there are none
  * available
  **/
-static inline scb_t *
+static scb_t *
 megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
 {
 	struct list_head	*head = &adapter->kscb_pool;
@@ -1329,7 +1329,7 @@
  *
  * prepare the scatter-gather list
  */
-static inline int
+static int
 megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
 {
 	struct scatterlist	*sgl;
@@ -1402,7 +1402,7 @@
  *
  * post the command to the controller if mailbox is availble.
  */
-static inline int
+static int
 mbox_post_cmd(adapter_t *adapter, scb_t *scb)
 {
 	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
@@ -2070,7 +2070,7 @@
  *
  * Returns:	1 if the interrupt is valid, 0 otherwise
  */
-static inline int
+static int
 megaraid_ack_sequence(adapter_t *adapter)
 {
 	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
@@ -2208,7 +2208,7 @@
  *
  * DMA sync if required.
  */
-static inline void
+static void
 megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
 {
 	mbox_ccb_t	*ccb;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 3c32e69..511ed52 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <linux/fs.h>
 #include <linux/compat.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -72,7 +73,7 @@
 static int megasas_mgmt_majorno;
 static struct megasas_mgmt_info megasas_mgmt_info;
 static struct fasync_struct *megasas_async_queue;
-static DECLARE_MUTEX(megasas_async_queue_mutex);
+static DEFINE_MUTEX(megasas_async_queue_mutex);
 
 /**
  * megasas_get_cmd -	Get a command from the free pool
@@ -80,7 +81,7 @@
  *
  * Returns a free command from the pool
  */
-static inline struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
 						  *instance)
 {
 	unsigned long flags;
@@ -262,7 +263,7 @@
  * If successful, this function returns the number of SG elements. Otherwise,
  * it returnes -1.
  */
-static inline int
+static int
 megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   union megasas_sgl *mfi_sgl)
 {
@@ -310,7 +311,7 @@
  * If successful, this function returns the number of SG elements. Otherwise,
  * it returnes -1.
  */
-static inline int
+static int
 megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   union megasas_sgl *mfi_sgl)
 {
@@ -359,7 +360,7 @@
  * This function prepares CDB commands. These are typcially pass-through
  * commands to the devices.
  */
-static inline int
+static int
 megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   struct megasas_cmd *cmd)
 {
@@ -440,7 +441,7 @@
  *
  * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
  */
-static inline int
+static int
 megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   struct megasas_cmd *cmd)
 {
@@ -562,7 +563,7 @@
  * @scp:		SCSI command
  * @frame_count:	[OUT] Number of frames used to prepare this command
  */
-static inline struct megasas_cmd *megasas_build_cmd(struct megasas_instance
+static struct megasas_cmd *megasas_build_cmd(struct megasas_instance
 						    *instance,
 						    struct scsi_cmnd *scp,
 						    int *frame_count)
@@ -913,7 +914,7 @@
  * @instance:			Adapter soft state
  * @cmd:			Completed command
  */
-static inline void
+static void
 megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
 	dma_addr_t buf_h;
@@ -957,7 +958,7 @@
  * 				an alternate status (as in the case of aborted
  * 				commands)
  */
-static inline void
+static void
 megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 		     u8 alt_status)
 {
@@ -1104,7 +1105,7 @@
  * 					SCSI mid-layer instead of the status
  * 					returned by the FW
  */
-static inline int
+static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
 	u32 status;
@@ -2362,11 +2363,11 @@
 {
 	int rc;
 
-	down(&megasas_async_queue_mutex);
+	mutex_lock(&megasas_async_queue_mutex);
 
 	rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
 
-	up(&megasas_async_queue_mutex);
+	mutex_unlock(&megasas_async_queue_mutex);
 
 	if (rc >= 0) {
 		/* For sanity check when we get ioctl */
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
index 5205c4e..5758b25 100644
--- a/drivers/scsi/qla2xxx/Kconfig
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -1,4 +1,4 @@
-config SCSI_QLA2XXX
+config SCSI_QLA_FC
 	tristate "QLogic QLA2XXX Fibre Channel Support"
 	depends on PCI && SCSI
 	select SCSI_FC_ATTRS
@@ -22,49 +22,57 @@
 	Upon request, the driver caches the firmware image until
 	the driver is unloaded.
 
+	Firmware images can be retrieved from:
+
+		ftp://ftp.qlogic.com/outgoing/linux/firmware/
+
 	NOTE: The original method of building firmware-loader
 	modules has been deprecated as the firmware-images will
 	be removed from the kernel sources.
 
 config SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	bool "  Use firmware-loader modules (DEPRECATED)"
-	depends on SCSI_QLA2XXX
+	depends on SCSI_QLA_FC
+	help
+	  This option offers you the deprecated firmware-loader
+	  modules that have been obsoleted by the usage of the
+	  Firmware Loader interface in the qla2xxx driver.
 
 config SCSI_QLA21XX
 	tristate "  Build QLogic ISP2100 firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 21xx (ISP2100) host adapter family.
 
 config SCSI_QLA22XX
 	tristate "  Build QLogic ISP2200 firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 22xx (ISP2200) host adapter family.
 
 config SCSI_QLA2300
 	tristate "  Build QLogic ISP2300 firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 2300 (ISP2300 and ISP2312) host
 	adapter family.
 
 config SCSI_QLA2322
 	tristate "  Build QLogic ISP2322 firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 2322 (ISP2322) host adapter family.
 
 config SCSI_QLA6312
 	tristate "  Build QLogic ISP63xx firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 63xx (ISP6312 and ISP6322) host
 	adapter family.
 
 config SCSI_QLA24XX
 	tristate "  Build QLogic ISP24xx firmware-module"
-	depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+	depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
 	---help---
 	This driver supports the QLogic 24xx (ISP2422 and ISP2432) host
 	adapter family.
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index 40c0de1..d028bc50 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -3,7 +3,7 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
 		qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o
 
-obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx.o
+obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
 
 qla2100-y := ql2100.o ql2100_fw.o
 qla2200-y := ql2200.o ql2200_fw.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 2efca52..b17ee62 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -541,7 +541,7 @@
 void
 qla2x00_init_host_attr(scsi_qla_host_t *ha)
 {
-	fc_host_node_name(ha->host) = wwn_to_u64(ha->init_cb->node_name);
-	fc_host_port_name(ha->host) = wwn_to_u64(ha->init_cb->port_name);
+	fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
+	fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
 	fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
 }
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 5c5d231..2d9b12f 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1003,10 +1003,10 @@
 	fw = (struct qla24xx_fw_dump *) ha->fw_dump24;
 
 	rval = QLA_SUCCESS;
-	fw->hccr = RD_REG_DWORD(&reg->hccr);
+	fw->host_status = RD_REG_DWORD(&reg->host_status);
 
 	/* Pause RISC. */
-	if ((fw->hccr & HCCRX_RISC_PAUSE) == 0) {
+	if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
 		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
 		    HCCRX_CLR_HOST_INT);
 		RD_REG_DWORD(&reg->hccr);		/* PCI Posting. */
@@ -1021,16 +1021,54 @@
 		}
 	}
 
-	/* Disable interrupts. */
-	WRT_REG_DWORD(&reg->ictrl, 0);
-	RD_REG_DWORD(&reg->ictrl);
-
 	if (rval == QLA_SUCCESS) {
 		/* Host interface registers. */
 		dmp_reg = (uint32_t __iomem *)(reg + 0);
 		for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
 			fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++);
 
+		/* Disable interrupts. */
+		WRT_REG_DWORD(&reg->ictrl, 0);
+		RD_REG_DWORD(&reg->ictrl);
+
+		/* Shadow registers. */
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+		RD_REG_DWORD(&reg->iobase_addr);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0000000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0100000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0200000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0300000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0400000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0500000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
+
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+		WRT_REG_DWORD(dmp_reg, 0xB0600000);
+		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+		fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
+
 		/* Mailbox registers. */
 		mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
 		for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
@@ -1308,43 +1346,6 @@
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = RD_REG_DWORD(dmp_reg++);
 
-		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-		RD_REG_DWORD(&reg->iobase_addr);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0000000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0100000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0200000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0300000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0400000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0500000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
-
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0600000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
-
 		/* Local memory controller registers. */
 		iter_reg = fw->lmc_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
@@ -1677,7 +1678,7 @@
 	    ha->fw_major_version, ha->fw_minor_version,
 	    ha->fw_subminor_version, ha->fw_attributes);
 
-	qla_uprintf(&uiter, "\nHCCR Register\n%04x\n", fw->hccr);
+	qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status);
 
 	qla_uprintf(&uiter, "\nHost Interface Registers");
 	for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) {
@@ -1687,6 +1688,14 @@
 		qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]);
 	}
 
+	qla_uprintf(&uiter, "\n\nShadow Registers");
+	for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
+		if (cnt % 8 == 0)
+			qla_uprintf(&uiter, "\n");
+
+		qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
+	}
+
 	qla_uprintf(&uiter, "\n\nMailbox Registers");
 	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) {
 		if (cnt % 8 == 0)
@@ -1855,14 +1864,6 @@
 		qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]);
 	}
 
-	qla_uprintf(&uiter, "\n\nShadow Registers");
-	for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
-		if (cnt % 8 == 0)
-			qla_uprintf(&uiter, "\n");
-
-		qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
-	}
-
 	qla_uprintf(&uiter, "\n\nLMC Registers");
 	for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) {
 		if (cnt % 8 == 0)
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 935a59a..ab6afea 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -227,8 +227,9 @@
 #define FW_DUMP_SIZE_24XX	0x2B0000
 
 struct qla24xx_fw_dump {
-	uint32_t hccr;
+	uint32_t host_status;
 	uint32_t host_reg[32];
+	uint32_t shadow_reg[7];
 	uint16_t mailbox_reg[32];
 	uint32_t xseq_gp_reg[128];
 	uint32_t xseq_0_reg[16];
@@ -250,7 +251,6 @@
 	uint32_t rcvt0_data_dma_reg[32];
 	uint32_t rcvt1_data_dma_reg[32];
 	uint32_t risc_gp_reg[128];
-	uint32_t shadow_reg[7];
 	uint32_t lmc_reg[112];
 	uint32_t fpm_hdw_reg[192];
 	uint32_t fb_hdw_reg[176];
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index bec81ad..32be4c1 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -62,6 +62,7 @@
 extern int ql2xplogiabsentdevice;
 extern int ql2xloginretrycount;
 extern int ql2xfdmienable;
+extern int ql2xprocessrscn;
 
 extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
@@ -96,10 +97,7 @@
  * Global Function Prototypes in qla_mbx.c source file.
  */
 extern int
-qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t);
-
-extern int
-qla2x00_load_ram_ext(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index cd6f7c3..d620a8e8 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -538,6 +538,7 @@
 	ct_req->req.rff_id.port_id[1] = ha->d_id.b.area;
 	ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa;
 
+	ct_req->req.rff_id.fc4_feature = BIT_1;
 	ct_req->req.rff_id.fc4_type = 0x08;		/* SCSI - FCP */
 
 	/* Execute MS IOCB */
@@ -1529,9 +1530,9 @@
 	eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
 	eiter->len = __constant_cpu_to_be16(4 + 4);
 	if (IS_QLA25XX(ha))
-		eiter->a.sup_speed = __constant_cpu_to_be32(4);
-	else if (IS_QLA24XX(ha))
 		eiter->a.sup_speed = __constant_cpu_to_be32(8);
+	else if (IS_QLA24XX(ha))
+		eiter->a.sup_speed = __constant_cpu_to_be32(4);
 	else if (IS_QLA23XX(ha))
 		eiter->a.sup_speed = __constant_cpu_to_be32(2);
 	else
@@ -1553,9 +1554,6 @@
 		eiter->a.cur_speed = __constant_cpu_to_be32(2);
 		break;
 	case 3:
-		eiter->a.cur_speed = __constant_cpu_to_be32(8);
-		break;
-	case 4:
 		eiter->a.cur_speed = __constant_cpu_to_be32(4);
 		break;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 7d973bd..a91fea6 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1014,11 +1014,13 @@
 	int rval;
 
 	/* Update Serial Link options. */
-	if ((ha->fw_seriallink_options24[0] & BIT_0) == 0)
+	if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
 		return;
 
-	rval = qla2x00_set_serdes_params(ha, ha->fw_seriallink_options24[1],
-	    ha->fw_seriallink_options24[2], ha->fw_seriallink_options24[3]);
+	rval = qla2x00_set_serdes_params(ha,
+	    le16_to_cpu(ha->fw_seriallink_options24[1]),
+	    le16_to_cpu(ha->fw_seriallink_options24[2]),
+	    le16_to_cpu(ha->fw_seriallink_options24[3]));
 	if (rval != QLA_SUCCESS) {
 		qla_printk(KERN_WARNING, ha,
 		    "Unable to update Serial Link options (%x).\n", rval);
@@ -1939,6 +1941,9 @@
 			    "information -- get_port_database=%x, "
 			    "loop_id=0x%04x\n",
 			    ha->host_no, rval2, new_fcport->loop_id));
+			DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
+			    ha->host_no));
+			set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
 			continue;
 		}
 
@@ -2648,7 +2653,8 @@
 
 		switch (format) {
 		case 0:
-			if (!IS_QLA2100(ha) && !IS_QLA2200(ha) &&
+			if (ql2xprocessrscn &&
+			    !IS_QLA2100(ha) && !IS_QLA2200(ha) &&
 			    !IS_QLA6312(ha) && !IS_QLA6322(ha) &&
 			    !IS_QLA24XX(ha) && !IS_QLA25XX(ha) &&
 			    ha->flags.init_done) {
@@ -3402,6 +3408,8 @@
 	ha->node_name = icb->node_name;
 	ha->port_name = icb->port_name;
 
+	icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+
 	ha->retry_count = le16_to_cpu(nv->login_retry_count);
 
 	/* Set minimum login_timeout to 4 seconds. */
@@ -3667,8 +3675,8 @@
 			for (i = 0; i < dlen; i++)
 				dcode[i] = swab32(dcode[i]);
 
-			rval = qla2x00_load_ram_ext(ha, ha->request_dma,
-			    risc_addr, dlen);
+			rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
+			    dlen);
 			if (rval) {
 				DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
 				    "segment %d of firmware\n", ha->host_no,
@@ -3868,8 +3876,8 @@
 			for (i = 0; i < dlen; i++)
 				dcode[i] = swab32(fwcode[i]);
 
-			rval = qla2x00_load_ram_ext(ha, ha->request_dma,
-			    risc_addr, dlen);
+			rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
+			    dlen);
 			if (rval) {
 				DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
 				    "segment %d of firmware\n", ha->host_no,
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 5181d96..f63af08 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -519,7 +519,8 @@
 		 * us, create a new entry in our rscn fcports list and handle
 		 * the event like an RSCN.
 		 */
-		if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA6312(ha) &&
+		if (ql2xprocessrscn &&
+		    !IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA6312(ha) &&
 		    !IS_QLA6322(ha) && !IS_QLA24XX(ha) && !IS_QLA25XX(ha) &&
 		    ha->flags.init_done && mb[1] != 0xffff &&
 		    ((ha->operating_mode == P2P && mb[1] != 0) ||
@@ -963,15 +964,16 @@
 		break;
 
 	case CS_DATA_UNDERRUN:
-		DEBUG2(printk(KERN_INFO
-		    "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x.\n",
-		    ha->host_no, cp->device->id, cp->device->lun, comp_status,
-		    scsi_status));
-
 		resid = resid_len;
 		if (scsi_status & SS_RESIDUAL_UNDER) {
 			cp->resid = resid;
 			CMD_RESID_LEN(cp) = resid;
+		} else {
+			DEBUG2(printk(KERN_INFO
+			    "scsi(%ld:%d:%d) UNDERRUN status detected "
+			    "0x%x-0x%x.\n", ha->host_no, cp->device->id,
+			    cp->device->lun, comp_status, scsi_status));
+
 		}
 
 		/*
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 9746cd1..3099b37 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -196,7 +196,9 @@
 			/* Check for pending interrupts. */
 			qla2x00_poll(ha);
 
-			udelay(10); /* v4.27 */
+			if (command != MBC_LOAD_RISC_RAM_EXTENDED &&
+			    !ha->flags.mbox_int)
+				msleep(10);
 		} /* while */
 	}
 
@@ -325,98 +327,9 @@
 	return rval;
 }
 
-/*
- * qla2x00_load_ram
- *	Load adapter RAM using DMA.
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Returns:
- *	qla2x00 local function return status code.
- *
- * Context:
- *	Kernel context.
- */
 int
-qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint16_t risc_addr,
-    uint16_t risc_code_size)
-{
-	int rval;
-	mbx_cmd_t mc;
-	mbx_cmd_t *mcp = &mc;
-	uint32_t	req_len;
-	dma_addr_t	nml_dma;
-	uint32_t	nml_len;
-	uint32_t	normalized;
-
-	DEBUG11(printk("qla2x00_load_ram(%ld): entered.\n",
-	    ha->host_no);)
-
-	req_len = risc_code_size;
-	nml_dma = 0;
-	nml_len = 0;
-
-	normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma,
-	    &nml_len);
-
-	/* Load first segment */
-	mcp->mb[0] = MBC_LOAD_RISC_RAM;
-	mcp->mb[1] = risc_addr;
-	mcp->mb[2] = MSW(req_dma);
-	mcp->mb[3] = LSW(req_dma);
-	mcp->mb[4] = (uint16_t)req_len;
-	mcp->mb[6] = MSW(MSD(req_dma));
-	mcp->mb[7] = LSW(MSD(req_dma));
-	mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-	mcp->in_mb = MBX_0;
-	mcp->tov = 30;
-	mcp->flags = 0;
-	rval = qla2x00_mailbox_command(ha, mcp);
-
-	/* Load second segment - if necessary */
-	if (normalized && (rval == QLA_SUCCESS)) {
-		mcp->mb[0] = MBC_LOAD_RISC_RAM;
-		mcp->mb[1] = risc_addr + (uint16_t)req_len;
-		mcp->mb[2] = MSW(nml_dma);
-		mcp->mb[3] = LSW(nml_dma);
-		mcp->mb[4] = (uint16_t)nml_len;
-		mcp->mb[6] = MSW(MSD(nml_dma));
-		mcp->mb[7] = LSW(MSD(nml_dma));
-		mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-		mcp->in_mb = MBX_0;
-		mcp->tov = 30;
-		mcp->flags = 0;
-		rval = qla2x00_mailbox_command(ha, mcp);
-	}
-
-	if (rval == QLA_SUCCESS) {
-		/* Empty */
-		DEBUG11(printk("qla2x00_load_ram(%ld): done.\n", ha->host_no);)
-	} else {
-		/* Empty */
-		DEBUG2_3_11(printk("qla2x00_load_ram(%ld): failed. rval=%x "
-		    "mb[0]=%x.\n", ha->host_no, rval, mcp->mb[0]);)
-	}
-	return rval;
-}
-
-/*
- * qla2x00_load_ram_ext
- *	Load adapter extended RAM using DMA.
- *
- * Input:
- *	ha = adapter block pointer.
- *
- * Returns:
- *	qla2x00 local function return status code.
- *
- * Context:
- *	Kernel context.
- */
-int
-qla2x00_load_ram_ext(scsi_qla_host_t *ha, dma_addr_t req_dma,
-    uint32_t risc_addr, uint32_t risc_code_size)
+qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
+    uint32_t risc_code_size)
 {
 	int rval;
 	mbx_cmd_t mc;
@@ -424,14 +337,20 @@
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
+	if (MSW(risc_addr) || IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+		mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
+		mcp->mb[8] = MSW(risc_addr);
+		mcp->out_mb = MBX_8|MBX_0;
+	} else {
+		mcp->mb[0] = MBC_LOAD_RISC_RAM;
+		mcp->out_mb = MBX_0;
+	}
 	mcp->mb[1] = LSW(risc_addr);
 	mcp->mb[2] = MSW(req_dma);
 	mcp->mb[3] = LSW(req_dma);
 	mcp->mb[6] = MSW(MSD(req_dma));
 	mcp->mb[7] = LSW(MSD(req_dma));
-	mcp->mb[8] = MSW(risc_addr);
-	mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
 	if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
 		mcp->mb[4] = MSW(risc_code_size);
 		mcp->mb[5] = LSW(risc_code_size);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2430430..4916847 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -71,6 +71,12 @@
 		"Enables FDMI registratons "
 		"Default is 0 - no FDMI. 1 - perfom FDMI.");
 
+int ql2xprocessrscn;
+module_param(ql2xprocessrscn, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xprocessrscn,
+		"Option to enable port RSCN handling via a series of less"
+		"fabric intrusive ADISCs and PLOGIs.");
+
 /*
  * SCSI host template entry points
  */
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index d54d2a9..f4d755a 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -573,6 +573,9 @@
 		}
 	} while (0);
 
+	/* Enable flash write-protection. */
+	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
+
 	/* Disable flash write. */
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index f7937f7..d537192 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.03-k"
+#define QLA2XXX_VERSION      "8.01.04-k"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	1
-#define QLA_DRIVER_PATCH_VER	3
+#define QLA_DRIVER_PATCH_VER	4
 #define QLA_DRIVER_BETA_VER	0
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 5ec5f44..50c398a 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -148,9 +148,11 @@
 	{ RAID_LEVEL_LINEAR, "linear" },
 	{ RAID_LEVEL_0, "raid0" },
 	{ RAID_LEVEL_1, "raid1" },
+	{ RAID_LEVEL_10, "raid10" },
 	{ RAID_LEVEL_3, "raid3" },
 	{ RAID_LEVEL_4, "raid4" },
 	{ RAID_LEVEL_5, "raid5" },
+	{ RAID_LEVEL_50, "raid50" },
 	{ RAID_LEVEL_6, "raid6" },
 };
 
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ee5f4df..245ca99 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -55,6 +55,7 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -209,7 +210,7 @@
 	.gfp_mask	= __GFP_DMA,
 };
 
-static DECLARE_MUTEX(host_cmd_pool_mutex);
+static DEFINE_MUTEX(host_cmd_pool_mutex);
 
 static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
 					    gfp_t gfp_mask)
@@ -330,7 +331,7 @@
 	 * Select a command slab for this host and create it if not
 	 * yet existant.
 	 */
-	down(&host_cmd_pool_mutex);
+	mutex_lock(&host_cmd_pool_mutex);
 	pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
 	if (!pool->users) {
 		pool->slab = kmem_cache_create(pool->name,
@@ -342,7 +343,7 @@
 
 	pool->users++;
 	shost->cmd_pool = pool;
-	up(&host_cmd_pool_mutex);
+	mutex_unlock(&host_cmd_pool_mutex);
 
 	/*
 	 * Get one backup command for this host.
@@ -359,7 +360,7 @@
 		kmem_cache_destroy(pool->slab);
 	return -ENOMEM;
  fail:
-	up(&host_cmd_pool_mutex);
+	mutex_unlock(&host_cmd_pool_mutex);
 	return -ENOMEM;
 
 }
@@ -381,10 +382,10 @@
 		kmem_cache_free(shost->cmd_pool->slab, cmd);
 	}
 
-	down(&host_cmd_pool_mutex);
+	mutex_lock(&host_cmd_pool_mutex);
 	if (!--shost->cmd_pool->users)
 		kmem_cache_destroy(shost->cmd_pool->slab);
-	up(&host_cmd_pool_mutex);
+	mutex_unlock(&host_cmd_pool_mutex);
 }
 
 #ifdef CONFIG_SCSI_LOGGING
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 3ded9da..0e529f8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -221,8 +221,6 @@
 static struct device_driver sdebug_driverfs_driver = {
 	.name 		= sdebug_proc_name,
 	.bus		= &pseudo_lld_bus,
-	.probe          = sdebug_driver_probe,
-	.remove         = sdebug_driver_remove,
 };
 
 static const int check_condition_result =
@@ -1796,6 +1794,8 @@
 static struct bus_type pseudo_lld_bus = {
         .name = "pseudo",
         .match = pseudo_lld_bus_match,
+	.probe = sdebug_driver_probe,
+	.remove = sdebug_driver_remove,
 };
 
 static void sdebug_release_adapter(struct device * dev)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 00c9bf3..3574ba9 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1212,7 +1212,7 @@
 	return -EOPNOTSUPP;
 }
 
-static void scsi_generic_done(struct scsi_cmnd *cmd)
+static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
 {
 	BUG_ON(!blk_pc_request(cmd->request));
 	/*
@@ -1224,7 +1224,7 @@
 	scsi_io_completion(cmd, cmd->bufflen, 0);
 }
 
-void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
 {
 	struct request *req = cmd->request;
 
@@ -1241,8 +1241,8 @@
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
 	cmd->timeout_per_command = req->timeout;
+	cmd->done = scsi_blk_pc_done;
 }
-EXPORT_SYMBOL_GPL(scsi_setup_blk_pc_cmnd);
 
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
@@ -1339,7 +1339,6 @@
 	 * happening now.
 	 */
 	if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-		struct scsi_driver *drv;
 		int ret;
 
 		/*
@@ -1371,16 +1370,17 @@
 		/*
 		 * Initialize the actual SCSI command for this request.
 		 */
-		if (req->rq_disk) {
+		if (req->flags & REQ_BLOCK_PC) {
+			scsi_setup_blk_pc_cmnd(cmd);
+		} else if (req->rq_disk) {
+			struct scsi_driver *drv;
+
 			drv = *(struct scsi_driver **)req->rq_disk->private_data;
 			if (unlikely(!drv->init_command(cmd))) {
 				scsi_release_buffers(cmd);
 				scsi_put_command(cmd);
 				goto kill;
 			}
-		} else {
-			scsi_setup_blk_pc_cmnd(cmd);
-			cmd->done = scsi_generic_done;
 		}
 	}
 
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 14a6198..27c4827 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -26,12 +26,6 @@
 #define SCSI_SENSE_VALID(scmd) \
 	(((scmd)->sense_buffer[0] & 0x70) == 0x70)
 
-/*
- * Special value for scanning to specify scanning or rescanning of all
- * possible channels, (target) ids, or luns on a given shost.
- */
-#define SCAN_WILD_CARD	~0
-
 /* hosts.c */
 extern int scsi_init_hosts(void);
 extern void scsi_exit_hosts(void);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index a50958b..07be62b 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -25,11 +25,13 @@
 #include <linux/errno.h>
 #include <linux/blkdev.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -41,7 +43,7 @@
 static struct proc_dir_entry *proc_scsi;
 
 /* Protect sht->present and sht->proc_dir */
-static DECLARE_MUTEX(global_host_template_sem);
+static DEFINE_MUTEX(global_host_template_mutex);
 
 static int proc_scsi_read(char *buffer, char **start, off_t offset,
 			  int length, int *eof, void *data)
@@ -83,7 +85,7 @@
 	if (!sht->proc_info)
 		return;
 
-	down(&global_host_template_sem);
+	mutex_lock(&global_host_template_mutex);
 	if (!sht->present++) {
 		sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
         	if (!sht->proc_dir)
@@ -92,7 +94,7 @@
 		else
 			sht->proc_dir->owner = sht->module;
 	}
-	up(&global_host_template_sem);
+	mutex_unlock(&global_host_template_mutex);
 }
 
 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
@@ -100,12 +102,12 @@
 	if (!sht->proc_info)
 		return;
 
-	down(&global_host_template_sem);
+	mutex_lock(&global_host_template_mutex);
 	if (!--sht->present && sht->proc_dir) {
 		remove_proc_entry(sht->proc_name, proc_scsi);
 		sht->proc_dir = NULL;
 	}
-	up(&global_host_template_sem);
+	mutex_unlock(&global_host_template_mutex);
 }
 
 void scsi_proc_host_add(struct Scsi_Host *shost)
@@ -199,7 +201,10 @@
 	if (IS_ERR(shost))
 		return PTR_ERR(shost);
 
-	error = scsi_scan_host_selected(shost, channel, id, lun, 1);
+	if (shost->transportt->user_scan)
+		error = shost->transportt->user_scan(shost, channel, id, lun);
+	else
+		error = scsi_scan_host_selected(shost, channel, id, lun, 1);
 	scsi_host_put(shost);
 	return error;
 }
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 05ebb9c..752fb5d 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -334,19 +334,6 @@
 	struct scsi_target *starget;
 	struct scsi_target *found_target;
 
-	/*
-	 * Obtain the real parent from the transport. The transport
-	 * is allowed to fail (no error) if there is nothing at that
-	 * target id.
-	 */
-	if (shost->transportt->target_parent) {
-		spin_lock_irqsave(shost->host_lock, flags);
-		parent = shost->transportt->target_parent(shost, channel, id);
-		spin_unlock_irqrestore(shost->host_lock, flags);
-		if (!parent)
-			return NULL;
-	}
-
 	starget = kmalloc(size, GFP_KERNEL);
 	if (!starget) {
 		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
@@ -1283,20 +1270,21 @@
 	struct scsi_device *sdev;
 	struct device *parent = &shost->shost_gendev;
 	int res;
-	struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
+	struct scsi_target *starget;
 
+	starget = scsi_alloc_target(parent, channel, id);
 	if (!starget)
 		return ERR_PTR(-ENOMEM);
 
 	get_device(&starget->dev);
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	if (scsi_host_scan_allowed(shost)) {
 		res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
 					     hostdata);
 		if (res != SCSI_SCAN_LUN_PRESENT)
 			sdev = ERR_PTR(-ENODEV);
 	}
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 	scsi_target_reap(starget);
 	put_device(&starget->dev);
 
@@ -1404,10 +1392,10 @@
 {
 	struct Scsi_Host *shost = dev_to_shost(parent);
 
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	if (scsi_host_scan_allowed(shost))
 		__scsi_scan_target(parent, channel, id, lun, rescan);
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_scan_target);
 
@@ -1454,7 +1442,7 @@
 	    ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
 		return -EINVAL;
 
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	if (scsi_host_scan_allowed(shost)) {
 		if (channel == SCAN_WILD_CARD)
 			for (channel = 0; channel <= shost->max_channel;
@@ -1464,7 +1452,7 @@
 		else
 			scsi_scan_channel(shost, channel, id, lun, rescan);
 	}
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 
 	return 0;
 }
@@ -1522,7 +1510,7 @@
 	struct scsi_device *sdev = NULL;
 	struct scsi_target *starget;
 
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	if (!scsi_host_scan_allowed(shost))
 		goto out;
 	starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
@@ -1536,7 +1524,7 @@
 	}
 	put_device(&starget->dev);
  out:
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 	return sdev;
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ea7f3a4..a77b32de 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -106,7 +106,10 @@
 		return -EINVAL;
 	if (check_set(&lun, s3))
 		return -EINVAL;
-	res = scsi_scan_host_selected(shost, channel, id, lun, 1);
+	if (shost->transportt->user_scan)
+		res = shost->transportt->user_scan(shost, channel, id, lun);
+	else
+		res = scsi_scan_host_selected(shost, channel, id, lun, 1);
 	return res;
 }
 
@@ -745,9 +748,9 @@
 {
 	struct Scsi_Host *shost = sdev->host;
 
-	down(&shost->scan_mutex);
+	mutex_lock(&shost->scan_mutex);
 	__scsi_remove_device(sdev);
-	up(&shost->scan_mutex);
+	mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 685b997..f2c9acf 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -295,6 +295,7 @@
 	 */
 	fc_host_node_name(shost) = -1;
 	fc_host_port_name(shost) = -1;
+	fc_host_permanent_port_name(shost) = -1;
 	fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED;
 	memset(fc_host_supported_fc4s(shost), 0,
 		sizeof(fc_host_supported_fc4s(shost)));
@@ -795,6 +796,8 @@
 
 fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
 fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
+			     unsigned long long);
 fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
 fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
 fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -1090,17 +1093,23 @@
 /*
  * Must be called with shost->host_lock held
  */
-static struct device *fc_target_parent(struct Scsi_Host *shost,
-					int channel, uint id)
+static int fc_user_scan(struct Scsi_Host *shost, uint channel,
+		uint id, uint lun)
 {
 	struct fc_rport *rport;
 
-	list_for_each_entry(rport, &fc_host_rports(shost), peers)
-		if ((rport->channel == channel) &&
-		    (rport->scsi_target_id == id))
-			return &rport->dev;
+	list_for_each_entry(rport, &fc_host_rports(shost), peers) {
+		if (rport->scsi_target_id == -1)
+			continue;
 
-	return NULL;
+		if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
+		    (id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
+			scsi_scan_target(&rport->dev, rport->channel,
+					 rport->scsi_target_id, lun, 1);
+		}
+	}
+
+	return 0;
 }
 
 struct scsi_transport_template *
@@ -1139,7 +1148,7 @@
 	/* Transport uses the shost workq for scsi scanning */
 	i->t.create_work_queue = 1;
 
-	i->t.target_parent = fc_target_parent;
+	i->t.user_scan = fc_user_scan;
 	
 	/*
 	 * Setup SCSI Target Attributes.
@@ -1160,6 +1169,7 @@
 	count=0;
 	SETUP_HOST_ATTRIBUTE_RD(node_name);
 	SETUP_HOST_ATTRIBUTE_RD(port_name);
+	SETUP_HOST_ATTRIBUTE_RD(permanent_port_name);
 	SETUP_HOST_ATTRIBUTE_RD(supported_classes);
 	SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
 	SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index e08462d..59a1c9d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -21,11 +21,9 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 #include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mempool.h>
+#include <linux/mutex.h>
 #include <net/tcp.h>
-
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -45,11 +43,6 @@
 	 */
 	struct list_head sessions;
 	/*
-	 * lock to serialize access to the sessions list which must
-	 * be taken after the rx_queue_sema
-	 */
-	spinlock_t session_lock;
-	/*
 	 * based on transport capabilities, at register time we set these
 	 * bits to tell the transport class it wants attributes displayed
 	 * in sysfs or that it can support different iSCSI Data-Path
@@ -70,7 +63,7 @@
 /*
  * list of registered transports and lock that must
  * be held while accessing list. The iscsi_transport_lock must
- * be acquired after the rx_queue_sema.
+ * be acquired after the rx_queue_mutex.
  */
 static LIST_HEAD(iscsi_transports);
 static DEFINE_SPINLOCK(iscsi_transport_lock);
@@ -145,7 +138,7 @@
 
 static struct sock *nls;
 static int daemon_pid;
-static DECLARE_MUTEX(rx_queue_sema);
+static DEFINE_MUTEX(rx_queue_mutex);
 
 struct mempool_zone {
 	mempool_t *pool;
@@ -156,7 +149,7 @@
 	spinlock_t freelock;
 };
 
-static struct mempool_zone z_reply;
+static struct mempool_zone *z_reply;
 
 /*
  * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
@@ -171,50 +164,271 @@
 #define Z_MAX_ERROR	16
 #define Z_HIWAT_ERROR	12
 
-struct iscsi_if_conn {
-	struct list_head conn_list;	/* item in connlist */
-	struct list_head session_list;	/* item in session->connections */
-	iscsi_connh_t connh;
-	int active;			/* must be accessed with the connlock */
-	struct Scsi_Host *host;		/* originated shost */
-	struct device dev;		/* sysfs transport/container device */
-	struct iscsi_transport *transport;
-	struct mempool_zone z_error;
-	struct mempool_zone z_pdu;
-	struct list_head freequeue;
-};
-
-#define iscsi_dev_to_if_conn(_dev) \
-	container_of(_dev, struct iscsi_if_conn, dev)
-
-#define iscsi_cdev_to_if_conn(_cdev) \
-	iscsi_dev_to_if_conn(_cdev->dev)
-
 static LIST_HEAD(connlist);
 static DEFINE_SPINLOCK(connlock);
 
-struct iscsi_if_session {
-	struct list_head list;	/* item in session_list */
-	struct list_head connections;
-	iscsi_sessionh_t sessionh;
-	struct iscsi_transport *transport;
-	struct device dev;	/* sysfs transport/container device */
-};
+/*
+ * The following functions can be used by LLDs that allocate
+ * their own scsi_hosts or by software iscsi LLDs
+ */
+static void iscsi_session_release(struct device *dev)
+{
+	struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
+	struct iscsi_transport *transport = session->transport;
+	struct Scsi_Host *shost;
 
-#define iscsi_dev_to_if_session(_dev) \
-	container_of(_dev, struct iscsi_if_session, dev)
+	shost = iscsi_session_to_shost(session);
+	scsi_host_put(shost);
+	kfree(session);
+	module_put(transport->owner);
+}
 
-#define iscsi_cdev_to_if_session(_cdev) \
-	iscsi_dev_to_if_session(_cdev->dev)
+static int iscsi_is_session_dev(const struct device *dev)
+{
+	return dev->release == iscsi_session_release;
+}
 
-#define iscsi_if_session_to_shost(_session) \
-	dev_to_shost(_session->dev.parent)
+/**
+ * iscsi_create_session - create iscsi class session
+ * @shost: scsi host
+ * @transport: iscsi transport
+ *
+ * This can be called from a LLD or iscsi_transport
+ **/
+struct iscsi_cls_session *
+iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
+{
+	struct iscsi_cls_session *session;
+	int err;
 
-static struct iscsi_if_conn*
+	if (!try_module_get(transport->owner))
+		return NULL;
+
+	session = kzalloc(sizeof(*session), GFP_KERNEL);
+	if (!session)
+		goto module_put;
+	session->transport = transport;
+
+	/* this is released in the dev's release function */
+	scsi_host_get(shost);
+	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
+	session->dev.parent = &shost->shost_gendev;
+	session->dev.release = iscsi_session_release;
+	err = device_register(&session->dev);
+	if (err) {
+		dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
+			   "register session's dev\n");
+		goto free_session;
+	}
+	transport_register_device(&session->dev);
+
+	return session;
+
+free_session:
+	kfree(session);
+module_put:
+	module_put(transport->owner);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_session);
+
+/**
+ * iscsi_destroy_session - destroy iscsi session
+ * @session: iscsi_session
+ *
+ * Can be called by a LLD or iscsi_transport. There must not be
+ * any running connections.
+ **/
+int iscsi_destroy_session(struct iscsi_cls_session *session)
+{
+	transport_unregister_device(&session->dev);
+	device_unregister(&session->dev);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+
+static void iscsi_conn_release(struct device *dev)
+{
+	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+	struct device *parent = conn->dev.parent;
+
+	kfree(conn);
+	put_device(parent);
+}
+
+static int iscsi_is_conn_dev(const struct device *dev)
+{
+	return dev->release == iscsi_conn_release;
+}
+
+/**
+ * iscsi_create_conn - create iscsi class connection
+ * @session: iscsi cls session
+ * @cid: connection id
+ *
+ * This can be called from a LLD or iscsi_transport. The connection
+ * is child of the session so cid must be unique for all connections
+ * on the session.
+ **/
+struct iscsi_cls_conn *
+iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+{
+	struct iscsi_transport *transport = session->transport;
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+	struct iscsi_cls_conn *conn;
+	int err;
+
+	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
+	if (!conn)
+		return NULL;
+
+	if (transport->conndata_size)
+		conn->dd_data = &conn[1];
+
+	INIT_LIST_HEAD(&conn->conn_list);
+	conn->transport = transport;
+
+	/* this is released in the dev's release function */
+	if (!get_device(&session->dev))
+		goto free_conn;
+	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
+		 shost->host_no, cid);
+	conn->dev.parent = &session->dev;
+	conn->dev.release = iscsi_conn_release;
+	err = device_register(&conn->dev);
+	if (err) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register "
+			   "connection's dev\n");
+		goto release_parent_ref;
+	}
+	transport_register_device(&conn->dev);
+	return conn;
+
+release_parent_ref:
+	put_device(&session->dev);
+free_conn:
+	kfree(conn);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_conn);
+
+/**
+ * iscsi_destroy_conn - destroy iscsi class connection
+ * @session: iscsi cls session
+ *
+ * This can be called from a LLD or iscsi_transport.
+ **/
+int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
+{
+	transport_unregister_device(&conn->dev);
+	device_unregister(&conn->dev);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
+
+/*
+ * These functions are used only by software iscsi_transports
+ * which do not allocate and more their scsi_hosts since this
+ * is initiated from userspace.
+ */
+
+/*
+ * iSCSI Session's hostdata organization:
+ *
+ *    *------------------* <== hostdata_session(host->hostdata)
+ *    | ptr to class sess|
+ *    |------------------| <== iscsi_hostdata(host->hostdata)
+ *    | transport's data |
+ *    *------------------*
+ */
+
+#define hostdata_privsize(_t)	(sizeof(unsigned long) + _t->hostdata_size + \
+				 _t->hostdata_size % sizeof(unsigned long))
+
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_transport_create_session - create iscsi cls session and host
+ * scsit: scsi transport template
+ * transport: iscsi transport template
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+struct Scsi_Host *
+iscsi_transport_create_session(struct scsi_transport_template *scsit,
+			       struct iscsi_transport *transport)
+{
+	struct iscsi_cls_session *session;
+	struct Scsi_Host *shost;
+
+	shost = scsi_host_alloc(transport->host_template,
+				hostdata_privsize(transport));
+	if (!shost) {
+		printk(KERN_ERR "iscsi: can not allocate SCSI host for "
+			"session\n");
+		return NULL;
+	}
+
+	shost->max_id = 1;
+	shost->max_channel = 0;
+	shost->max_lun = transport->max_lun;
+	shost->max_cmd_len = transport->max_cmd_len;
+	shost->transportt = scsit;
+	shost->transportt->create_work_queue = 1;
+
+	if (scsi_add_host(shost, NULL))
+		goto free_host;
+
+	session = iscsi_create_session(shost, transport);
+	if (!session)
+		goto remove_host;
+
+	*(unsigned long*)shost->hostdata = (unsigned long)session;
+	return shost;
+
+remove_host:
+	scsi_remove_host(shost);
+free_host:
+	scsi_host_put(shost);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_transport_create_session);
+
+/**
+ * iscsi_transport_destroy_session - destroy session and scsi host
+ * shost: scsi host
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+int iscsi_transport_destroy_session(struct Scsi_Host *shost)
+{
+	struct iscsi_cls_session *session;
+
+	scsi_remove_host(shost);
+	session = hostdata_session(shost->hostdata);
+	iscsi_destroy_session(session);
+	/* ref from host alloc */
+	scsi_host_put(shost);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session);
+
+/*
+ * iscsi interface functions
+ */
+static struct iscsi_cls_conn*
 iscsi_if_find_conn(uint64_t key)
 {
 	unsigned long flags;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 
 	spin_lock_irqsave(&connlock, flags);
 	list_for_each_entry(conn, &connlist, conn_list)
@@ -249,7 +463,7 @@
 }
 
 static void*
-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
+mempool_zone_alloc_skb(unsigned int gfp_mask, void *pool_data)
 {
 	struct mempool_zone *zone = pool_data;
 
@@ -281,14 +495,21 @@
 	spin_unlock_irqrestore(&zone->freelock, flags);
 }
 
-static int
-mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size,
-		unsigned hiwat)
+static struct mempool_zone *
+mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
 {
+	struct mempool_zone *zp;
+
+	zp = kzalloc(sizeof(*zp), GFP_KERNEL);
+	if (!zp)
+		return NULL;
+
 	zp->pool = mempool_create(max, mempool_zone_alloc_skb,
 				  mempool_zone_free_skb, zp);
-	if (!zp->pool)
-		return -ENOMEM;
+	if (!zp->pool) {
+		kfree(zp);
+		return NULL;
+	}
 
 	zp->size = size;
 	zp->hiwat = hiwat;
@@ -297,9 +518,14 @@
 	spin_lock_init(&zp->freelock);
 	atomic_set(&zp->allocated, 0);
 
-	return 0;
+	return zp;
 }
 
+static void mempool_zone_destroy(struct mempool_zone *zp)
+{
+	mempool_destroy(zp->pool);
+	kfree(zp);
+}
 
 static struct sk_buff*
 mempool_zone_get_skb(struct mempool_zone *zone)
@@ -339,7 +565,7 @@
 	struct nlmsghdr	*nlh;
 	struct sk_buff *skb;
 	struct iscsi_uevent *ev;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	char *pdu;
 	int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
 			      data_size);
@@ -347,13 +573,13 @@
 	conn = iscsi_if_find_conn(connh);
 	BUG_ON(!conn);
 
-	mempool_zone_complete(&conn->z_pdu);
+	mempool_zone_complete(conn->z_pdu);
 
-	skb = mempool_zone_get_skb(&conn->z_pdu);
+	skb = mempool_zone_get_skb(conn->z_pdu);
 	if (!skb) {
 		iscsi_conn_error(connh, ISCSI_ERR_CONN_FAILED);
-		printk(KERN_ERR "iscsi%d: can not deliver control PDU: OOM\n",
-		       conn->host->host_no);
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
+			   "control PDU: OOM\n");
 		return -ENOMEM;
 	}
 
@@ -362,14 +588,14 @@
 	memset(ev, 0, sizeof(*ev));
 	ev->transport_handle = iscsi_handle(conn->transport);
 	ev->type = ISCSI_KEVENT_RECV_PDU;
-	if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
+	if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
 		ev->iferror = -ENOMEM;
 	ev->r.recv_req.conn_handle = connh;
 	pdu = (char*)ev + sizeof(*ev);
 	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
 	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-	return iscsi_unicast_skb(&conn->z_pdu, skb);
+	return iscsi_unicast_skb(conn->z_pdu, skb);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
@@ -378,18 +604,18 @@
 	struct nlmsghdr	*nlh;
 	struct sk_buff	*skb;
 	struct iscsi_uevent *ev;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	int len = NLMSG_SPACE(sizeof(*ev));
 
 	conn = iscsi_if_find_conn(connh);
 	BUG_ON(!conn);
 
-	mempool_zone_complete(&conn->z_error);
+	mempool_zone_complete(conn->z_error);
 
-	skb = mempool_zone_get_skb(&conn->z_error);
+	skb = mempool_zone_get_skb(conn->z_error);
 	if (!skb) {
-		printk(KERN_ERR "iscsi%d: gracefully ignored conn error (%d)\n",
-		       conn->host->host_no, error);
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
+			  "conn error (%d)\n", error);
 		return;
 	}
 
@@ -397,15 +623,15 @@
 	ev = NLMSG_DATA(nlh);
 	ev->transport_handle = iscsi_handle(conn->transport);
 	ev->type = ISCSI_KEVENT_CONN_ERROR;
-	if (atomic_read(&conn->z_error.allocated) >= conn->z_error.hiwat)
+	if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
 		ev->iferror = -ENOMEM;
 	ev->r.connerror.error = error;
 	ev->r.connerror.conn_handle = connh;
 
-	iscsi_unicast_skb(&conn->z_error, skb);
+	iscsi_unicast_skb(conn->z_error, skb);
 
-	printk(KERN_INFO "iscsi%d: detected conn error (%d)\n",
-	       conn->host->host_no, error);
+	dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
+		   error);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_error);
 
@@ -419,9 +645,9 @@
 	int flags = multi ? NLM_F_MULTI : 0;
 	int t = done ? NLMSG_DONE : type;
 
-	mempool_zone_complete(&z_reply);
+	mempool_zone_complete(z_reply);
 
-	skb = mempool_zone_get_skb(&z_reply);
+	skb = mempool_zone_get_skb(z_reply);
 	/*
 	 * FIXME:
 	 * user is supposed to react on iferror == -ENOMEM;
@@ -432,304 +658,7 @@
 	nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
 	nlh->nlmsg_flags = flags;
 	memcpy(NLMSG_DATA(nlh), payload, size);
-	return iscsi_unicast_skb(&z_reply, skb);
-}
-
-/*
- * iSCSI Session's hostdata organization:
- *
- *    *------------------* <== host->hostdata
- *    | transport        |
- *    |------------------| <== iscsi_hostdata(host->hostdata)
- *    | transport's data |
- *    |------------------| <== hostdata_session(host->hostdata)
- *    | interface's data |
- *    *------------------*
- */
-
-#define hostdata_privsize(_t)	(sizeof(unsigned long) + _t->hostdata_size + \
-				 _t->hostdata_size % sizeof(unsigned long) + \
-				 sizeof(struct iscsi_if_session))
-
-#define hostdata_session(_hostdata) ((void*)_hostdata + sizeof(unsigned long) + \
-			((struct iscsi_transport *) \
-			 iscsi_ptr(*(uint64_t *)_hostdata))->hostdata_size)
-
-static void iscsi_if_session_dev_release(struct device *dev)
-{
-	struct iscsi_if_session *session = iscsi_dev_to_if_session(dev);
-	struct iscsi_transport *transport = session->transport;
-	struct Scsi_Host *shost = iscsi_if_session_to_shost(session);
-	struct iscsi_if_conn *conn, *tmp;
-	unsigned long flags;
-
-	/* now free connections */
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry_safe(conn, tmp, &session->connections,
-				 session_list) {
-		list_del(&conn->session_list);
-		mempool_destroy(conn->z_pdu.pool);
-		mempool_destroy(conn->z_error.pool);
-		kfree(conn);
-	}
-	spin_unlock_irqrestore(&connlock, flags);
-	scsi_host_put(shost);
-	module_put(transport->owner);
-}
-
-static int
-iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
-{
-	struct iscsi_transport *transport = priv->iscsi_transport;
-	struct iscsi_if_session *session;
-	struct Scsi_Host *shost;
-	unsigned long flags;
-	int error;
-
-	if (!try_module_get(transport->owner))
-		return -EPERM;
-
-	shost = scsi_host_alloc(transport->host_template,
-				hostdata_privsize(transport));
-	if (!shost) {
-		ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-		printk(KERN_ERR "iscsi: can not allocate SCSI host for "
-		       "session\n");
-		error = -ENOMEM;
-		goto out_module_put;
-	}
-	shost->max_id = 1;
-	shost->max_channel = 0;
-	shost->max_lun = transport->max_lun;
-	shost->max_cmd_len = transport->max_cmd_len;
-	shost->transportt = &priv->t;
-
-	/* store struct iscsi_transport in hostdata */
-	*(uint64_t*)shost->hostdata = ev->transport_handle;
-
-	ev->r.c_session_ret.session_handle = transport->create_session(
-					ev->u.c_session.initial_cmdsn, shost);
-	if (ev->r.c_session_ret.session_handle == iscsi_handle(NULL)) {
-		error = 0;
-		goto out_host_put;
-	}
-
-	/* host_no becomes assigned SID */
-	ev->r.c_session_ret.sid = shost->host_no;
-	/* initialize session */
-	session = hostdata_session(shost->hostdata);
-	INIT_LIST_HEAD(&session->connections);
-	INIT_LIST_HEAD(&session->list);
-	session->sessionh = ev->r.c_session_ret.session_handle;
-	session->transport = transport;
-
-	error = scsi_add_host(shost, NULL);
-	if (error)
-		goto out_destroy_session;
-
-	/*
-	 * this is released in the dev's release function)
-	 */
-	scsi_host_get(shost);
-	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
-	session->dev.parent = &shost->shost_gendev;
-	session->dev.release = iscsi_if_session_dev_release;
-	error = device_register(&session->dev);
-	if (error) {
-		printk(KERN_ERR "iscsi: could not register session%d's dev\n",
-		       shost->host_no);
-		goto out_remove_host;
-	}
-	transport_register_device(&session->dev);
-
-	/* add this session to the list of active sessions */
-	spin_lock_irqsave(&priv->session_lock, flags);
-	list_add(&session->list, &priv->sessions);
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
-	return 0;
-
-out_remove_host:
-	scsi_remove_host(shost);
-out_destroy_session:
-	transport->destroy_session(ev->r.c_session_ret.session_handle);
-	ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-out_host_put:
-	scsi_host_put(shost);
-out_module_put:
-	module_put(transport->owner);
-	return error;
-}
-
-static int
-iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
-{
-	struct iscsi_transport *transport = priv->iscsi_transport;
-	struct Scsi_Host *shost;
-	struct iscsi_if_session *session;
-	unsigned long flags;
-	struct iscsi_if_conn *conn;
-	int error = 0;
-
-	shost = scsi_host_lookup(ev->u.d_session.sid);
-	if (shost == ERR_PTR(-ENXIO))
-		return -EEXIST;
-	session = hostdata_session(shost->hostdata);
-
-	/* check if we have active connections */
-	spin_lock_irqsave(&connlock, flags);
-	list_for_each_entry(conn, &session->connections, session_list) {
-		if (conn->active) {
-			printk(KERN_ERR "iscsi%d: can not destroy session: "
-			       "has active connection (%p)\n",
-			       shost->host_no, iscsi_ptr(conn->connh));
-			spin_unlock_irqrestore(&connlock, flags);
-			error = EIO;
-			goto out_release_ref;
-		}
-	}
-	spin_unlock_irqrestore(&connlock, flags);
-
-	scsi_remove_host(shost);
-	transport->destroy_session(ev->u.d_session.session_handle);
-	transport_unregister_device(&session->dev);
-	device_unregister(&session->dev);
-
-	/* remove this session from the list of active sessions */
-	spin_lock_irqsave(&priv->session_lock, flags);
-	list_del(&session->list);
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
-	/* ref from host alloc */
-	scsi_host_put(shost);
-out_release_ref:
-	/* ref from host lookup */
-	scsi_host_put(shost);
-	return error;
-}
-
-static void iscsi_if_conn_dev_release(struct device *dev)
-{
-	struct iscsi_if_conn *conn = iscsi_dev_to_if_conn(dev);
-	struct Scsi_Host *shost = conn->host;
-
-	scsi_host_put(shost);
-}
-
-static int
-iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
-	struct iscsi_if_session *session;
-	struct Scsi_Host *shost;
-	struct iscsi_if_conn *conn;
-	unsigned long flags;
-	int error;
-
-	shost = scsi_host_lookup(ev->u.c_conn.sid);
-	if (shost == ERR_PTR(-ENXIO))
-		return -EEXIST;
-	session = hostdata_session(shost->hostdata);
-
-	conn = kmalloc(sizeof(struct iscsi_if_conn), GFP_KERNEL);
-	if (!conn) {
-		error = -ENOMEM;
-		goto out_release_ref;
-	}
-	memset(conn, 0, sizeof(struct iscsi_if_conn));
-	INIT_LIST_HEAD(&conn->session_list);
-	INIT_LIST_HEAD(&conn->conn_list);
-	conn->host = shost;
-	conn->transport = transport;
-
-	error = mempool_zone_init(&conn->z_pdu, Z_MAX_PDU,
-			NLMSG_SPACE(sizeof(struct iscsi_uevent) +
-				    sizeof(struct iscsi_hdr) +
-				    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
-			Z_HIWAT_PDU);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: can not allocate pdu zone for new "
-		       "conn\n", shost->host_no);
-		goto out_free_conn;
-	}
-	error = mempool_zone_init(&conn->z_error, Z_MAX_ERROR,
-			NLMSG_SPACE(sizeof(struct iscsi_uevent)),
-			Z_HIWAT_ERROR);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: can not allocate error zone for "
-		       "new conn\n", shost->host_no);
-		goto out_free_pdu_pool;
-	}
-
-	ev->r.handle = transport->create_conn(ev->u.c_conn.session_handle,
-					ev->u.c_conn.cid);
-	if (!ev->r.handle) {
-		error = -ENODEV;
-		goto out_free_error_pool;
-	}
-
-	conn->connh = ev->r.handle;
-
-	/*
-	 * this is released in the dev's release function
-	 */
-	if (!scsi_host_get(shost))
-		goto out_destroy_conn;
-	snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-		 shost->host_no, ev->u.c_conn.cid);
-	conn->dev.parent = &session->dev;
-	conn->dev.release = iscsi_if_conn_dev_release;
-	error = device_register(&conn->dev);
-	if (error) {
-		printk(KERN_ERR "iscsi%d: could not register connections%u "
-		       "dev\n", shost->host_no, ev->u.c_conn.cid);
-		goto out_release_parent_ref;
-	}
-	transport_register_device(&conn->dev);
-
-	spin_lock_irqsave(&connlock, flags);
-	list_add(&conn->conn_list, &connlist);
-	list_add(&conn->session_list, &session->connections);
-	conn->active = 1;
-	spin_unlock_irqrestore(&connlock, flags);
-
-	scsi_host_put(shost);
-	return 0;
-
-out_release_parent_ref:
-	scsi_host_put(shost);
-out_destroy_conn:
-	transport->destroy_conn(ev->r.handle);
-out_free_error_pool:
-	mempool_destroy(conn->z_error.pool);
-out_free_pdu_pool:
-	mempool_destroy(conn->z_pdu.pool);
-out_free_conn:
-	kfree(conn);
-out_release_ref:
-	scsi_host_put(shost);
-	return error;
-}
-
-static int
-iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
-	unsigned long flags;
-	struct iscsi_if_conn *conn;
-
-	conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle);
-	if (!conn)
-		return -EEXIST;
-
-	transport->destroy_conn(ev->u.d_conn.conn_handle);
-
-	spin_lock_irqsave(&connlock, flags);
-	conn->active = 0;
-	list_del(&conn->conn_list);
-	spin_unlock_irqrestore(&connlock, flags);
-
-	transport_unregister_device(&conn->dev);
-	device_unregister(&conn->dev);
-	return 0;
+	return iscsi_unicast_skb(z_reply, skb);
 }
 
 static int
@@ -739,7 +668,7 @@
 	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
 	struct iscsi_stats *stats;
 	struct sk_buff *skbstat;
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_conn *conn;
 	struct nlmsghdr	*nlhstat;
 	struct iscsi_uevent *evstat;
 	int len = NLMSG_SPACE(sizeof(*ev) +
@@ -755,12 +684,12 @@
 	do {
 		int actual_size;
 
-		mempool_zone_complete(&conn->z_pdu);
+		mempool_zone_complete(conn->z_pdu);
 
-		skbstat = mempool_zone_get_skb(&conn->z_pdu);
+		skbstat = mempool_zone_get_skb(conn->z_pdu);
 		if (!skbstat) {
-			printk(KERN_ERR "iscsi%d: can not deliver stats: OOM\n",
-			       conn->host->host_no);
+			dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+				   "deliver stats: OOM\n");
 			return -ENOMEM;
 		}
 
@@ -770,7 +699,7 @@
 		memset(evstat, 0, sizeof(*evstat));
 		evstat->transport_handle = iscsi_handle(conn->transport);
 		evstat->type = nlh->nlmsg_type;
-		if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
+		if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
 			evstat->iferror = -ENOMEM;
 		evstat->u.get_stats.conn_handle =
 			ev->u.get_stats.conn_handle;
@@ -788,13 +717,141 @@
 		skb_trim(skb, NLMSG_ALIGN(actual_size));
 		nlhstat->nlmsg_len = actual_size;
 
-		err = iscsi_unicast_skb(&conn->z_pdu, skbstat);
+		err = iscsi_unicast_skb(conn->z_pdu, skbstat);
 	} while (err < 0 && err != -ECONNREFUSED);
 
 	return err;
 }
 
 static int
+iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+{
+	struct iscsi_transport *transport = priv->iscsi_transport;
+	struct Scsi_Host *shost;
+
+	if (!transport->create_session)
+		return -EINVAL;
+
+	shost = transport->create_session(&priv->t,
+					  ev->u.c_session.initial_cmdsn);
+	if (!shost)
+		return -ENOMEM;
+
+	ev->r.c_session_ret.session_handle = iscsi_handle(iscsi_hostdata(shost->hostdata));
+	ev->r.c_session_ret.sid = shost->host_no;
+	return 0;
+}
+
+static int
+iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
+{
+	struct iscsi_transport *transport = priv->iscsi_transport;
+
+	struct Scsi_Host *shost;
+
+	if (!transport->destroy_session)
+		return -EINVAL;
+
+	shost = scsi_host_lookup(ev->u.d_session.sid);
+	if (shost == ERR_PTR(-ENXIO))
+		return -EEXIST;
+
+	if (transport->destroy_session)
+		transport->destroy_session(shost);
+        /* ref from host lookup */
+        scsi_host_put(shost);
+	return 0;
+}
+
+static int
+iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){
+	struct Scsi_Host *shost;
+	struct iscsi_cls_conn *conn;
+	unsigned long flags;
+
+	if (!transport->create_conn)
+		return -EINVAL;
+
+	shost = scsi_host_lookup(ev->u.c_conn.sid);
+	if (shost == ERR_PTR(-ENXIO))
+		return -EEXIST;
+
+	conn = transport->create_conn(shost, ev->u.c_conn.cid);
+	if (!conn)
+		goto release_ref;
+
+	conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
+			NLMSG_SPACE(sizeof(struct iscsi_uevent) +
+				    sizeof(struct iscsi_hdr) +
+				    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
+			Z_HIWAT_PDU);
+	if (!conn->z_pdu) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+			   "pdu zone for new conn\n");
+		goto destroy_conn;
+	}
+
+	conn->z_error = mempool_zone_init(Z_MAX_ERROR,
+			NLMSG_SPACE(sizeof(struct iscsi_uevent)),
+			Z_HIWAT_ERROR);
+	if (!conn->z_error) {
+		dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+			   "error zone for new conn\n");
+		goto free_pdu_pool;
+	}
+
+	ev->r.handle = conn->connh = iscsi_handle(conn->dd_data);
+
+	spin_lock_irqsave(&connlock, flags);
+	list_add(&conn->conn_list, &connlist);
+	conn->active = 1;
+	spin_unlock_irqrestore(&connlock, flags);
+
+	scsi_host_put(shost);
+	return 0;
+
+free_pdu_pool:
+	mempool_zone_destroy(conn->z_pdu);
+destroy_conn:
+	if (transport->destroy_conn)
+		transport->destroy_conn(conn->dd_data);
+release_ref:
+	scsi_host_put(shost);
+	return -ENOMEM;
+}
+
+static int
+iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
+{
+	unsigned long flags;
+	struct iscsi_cls_conn *conn;
+	struct mempool_zone *z_error, *z_pdu;
+
+	conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle);
+	if (!conn)
+		return -EEXIST;
+
+	if (!transport->destroy_conn)
+		return -EINVAL;
+
+	spin_lock_irqsave(&connlock, flags);
+	conn->active = 0;
+	list_del(&conn->conn_list);
+	spin_unlock_irqrestore(&connlock, flags);
+
+	z_pdu = conn->z_pdu;
+	z_error = conn->z_error;
+
+	if (transport->destroy_conn)
+		transport->destroy_conn(conn);
+
+	mempool_zone_destroy(z_pdu);
+	mempool_zone_destroy(z_error);
+
+	return 0;
+}
+
+static int
 iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	int err = 0;
@@ -881,7 +938,7 @@
 {
 	struct sk_buff *skb;
 
-	down(&rx_queue_sema);
+	mutex_lock(&rx_queue_mutex);
 	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 		while (skb->len >= NLMSG_SPACE(0)) {
 			int err;
@@ -915,17 +972,20 @@
 				err = iscsi_if_send_reply(
 					NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
 					nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-				if (atomic_read(&z_reply.allocated) >=
-						z_reply.hiwat)
+				if (atomic_read(&z_reply->allocated) >=
+						z_reply->hiwat)
 					ev->iferror = -ENOMEM;
 			} while (err < 0 && err != -ECONNREFUSED);
 			skb_pull(skb, rlen);
 		}
 		kfree_skb(skb);
 	}
-	up(&rx_queue_sema);
+	mutex_unlock(&rx_queue_mutex);
 }
 
+#define iscsi_cdev_to_conn(_cdev) \
+	iscsi_dev_to_conn(_cdev->dev)
+
 /*
  * iSCSI connection attrs
  */
@@ -934,12 +994,10 @@
 show_conn_int_param_##param(struct class_device *cdev, char *buf)	\
 {									\
 	uint32_t value = 0;						\
-	struct iscsi_if_conn *conn = iscsi_cdev_to_if_conn(cdev);	\
-	struct iscsi_internal *priv;					\
+	struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);		\
+	struct iscsi_transport *t = conn->transport;			\
 									\
-	priv = to_iscsi_internal(conn->host->transportt);		\
-	if (priv->param_mask & (1 << param))				\
-		priv->iscsi_transport->get_param(conn->connh, param, &value); \
+	t->get_conn_param(conn->dd_data, param, &value);		\
 	return snprintf(buf, 20, format"\n", value);			\
 }
 
@@ -954,6 +1012,9 @@
 iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
 iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
 
+#define iscsi_cdev_to_session(_cdev) \
+	iscsi_dev_to_session(_cdev->dev)
+
 /*
  * iSCSI session attrs
  */
@@ -962,20 +1023,11 @@
 show_session_int_param_##param(struct class_device *cdev, char *buf)	\
 {									\
 	uint32_t value = 0;						\
-	struct iscsi_if_session *session = iscsi_cdev_to_if_session(cdev); \
-	struct Scsi_Host *shost = iscsi_if_session_to_shost(session);	\
-	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
-	struct iscsi_if_conn *conn = NULL;				\
-	unsigned long  flags;						\
+	struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);	\
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);	\
+	struct iscsi_transport *t = session->transport;			\
 									\
-	spin_lock_irqsave(&connlock, flags);				\
-	if (!list_empty(&session->connections))				\
-		conn = list_entry(session->connections.next,		\
-				  struct iscsi_if_conn, session_list);	\
-	spin_unlock_irqrestore(&connlock, flags);			\
-									\
-	if (conn && (priv->param_mask & (1 << param)))			\
-		priv->iscsi_transport->get_param(conn->connh, param, &value);\
+	t->get_session_param(shost, param, &value);			\
 	return snprintf(buf, 20, format"\n", value);			\
 }
 
@@ -1004,23 +1056,18 @@
 		count++;						\
 	}
 
-static int iscsi_is_session_dev(const struct device *dev)
-{
-	return dev->release == iscsi_if_session_dev_release;
-}
-
 static int iscsi_session_match(struct attribute_container *cont,
 			   struct device *dev)
 {
-	struct iscsi_if_session *session;
+	struct iscsi_cls_session *session;
 	struct Scsi_Host *shost;
 	struct iscsi_internal *priv;
 
 	if (!iscsi_is_session_dev(dev))
 		return 0;
 
-	session = iscsi_dev_to_if_session(dev);
-	shost = iscsi_if_session_to_shost(session);
+	session = iscsi_dev_to_session(dev);
+	shost = iscsi_session_to_shost(session);
 	if (!shost->transportt)
 		return 0;
 
@@ -1031,23 +1078,21 @@
 	return &priv->session_cont.ac == cont;
 }
 
-static int iscsi_is_conn_dev(const struct device *dev)
-{
-	return dev->release == iscsi_if_conn_dev_release;
-}
-
 static int iscsi_conn_match(struct attribute_container *cont,
 			   struct device *dev)
 {
-	struct iscsi_if_conn *conn;
+	struct iscsi_cls_session *session;
+	struct iscsi_cls_conn *conn;
 	struct Scsi_Host *shost;
 	struct iscsi_internal *priv;
 
 	if (!iscsi_is_conn_dev(dev))
 		return 0;
 
-	conn = iscsi_dev_to_if_conn(dev);
-	shost = conn->host;
+	conn = iscsi_dev_to_conn(dev);
+	session = iscsi_dev_to_session(conn->dev.parent);
+	shost = iscsi_session_to_shost(session);
+
 	if (!shost->transportt)
 		return 0;
 
@@ -1058,7 +1103,8 @@
 	return &priv->conn_cont.ac == cont;
 }
 
-int iscsi_register_transport(struct iscsi_transport *tt)
+struct scsi_transport_template *
+iscsi_register_transport(struct iscsi_transport *tt)
 {
 	struct iscsi_internal *priv;
 	unsigned long flags;
@@ -1068,15 +1114,14 @@
 
 	priv = iscsi_if_transport_lookup(tt);
 	if (priv)
-		return -EEXIST;
+		return NULL;
 
 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
-		return -ENOMEM;
+		return NULL;
 	memset(priv, 0, sizeof(*priv));
 	INIT_LIST_HEAD(&priv->list);
 	INIT_LIST_HEAD(&priv->sessions);
-	spin_lock_init(&priv->session_lock);
 	priv->iscsi_transport = tt;
 
 	priv->cdev.class = &iscsi_transport_class;
@@ -1142,13 +1187,13 @@
 	spin_unlock_irqrestore(&iscsi_transport_lock, flags);
 
 	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
-	return 0;
+	return &priv->t;
 
 unregister_cdev:
 	class_device_unregister(&priv->cdev);
 free_priv:
 	kfree(priv);
-	return err;
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(iscsi_register_transport);
 
@@ -1159,19 +1204,11 @@
 
 	BUG_ON(!tt);
 
-	down(&rx_queue_sema);
+	mutex_lock(&rx_queue_mutex);
 
 	priv = iscsi_if_transport_lookup(tt);
 	BUG_ON (!priv);
 
-	spin_lock_irqsave(&priv->session_lock, flags);
-	if (!list_empty(&priv->sessions)) {
-		spin_unlock_irqrestore(&priv->session_lock, flags);
-		up(&rx_queue_sema);
-		return -EPERM;
-	}
-	spin_unlock_irqrestore(&priv->session_lock, flags);
-
 	spin_lock_irqsave(&iscsi_transport_lock, flags);
 	list_del(&priv->list);
 	spin_unlock_irqrestore(&iscsi_transport_lock, flags);
@@ -1181,7 +1218,7 @@
 
 	sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
 	class_device_unregister(&priv->cdev);
-	up(&rx_queue_sema);
+	mutex_unlock(&rx_queue_mutex);
 
 	return 0;
 }
@@ -1194,14 +1231,14 @@
 
 	if (event == NETLINK_URELEASE &&
 	    n->protocol == NETLINK_ISCSI && n->pid) {
-		struct iscsi_if_conn *conn;
+		struct iscsi_cls_conn *conn;
 		unsigned long flags;
 
-		mempool_zone_complete(&z_reply);
+		mempool_zone_complete(z_reply);
 		spin_lock_irqsave(&connlock, flags);
 		list_for_each_entry(conn, &connlist, conn_list) {
-			mempool_zone_complete(&conn->z_error);
-			mempool_zone_complete(&conn->z_pdu);
+			mempool_zone_complete(conn->z_error);
+			mempool_zone_complete(conn->z_pdu);
 		}
 		spin_unlock_irqrestore(&connlock, flags);
 	}
@@ -1234,15 +1271,15 @@
 		goto unregister_session_class;
 
 	nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
-				    THIS_MODULE);
+			THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
 		goto unregister_notifier;
 	}
 
-	err = mempool_zone_init(&z_reply, Z_MAX_REPLY,
+	z_reply = mempool_zone_init(Z_MAX_REPLY,
 		NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
-	if (!err)
+	if (z_reply)
 		return 0;
 
 	sock_release(nls->sk_socket);
@@ -1259,7 +1296,7 @@
 
 static void __exit iscsi_transport_exit(void)
 {
-	mempool_destroy(z_reply.pool);
+	mempool_zone_destroy(z_reply);
 	sock_release(nls->sk_socket);
 	netlink_unregister_notifier(&iscsi_nl_notifier);
 	transport_class_unregister(&iscsi_connection_class);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index edabbd0..a3e0b7b 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
@@ -62,7 +63,7 @@
 
 struct sas_host_attrs {
 	struct list_head rphy_list;
-	spinlock_t lock;
+	struct mutex lock;
 	u32 next_target_id;
 };
 #define to_sas_host_attrs(host)	((struct sas_host_attrs *)(host)->shost_data)
@@ -165,7 +166,7 @@
 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
 	INIT_LIST_HEAD(&sas_host->rphy_list);
-	spin_lock_init(&sas_host->lock);
+	mutex_init(&sas_host->lock);
 	sas_host->next_target_id = 0;
 	return 0;
 }
@@ -626,7 +627,7 @@
 	transport_add_device(&rphy->dev);
 	transport_configure_device(&rphy->dev);
 
-	spin_lock(&sas_host->lock);
+	mutex_lock(&sas_host->lock);
 	list_add_tail(&rphy->list, &sas_host->rphy_list);
 	if (identify->device_type == SAS_END_DEVICE &&
 	    (identify->target_port_protocols &
@@ -634,10 +635,10 @@
 		rphy->scsi_target_id = sas_host->next_target_id++;
 	else
 		rphy->scsi_target_id = -1;
-	spin_unlock(&sas_host->lock);
+	mutex_unlock(&sas_host->lock);
 
 	if (rphy->scsi_target_id != -1) {
-		scsi_scan_target(&rphy->dev, parent->number,
+		scsi_scan_target(&rphy->dev, parent->port_identifier,
 				rphy->scsi_target_id, ~0, 0);
 	}
 
@@ -661,9 +662,9 @@
 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
-	spin_lock(&sas_host->lock);
+	mutex_lock(&sas_host->lock);
 	list_del(&rphy->list);
-	spin_unlock(&sas_host->lock);
+	mutex_unlock(&sas_host->lock);
 
 	transport_destroy_device(&rphy->dev);
 	put_device(rphy->dev.parent);
@@ -687,15 +688,27 @@
 	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
-	scsi_remove_target(dev);
+	switch (rphy->identify.device_type) {
+	case SAS_END_DEVICE:
+		scsi_remove_target(dev);
+		break;
+	case SAS_EDGE_EXPANDER_DEVICE:
+	case SAS_FANOUT_EXPANDER_DEVICE:
+		device_for_each_child(dev, NULL, do_sas_phy_delete);
+		break;
+	default:
+		break;
+	}
 
 	transport_remove_device(dev);
 	device_del(dev);
 	transport_destroy_device(dev);
 
-	spin_lock(&sas_host->lock);
+	mutex_lock(&sas_host->lock);
 	list_del(&rphy->list);
-	spin_unlock(&sas_host->lock);
+	mutex_unlock(&sas_host->lock);
+
+	parent->rphy = NULL;
 
 	put_device(&parent->dev);
 }
@@ -719,23 +732,28 @@
  * SCSI scan helper
  */
 
-static struct device *sas_target_parent(struct Scsi_Host *shost,
-					int channel, uint id)
+static int sas_user_scan(struct Scsi_Host *shost, uint channel,
+		uint id, uint lun)
 {
 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 	struct sas_rphy *rphy;
-	struct device *dev = NULL;
 
-	spin_lock(&sas_host->lock);
+	mutex_lock(&sas_host->lock);
 	list_for_each_entry(rphy, &sas_host->rphy_list, list) {
 		struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
-		if (parent->number == channel &&
-		    rphy->scsi_target_id == id)
-			dev = &rphy->dev;
-	}
-	spin_unlock(&sas_host->lock);
 
-	return dev;
+		if (rphy->scsi_target_id == -1)
+			continue;
+
+		if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
+		    (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
+			scsi_scan_target(&rphy->dev, parent->port_identifier,
+					 rphy->scsi_target_id, lun, 1);
+		}
+	}
+	mutex_unlock(&sas_host->lock);
+
+	return 0;
 }
 
 
@@ -780,7 +798,7 @@
 		return NULL;
 	memset(i, 0, sizeof(struct sas_internal));
 
-	i->t.target_parent = sas_target_parent;
+	i->t.user_scan = sas_user_scan;
 
 	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
 	i->t.host_attrs.ac.class = &sas_host_class.class;
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 46da6fe..7ee95eb 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -24,7 +24,7 @@
 #include <linux/module.h>
 #include <linux/workqueue.h>
 #include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 #include <scsi/scsi_device.h>
@@ -48,7 +48,7 @@
 
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
-#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
+#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
 
 struct spi_internal {
 	struct scsi_transport_template t;
@@ -242,7 +242,7 @@
 	spi_hold_mcs(starget) = 0;
 	spi_dv_pending(starget) = 0;
 	spi_initial_dv(starget) = 0;
-	init_MUTEX(&spi_dv_sem(starget));
+	mutex_init(&spi_dv_mutex(starget));
 
 	return 0;
 }
@@ -915,7 +915,7 @@
 	scsi_target_quiesce(starget);
 
 	spi_dv_pending(starget) = 1;
-	down(&spi_dv_sem(starget));
+	mutex_lock(&spi_dv_mutex(starget));
 
 	starget_printk(KERN_INFO, starget, "Beginning Domain Validation\n");
 
@@ -923,7 +923,7 @@
 
 	starget_printk(KERN_INFO, starget, "Ending Domain Validation\n");
 
-	up(&spi_dv_sem(starget));
+	mutex_unlock(&spi_dv_mutex(starget));
 	spi_dv_pending(starget) = 0;
 
 	scsi_target_resume(starget);
@@ -1075,7 +1075,7 @@
 /* 0x04 */ "Parallel Protocol Request"
 };
 
-void print_nego(const unsigned char *msg, int per, int off, int width)
+static void print_nego(const unsigned char *msg, int per, int off, int width)
 {
 	if (per) {
 		char buf[20];
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 4c5127e..930db39 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -49,6 +49,7 @@
 #include <linux/blkpg.h>
 #include <linux/kref.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -111,7 +112,7 @@
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * object after last put) */
-static DECLARE_MUTEX(sd_ref_sem);
+static DEFINE_MUTEX(sd_ref_mutex);
 
 static int sd_revalidate_disk(struct gendisk *disk);
 static void sd_rw_intr(struct scsi_cmnd * SCpnt);
@@ -193,9 +194,9 @@
 {
 	struct scsi_disk *sdkp;
 
-	down(&sd_ref_sem);
+	mutex_lock(&sd_ref_mutex);
 	sdkp = __scsi_disk_get(disk);
-	up(&sd_ref_sem);
+	mutex_unlock(&sd_ref_mutex);
 	return sdkp;
 }
 
@@ -203,11 +204,11 @@
 {
 	struct scsi_disk *sdkp;
 
-	down(&sd_ref_sem);
+	mutex_lock(&sd_ref_mutex);
 	sdkp = dev_get_drvdata(dev);
 	if (sdkp)
 		sdkp = __scsi_disk_get(sdkp->disk);
-	up(&sd_ref_sem);
+	mutex_unlock(&sd_ref_mutex);
 	return sdkp;
 }
 
@@ -215,10 +216,10 @@
 {
 	struct scsi_device *sdev = sdkp->device;
 
-	down(&sd_ref_sem);
+	mutex_lock(&sd_ref_mutex);
 	kref_put(&sdkp->kref, scsi_disk_release);
 	scsi_device_put(sdev);
-	up(&sd_ref_sem);
+	mutex_unlock(&sd_ref_mutex);
 }
 
 /**
@@ -231,34 +232,12 @@
  **/
 static int sd_init_command(struct scsi_cmnd * SCpnt)
 {
-	unsigned int this_count, timeout;
-	struct gendisk *disk;
-	sector_t block;
 	struct scsi_device *sdp = SCpnt->device;
 	struct request *rq = SCpnt->request;
-
-	timeout = sdp->timeout;
-
-	/*
-	 * SG_IO from block layer already setup, just copy cdb basically
-	 */
-	if (blk_pc_request(rq)) {
-		scsi_setup_blk_pc_cmnd(SCpnt);
-		if (rq->timeout)
-			timeout = rq->timeout;
-
-		goto queue;
-	}
-
-	/*
-	 * we only do REQ_CMD and REQ_BLOCK_PC
-	 */
-	if (!blk_fs_request(rq))
-		return 0;
-
-	disk = rq->rq_disk;
-	block = rq->sector;
-	this_count = SCpnt->request_bufflen >> 9;
+	struct gendisk *disk = rq->rq_disk;
+	sector_t block = rq->sector;
+	unsigned int this_count = SCpnt->request_bufflen >> 9;
+	unsigned int timeout = sdp->timeout;
 
 	SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
 			    "count=%d\n", disk->disk_name,
@@ -401,8 +380,6 @@
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-
-queue:
 	SCpnt->timeout_per_command = timeout;
 
 	/*
@@ -836,15 +813,7 @@
 	   relatively rare error condition, no care is taken to avoid
 	   unnecessary additional work such as memcpy's that could be avoided.
 	 */
-
-	/* 
-	 * If SG_IO from block layer then set good_bytes to stop retries;
-	 * else if errors, check them, and if necessary prepare for
-	 * (partial) retries.
-	 */
-	if (blk_pc_request(SCpnt->request))
-		good_bytes = this_count;
-	else if (driver_byte(result) != 0 &&
+	if (driver_byte(result) != 0 &&
 		 sense_valid && !sense_deferred) {
 		switch (sshdr.sense_key) {
 		case MEDIUM_ERROR:
@@ -1635,10 +1604,10 @@
 	del_gendisk(sdkp->disk);
 	sd_shutdown(dev);
 
-	down(&sd_ref_sem);
+	mutex_lock(&sd_ref_mutex);
 	dev_set_drvdata(dev, NULL);
 	kref_put(&sdkp->kref, scsi_disk_release);
-	up(&sd_ref_sem);
+	mutex_unlock(&sd_ref_mutex);
 
 	return 0;
 }
@@ -1647,7 +1616,7 @@
  *	scsi_disk_release - Called to free the scsi_disk structure
  *	@kref: pointer to embedded kref
  *
- *	sd_ref_sem must be held entering this routine.  Because it is
+ *	sd_ref_mutex must be held entering this routine.  Because it is
  *	called on last put, you should always use the scsi_disk_get()
  *	scsi_disk_put() helpers which manipulate the semaphore directly
  *	and never do a direct kref_put().
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index a4d9be7..997f8e3 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -44,6 +44,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -90,7 +91,7 @@
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * object after last put) */
-static DECLARE_MUTEX(sr_ref_sem);
+static DEFINE_MUTEX(sr_ref_mutex);
 
 static int sr_open(struct cdrom_device_info *, int);
 static void sr_release(struct cdrom_device_info *);
@@ -133,7 +134,7 @@
 {
 	struct scsi_cd *cd = NULL;
 
-	down(&sr_ref_sem);
+	mutex_lock(&sr_ref_mutex);
 	if (disk->private_data == NULL)
 		goto out;
 	cd = scsi_cd(disk);
@@ -146,18 +147,18 @@
 	kref_put(&cd->kref, sr_kref_release);
 	cd = NULL;
  out:
-	up(&sr_ref_sem);
+	mutex_unlock(&sr_ref_mutex);
 	return cd;
 }
 
-static inline void scsi_cd_put(struct scsi_cd *cd)
+static void scsi_cd_put(struct scsi_cd *cd)
 {
 	struct scsi_device *sdev = cd->device;
 
-	down(&sr_ref_sem);
+	mutex_lock(&sr_ref_mutex);
 	kref_put(&cd->kref, sr_kref_release);
 	scsi_device_put(sdev);
-	up(&sr_ref_sem);
+	mutex_unlock(&sr_ref_mutex);
 }
 
 /*
@@ -237,8 +238,6 @@
 		case ILLEGAL_REQUEST:
 			if (!(SCpnt->sense_buffer[0] & 0x90))
 				break;
-			if (!blk_fs_request(SCpnt->request))
-				break;
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
 				(SCpnt->sense_buffer[4] << 16) |
 				(SCpnt->sense_buffer[5] << 8) |
@@ -317,23 +316,6 @@
 	}
 
 	/*
-	 * these are already setup, just copy cdb basically
-	 */
-	if (SCpnt->request->flags & REQ_BLOCK_PC) {
-		scsi_setup_blk_pc_cmnd(SCpnt);
-
-		if (SCpnt->timeout_per_command)
-			timeout = SCpnt->timeout_per_command;
-
-		goto queue;
-	}
-
-	if (!(SCpnt->request->flags & REQ_CMD)) {
-		blk_dump_rq_flags(SCpnt->request, "sr unsup command");
-		return 0;
-	}
-
-	/*
 	 * we do lazy blocksize switching (when reading XA sectors,
 	 * see CDROMREADMODE2 ioctl) 
 	 */
@@ -421,8 +403,6 @@
 	 */
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
-
-queue:
 	SCpnt->allowed = MAX_RETRIES;
 	SCpnt->timeout_per_command = timeout;
 
@@ -762,8 +742,9 @@
 		/* failed, drive doesn't have capabilities mode page */
 		cd->cdi.speed = 1;
 		cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
-					 CDC_DVD | CDC_DVD_RAM |
-					 CDC_SELECT_DISC | CDC_SELECT_SPEED);
+				 CDC_DVD | CDC_DVD_RAM |
+				 CDC_SELECT_DISC | CDC_SELECT_SPEED |
+				 CDC_MRW | CDC_MRW_W | CDC_RAM);
 		kfree(buffer);
 		printk("%s: scsi-1 drive\n", cd->cdi.name);
 		return;
@@ -845,7 +826,7 @@
  *	sr_kref_release - Called to free the scsi_cd structure
  *	@kref: pointer to embedded kref
  *
- *	sr_ref_sem must be held entering this routine.  Because it is
+ *	sr_ref_mutex must be held entering this routine.  Because it is
  *	called on last put, you should always use the scsi_cd_get()
  *	scsi_cd_put() helpers which manipulate the semaphore directly
  *	and never do a direct kref_put().
@@ -874,9 +855,9 @@
 
 	del_gendisk(cd->disk);
 
-	down(&sr_ref_sem);
+	mutex_lock(&sr_ref_mutex);
 	kref_put(&cd->kref, sr_kref_release);
-	up(&sr_ref_sem);
+	mutex_unlock(&sr_ref_mutex);
 
 	return 0;
 }
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 6e45ac3..5d02ff4 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -31,6 +31,79 @@
 
 module_param(xa_test, int, S_IRUGO | S_IWUSR);
 
+/* primitive to determine whether we need to have GFP_DMA set based on
+ * the status of the unchecked_isa_dma flag in the host structure */
+#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
+
+
+static int sr_read_tochdr(struct cdrom_device_info *cdi,
+		struct cdrom_tochdr *tochdr)
+{
+	struct scsi_cd *cd = cdi->handle;
+	struct packet_command cgc;
+	int result;
+	unsigned char *buffer;
+
+	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+	if (!buffer)
+		return -ENOMEM;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.timeout = IOCTL_TIMEOUT;
+	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+	cgc.cmd[8] = 12;		/* LSB of length */
+	cgc.buffer = buffer;
+	cgc.buflen = 12;
+	cgc.quiet = 1;
+	cgc.data_direction = DMA_FROM_DEVICE;
+
+	result = sr_do_ioctl(cd, &cgc);
+
+	tochdr->cdth_trk0 = buffer[2];
+	tochdr->cdth_trk1 = buffer[3];
+
+	kfree(buffer);
+	return result;
+}
+
+static int sr_read_tocentry(struct cdrom_device_info *cdi,
+		struct cdrom_tocentry *tocentry)
+{
+	struct scsi_cd *cd = cdi->handle;
+	struct packet_command cgc;
+	int result;
+	unsigned char *buffer;
+
+	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+	if (!buffer)
+		return -ENOMEM;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.timeout = IOCTL_TIMEOUT;
+	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+	cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
+	cgc.cmd[6] = tocentry->cdte_track;
+	cgc.cmd[8] = 12;		/* LSB of length */
+	cgc.buffer = buffer;
+	cgc.buflen = 12;
+	cgc.data_direction = DMA_FROM_DEVICE;
+
+	result = sr_do_ioctl(cd, &cgc);
+
+	tocentry->cdte_ctrl = buffer[5] & 0xf;
+	tocentry->cdte_adr = buffer[5] >> 4;
+	tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+	if (tocentry->cdte_format == CDROM_MSF) {
+		tocentry->cdte_addr.msf.minute = buffer[9];
+		tocentry->cdte_addr.msf.second = buffer[10];
+		tocentry->cdte_addr.msf.frame = buffer[11];
+	} else
+		tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+			+ buffer[10]) << 8) + buffer[11];
+
+	kfree(buffer);
+	return result;
+}
 
 #define IOCTL_RETRIES 3
 
@@ -45,7 +118,8 @@
 	struct packet_command cgc;
 	int ntracks, ret;
 
-	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
+	ret = sr_read_tochdr(cdi, &tochdr);
+	if (ret)
 		return ret;
 
 	ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
@@ -60,9 +134,11 @@
 	trk1_te.cdte_track = ti->cdti_trk1;
 	trk1_te.cdte_format = CDROM_MSF;
 	
-	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk0_te)))
+	ret = sr_read_tocentry(cdi, &trk0_te);
+	if (ret)
 		return ret;
-	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
+	ret = sr_read_tocentry(cdi, &trk1_te);
+	if (ret)
 		return ret;
 
 	memset(&cgc, 0, sizeof(struct packet_command));
@@ -78,6 +154,30 @@
 	return sr_do_ioctl(cdi->handle, &cgc);
 }
 
+static int sr_play_trkind(struct cdrom_device_info *cdi,
+		struct cdrom_ti *ti)
+
+{
+	struct scsi_cd *cd = cdi->handle;
+	struct packet_command cgc;
+	int result;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.timeout = IOCTL_TIMEOUT;
+	cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
+	cgc.cmd[4] = ti->cdti_trk0;
+	cgc.cmd[5] = ti->cdti_ind0;
+	cgc.cmd[7] = ti->cdti_trk1;
+	cgc.cmd[8] = ti->cdti_ind1;
+	cgc.data_direction = DMA_NONE;
+
+	result = sr_do_ioctl(cd, &cgc);
+	if (result == -EDRIVE_CANT_DO_THIS)
+		result = sr_fake_playtrkind(cdi, ti);
+
+	return result;
+}
+
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
@@ -229,13 +329,14 @@
 	int i, rc, have_datatracks = 0;
 
 	/* look for data tracks */
-	if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+	rc = sr_read_tochdr(cdi, &toc_h);
+	if (rc)
 		return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
 
 	for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
 		toc_e.cdte_track = i;
 		toc_e.cdte_format = CDROM_LBA;
-		if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
+		if (sr_read_tocentry(cdi, &toc_e))
 			return CDS_NO_INFO;
 		if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
 			have_datatracks = 1;
@@ -262,10 +363,6 @@
 	return 0;
 }
 
-/* primitive to determine whether we need to have GFP_DMA set based on
- * the status of the unchecked_isa_dma flag in the host structure */
-#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
-
 int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
 	Scsi_CD *cd = cdi->handle;
@@ -329,93 +426,16 @@
 
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
-	Scsi_CD *cd = cdi->handle;
-	struct packet_command cgc;
-	int result;
-	unsigned char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
-
-	if (!buffer)
-		return -ENOMEM;
-
-	memset(&cgc, 0, sizeof(struct packet_command));
-	cgc.timeout = IOCTL_TIMEOUT;
-
 	switch (cmd) {
 	case CDROMREADTOCHDR:
-		{
-			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
-
-			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			cgc.cmd[8] = 12;		/* LSB of length */
-			cgc.buffer = buffer;
-			cgc.buflen = 12;
-			cgc.quiet = 1;
-			cgc.data_direction = DMA_FROM_DEVICE;
-
-			result = sr_do_ioctl(cd, &cgc);
-
-			tochdr->cdth_trk0 = buffer[2];
-			tochdr->cdth_trk1 = buffer[3];
-
-			break;
-		}
-
+		return sr_read_tochdr(cdi, arg);
 	case CDROMREADTOCENTRY:
-		{
-			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
-
-			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
-			cgc.cmd[6] = tocentry->cdte_track;
-			cgc.cmd[8] = 12;		/* LSB of length */
-			cgc.buffer = buffer;
-			cgc.buflen = 12;
-			cgc.data_direction = DMA_FROM_DEVICE;
-
-			result = sr_do_ioctl(cd, &cgc);
-
-			tocentry->cdte_ctrl = buffer[5] & 0xf;
-			tocentry->cdte_adr = buffer[5] >> 4;
-			tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
-			if (tocentry->cdte_format == CDROM_MSF) {
-				tocentry->cdte_addr.msf.minute = buffer[9];
-				tocentry->cdte_addr.msf.second = buffer[10];
-				tocentry->cdte_addr.msf.frame = buffer[11];
-			} else
-				tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
-					+ buffer[10]) << 8) + buffer[11];
-
-			break;
-		}
-
-	case CDROMPLAYTRKIND: {
-		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
-
-		cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
-		cgc.cmd[4] = ti->cdti_trk0;
-		cgc.cmd[5] = ti->cdti_ind0;
-		cgc.cmd[7] = ti->cdti_trk1;
-		cgc.cmd[8] = ti->cdti_ind1;
-		cgc.data_direction = DMA_NONE;
-
-		result = sr_do_ioctl(cd, &cgc);
-		if (result == -EDRIVE_CANT_DO_THIS)
-			result = sr_fake_playtrkind(cdi, ti);
-
-		break;
-	}
-
+		return sr_read_tocentry(cdi, arg);
+	case CDROMPLAYTRKIND:
+		return sr_play_trkind(cdi, arg);
 	default:
-		result = -EINVAL;
+		return -EINVAL;
 	}
-
-#if 0
-	if (result)
-		printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
-#endif
-
-	kfree(buffer);
-	return result;
 }
 
 /* -----------------------------------------------------------------------
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index c4aade8..13b1d3a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -38,6 +38,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/cdev.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/dma.h>
@@ -193,7 +194,6 @@
 
 static int st_probe(struct device *);
 static int st_remove(struct device *);
-static int st_init_command(struct scsi_cmnd *);
 
 static void do_create_driverfs_files(void);
 static void do_remove_driverfs_files(void);
@@ -206,7 +206,6 @@
 		.probe		= st_probe,
 		.remove		= st_remove,
 	},
-	.init_command		= st_init_command,
 };
 
 static int st_compression(struct scsi_tape *, int);
@@ -220,7 +219,7 @@
 
 #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
 
-static DECLARE_MUTEX(st_ref_sem);
+static DEFINE_MUTEX(st_ref_mutex);
 
 
 #include "osst_detect.h"
@@ -237,7 +236,7 @@
 {
 	struct scsi_tape *STp = NULL;
 
-	down(&st_ref_sem);
+	mutex_lock(&st_ref_mutex);
 	write_lock(&st_dev_arr_lock);
 
 	if (dev < st_dev_max && scsi_tapes != NULL)
@@ -259,7 +258,7 @@
 	STp = NULL;
 out:
 	write_unlock(&st_dev_arr_lock);
-	up(&st_ref_sem);
+	mutex_unlock(&st_ref_mutex);
 	return STp;
 }
 
@@ -267,10 +266,10 @@
 {
 	struct scsi_device *sdev = STp->device;
 
-	down(&st_ref_sem);
+	mutex_lock(&st_ref_mutex);
 	kref_put(&STp->kref, scsi_tape_release);
 	scsi_device_put(sdev);
-	up(&st_ref_sem);
+	mutex_unlock(&st_ref_mutex);
 }
 
 struct st_reject_data {
@@ -4141,9 +4140,9 @@
 				}
 			}
 
-			down(&st_ref_sem);
+			mutex_lock(&st_ref_mutex);
 			kref_put(&tpnt->kref, scsi_tape_release);
-			up(&st_ref_sem);
+			mutex_unlock(&st_ref_mutex);
 			return 0;
 		}
 	}
@@ -4156,7 +4155,7 @@
  *      scsi_tape_release - Called to free the Scsi_Tape structure
  *      @kref: pointer to embedded kref
  *
- *      st_ref_sem must be held entering this routine.  Because it is
+ *      st_ref_mutex must be held entering this routine.  Because it is
  *      called on last put, you should always use the scsi_tape_get()
  *      scsi_tape_put() helpers which manipulate the semaphore directly
  *      and never do a direct kref_put().
@@ -4180,29 +4179,6 @@
 	return;
 }
 
-static void st_intr(struct scsi_cmnd *SCpnt)
-{
-	/*
-	 * The caller should be checking the request's errors
-	 * value.
-	 */
-	scsi_io_completion(SCpnt, SCpnt->bufflen, 0);
-}
-
-/*
- * st_init_command: only called via the scsi_cmd_ioctl (block SG_IO)
- * interface for REQ_BLOCK_PC commands.
- */
-static int st_init_command(struct scsi_cmnd *SCpnt)
-{
-	if (!(SCpnt->request->flags & REQ_BLOCK_PC))
-		return 0;
-
-	scsi_setup_blk_pc_cmnd(SCpnt);
-	SCpnt->done = st_intr;
-	return 1;
-}
-
 static int __init init_st(void)
 {
 	validate_options();
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 4dd5c3f..8cbf0fc 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -143,7 +143,6 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
-DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct m68k_serial *info,
 					char *name, const char *routine)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6627dda..5e7199f 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -190,7 +190,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called 8250_boca.
 
-
 config SERIAL_8250_HUB6
 	tristate "Support Hub6 cards"
 	depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
@@ -917,4 +916,12 @@
 		and wish to use the serial ports on this card, say Y.
 		Otherwise, say N.
 
+config SERIAL_SGI_IOC3
+	tristate "SGI Altix IOC3 serial support"
+	depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
+	select SERIAL_CORE
+	help
+	  If you have an SGI Altix with an IOC3 serial card,
+	  say Y or M.  Otherwise, say N.
+
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 24a583e..eaf8e01 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -56,4 +56,5 @@
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 5c098be..587cc6a 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -499,7 +499,7 @@
 		ucr2 |= UCR2_STPB;
 	if (termios->c_cflag & PARENB) {
 		ucr2 |= UCR2_PREN;
-		if (!(termios->c_cflag & PARODD))
+		if (termios->c_cflag & PARODD)
 			ucr2 |= UCR2_PROE;
 	}
 
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
new file mode 100644
index 0000000..8097cd9
--- /dev/null
+++ b/drivers/serial/ioc3_serial.c
@@ -0,0 +1,2197 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * This file contains a module version of the ioc3 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/ioc3.h>
+
+/*
+ * Interesting things about the ioc3
+ */
+
+#define LOGICAL_PORTS		2	/* rs232(0) and rs422(1) */
+#define PORTS_PER_CARD		2
+#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
+#define MAX_CARDS		8
+#define MAX_LOGICAL_PORTS	(LOGICAL_PORTS_PER_CARD * MAX_CARDS)
+
+/* determine given the sio_ir what port it applies to */
+#define GET_PORT_FROM_SIO_IR(_x)	(_x & SIO_IR_SA) ? 0 : 1
+
+
+/*
+ * we have 2 logical ports (rs232, rs422) for each physical port
+ * evens are rs232, odds are rs422
+ */
+#define GET_PHYSICAL_PORT(_x)	((_x) >> 1)
+#define GET_LOGICAL_PORT(_x)	((_x) & 1)
+#define IS_PHYSICAL_PORT(_x)	!((_x) & 1)
+#define IS_RS232(_x)		!((_x) & 1)
+
+static unsigned int Num_of_ioc3_cards;
+static unsigned int Submodule_slot;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)	;
+//#define DPRINT_CONFIG(_x...)  printk _x
+#define NOT_PROGRESS()	;
+//#define NOT_PROGRESS()	printk("%s : fails %d\n", __FUNCTION__, __LINE__)
+
+/* number of characters we want to transmit to the lower level at a time */
+#define MAX_CHARS		256
+#define FIFO_SIZE		(MAX_CHARS-1)	/* it's a uchar */
+
+/* Device name we're using */
+#define DEVICE_NAME		"ttySIOC"
+#define DEVICE_MAJOR		204
+#define DEVICE_MINOR		116
+
+/* flags for next_char_state */
+#define NCS_BREAK		0x1
+#define NCS_PARITY		0x2
+#define NCS_FRAMING		0x4
+#define NCS_OVERRUN		0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED	1200
+#define MAX_BAUD_SUPPORTED	115200
+
+/* protocol types supported */
+#define PROTO_RS232		0
+#define PROTO_RS422		1
+
+/* Notification types */
+#define N_DATA_READY		0x01
+#define N_OUTPUT_LOWAT		0x02
+#define N_BREAK			0x04
+#define N_PARITY_ERROR		0x08
+#define N_FRAMING_ERROR		0x10
+#define N_OVERRUN_ERROR		0x20
+#define N_DDCD			0x40
+#define N_DCTS			0x80
+
+#define N_ALL_INPUT		(N_DATA_READY | N_BREAK			   \
+					| N_PARITY_ERROR | N_FRAMING_ERROR \
+					| N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT		N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS		(N_PARITY_ERROR | N_FRAMING_ERROR \
+						| N_OVERRUN_ERROR)
+
+#define N_ALL			(N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
+					| N_PARITY_ERROR | N_FRAMING_ERROR  \
+					| N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_CLK_SPEED(prediv)	((22000000 << 1) / prediv)
+#define SER_DIVISOR(x, clk)	(((clk) + (x) * 8) / ((x) * 16))
+#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR	(UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+					| UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS	(UART_LCR_STOP)
+
+#define PENDING(_a, _p)		(readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
+
+#define RING_BUF_SIZE		4096
+#define BUF_SIZE_BIT		SBBR_L_SIZE
+#define PROD_CONS_MASK		PROD_CONS_PTR_4K
+
+#define TOTAL_RING_BUF_SIZE	(RING_BUF_SIZE * 4)
+
+/* driver specific - one per card */
+struct ioc3_card {
+	struct {
+		/* uart ports are allocated here */
+		struct uart_port icp_uart_port[LOGICAL_PORTS];
+		/* the ioc3_port used for this port */
+		struct ioc3_port *icp_port;
+	} ic_port[PORTS_PER_CARD];
+	/* currently enabled interrupts */
+	uint32_t ic_enable;
+};
+
+/* Local port info for each IOC3 serial port */
+struct ioc3_port {
+	/* handy reference material */
+	struct uart_port *ip_port;
+	struct ioc3_card *ip_card;
+	struct ioc3_driver_data *ip_idd;
+	struct ioc3_submodule *ip_is;
+
+	/* pci mem addresses for this port */
+	struct ioc3_serialregs __iomem *ip_serial_regs;
+	struct ioc3_uartregs __iomem *ip_uart_regs;
+
+	/* Ring buffer page for this port */
+	dma_addr_t ip_dma_ringbuf;
+	/* vaddr of ring buffer */
+	struct ring_buffer *ip_cpu_ringbuf;
+
+	/* Rings for this port */
+	struct ring *ip_inring;
+	struct ring *ip_outring;
+
+	/* Hook to port specific values */
+	struct port_hooks *ip_hooks;
+
+	spinlock_t ip_lock;
+
+	/* Various rx/tx parameters */
+	int ip_baud;
+	int ip_tx_lowat;
+	int ip_rx_timeout;
+
+	/* Copy of notification bits */
+	int ip_notify;
+
+	/* Shadow copies of various registers so we don't need to PIO
+	 * read them constantly
+	 */
+	uint32_t ip_sscr;
+	uint32_t ip_tx_prod;
+	uint32_t ip_rx_cons;
+	unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH		0x01
+	/* used to signify that we have turned off the rx_high
+	 * temporarily - we need to drain the fifo and don't
+	 * want to get blasted with interrupts.
+	 */
+#define DCD_ON			0x02
+	/* DCD state is on */
+#define LOWAT_WRITTEN		0x04
+#define READ_ABORTED		0x08
+	/* the read was aborted - used to avaoid infinate looping
+	 * in the interrupt handler
+	 */
+#define INPUT_ENABLE		0x10
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct port_hooks {
+	uint32_t intr_delta_dcd;
+	uint32_t intr_delta_cts;
+	uint32_t intr_tx_mt;
+	uint32_t intr_rx_timer;
+	uint32_t intr_rx_high;
+	uint32_t intr_tx_explicit;
+	uint32_t intr_clear;
+	uint32_t intr_all;
+	char rs422_select_pin;
+};
+
+static struct port_hooks hooks_array[PORTS_PER_CARD] = {
+	/* values for port A */
+	{
+	.intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
+	.intr_delta_cts = SIO_IR_SA_DELTA_CTS,
+	.intr_tx_mt = SIO_IR_SA_TX_MT,
+	.intr_rx_timer = SIO_IR_SA_RX_TIMER,
+	.intr_rx_high = SIO_IR_SA_RX_HIGH,
+	.intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
+	.intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
+				| SIO_IR_SA_RX_HIGH
+				| SIO_IR_SA_RX_TIMER
+				| SIO_IR_SA_DELTA_DCD
+				| SIO_IR_SA_DELTA_CTS
+				| SIO_IR_SA_INT
+				| SIO_IR_SA_TX_EXPLICIT
+				| SIO_IR_SA_MEMERR),
+	.intr_all =  SIO_IR_SA,
+	.rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
+	 },
+
+	/* values for port B */
+	{
+	.intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
+	.intr_delta_cts = SIO_IR_SB_DELTA_CTS,
+	.intr_tx_mt = SIO_IR_SB_TX_MT,
+	.intr_rx_timer = SIO_IR_SB_RX_TIMER,
+	.intr_rx_high = SIO_IR_SB_RX_HIGH,
+	.intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
+	.intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
+				| SIO_IR_SB_RX_HIGH
+				| SIO_IR_SB_RX_TIMER
+				| SIO_IR_SB_DELTA_DCD
+				| SIO_IR_SB_DELTA_CTS
+				| SIO_IR_SB_INT
+				| SIO_IR_SB_TX_EXPLICIT
+				| SIO_IR_SB_MEMERR),
+	.intr_all = SIO_IR_SB,
+	.rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
+	 }
+};
+
+struct ring_entry {
+	union {
+		struct {
+			uint32_t alldata;
+			uint32_t allsc;
+		} all;
+		struct {
+			char data[4];	/* data bytes */
+			char sc[4];	/* status/control */
+		} s;
+	} u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+	((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc		u.s.sc
+#define ring_data	u.s.data
+#define ring_allsc	u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+	struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+	struct ring TX_A;
+	struct ring RX_A;
+	struct ring TX_B;
+	struct ring RX_B;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)	&(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* for Infinite loop detection  */
+#define MAXITER		10000000
+
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc3_port *port, int baud)
+{
+	int divisor;
+	int actual_baud;
+	int diff;
+	int lcr, prediv;
+	struct ioc3_uartregs __iomem *uart;
+
+	for (prediv = 6; prediv < 64; prediv++) {
+		divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
+		if (!divisor)
+			continue;	/* invalid divisor */
+		actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
+
+		diff = actual_baud - baud;
+		if (diff < 0)
+			diff = -diff;
+
+		/* if we're within 1% we've found a match */
+		if (diff * 100 <= actual_baud)
+			break;
+	}
+
+	/* if the above loop completed, we didn't match
+	 * the baud rate.  give up.
+	 */
+	if (prediv == 64) {
+		NOT_PROGRESS();
+		return 1;
+	}
+
+	uart = port->ip_uart_regs;
+	lcr = readb(&uart->iu_lcr);
+
+	writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
+	writeb((unsigned char)divisor, &uart->iu_dll);
+	writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
+	writeb((unsigned char)prediv, &uart->iu_scr);
+	writeb((unsigned char)lcr, &uart->iu_lcr);
+
+	return 0;
+}
+
+/**
+ * get_ioc3_port - given a uart port, return the control structure
+ * @the_port: uart port to find
+ */
+static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
+{
+	struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
+	struct ioc3_card *card_ptr = idd->data[Submodule_slot];
+	int ii, jj;
+
+	if (!card_ptr) {
+		NOT_PROGRESS();
+		return NULL;
+	}
+	for (ii = 0; ii < PORTS_PER_CARD; ii++) {
+		for (jj = 0; jj < LOGICAL_PORTS; jj++) {
+			if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
+				return card_ptr->ic_port[ii].icp_port;
+		}
+	}
+	NOT_PROGRESS();
+	return NULL;
+}
+
+/**
+ * port_init - Initialize the sio and ioc3 hardware for a given port
+ *			called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc3_port *port)
+{
+	uint32_t sio_cr;
+	struct port_hooks *hooks = port->ip_hooks;
+	struct ioc3_uartregs __iomem *uart;
+	int reset_loop_counter = 0xfffff;
+	struct ioc3_driver_data *idd = port->ip_idd;
+
+	/* Idle the IOC3 serial interface */
+	writel(SSCR_RESET, &port->ip_serial_regs->sscr);
+
+	/* Wait until any pending bus activity for this port has ceased */
+	do {
+		sio_cr = readl(&idd->vma->sio_cr);
+		if (reset_loop_counter-- <= 0) {
+			printk(KERN_WARNING
+			       "IOC3 unable to come out of reset"
+				" scr 0x%x\n", sio_cr);
+			return -1;
+		}
+	} while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
+	       (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
+		|| sio_cr == SIO_CR_ARB_DIAG_TXB
+		|| sio_cr == SIO_CR_ARB_DIAG_RXA
+		|| sio_cr == SIO_CR_ARB_DIAG_RXB));
+
+	/* Finish reset sequence */
+	writel(0, &port->ip_serial_regs->sscr);
+
+	/* Once RESET is done, reload cached tx_prod and rx_cons values
+	 * and set rings to empty by making prod == cons
+	 */
+	port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+	writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+	port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+	writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+	/* Disable interrupts for this 16550 */
+	uart = port->ip_uart_regs;
+	writeb(0, &uart->iu_lcr);
+	writeb(0, &uart->iu_ier);
+
+	/* Set the default baud */
+	set_baud(port, port->ip_baud);
+
+	/* Set line control to 8 bits no parity */
+	writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
+	/* UART_LCR_STOP == 1 stop */
+
+	/* Enable the FIFOs */
+	writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
+	/* then reset 16550 FIFOs */
+	writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+	       &uart->iu_fcr);
+
+	/* Clear modem control register */
+	writeb(0, &uart->iu_mcr);
+
+	/* Clear deltas in modem status register */
+	writel(0, &port->ip_serial_regs->shadow);
+
+	/* Only do this once per port pair */
+	if (port->ip_hooks == &hooks_array[0]) {
+		unsigned long ring_pci_addr;
+		uint32_t __iomem *sbbr_l, *sbbr_h;
+
+		sbbr_l = &idd->vma->sbbr_l;
+		sbbr_h = &idd->vma->sbbr_h;
+		ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+		DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
+			       __FUNCTION__, (void *)ring_pci_addr));
+
+		writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
+		writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
+	}
+
+	/* Set the receive timeout value to 10 msec */
+	writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+	/* Set rx threshold, enable DMA */
+	/* Set high water mark at 3/4 of full ring */
+	port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+
+	/* uart experiences pauses at high baud rate reducing actual
+	 * throughput by 10% or so unless we enable high speed polling
+	 * XXX when this hardware bug is resolved we should revert to
+	 * normal polling speed
+	 */
+	port->ip_sscr |= SSCR_HIGH_SPD;
+
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Disable and clear all serial related interrupt bits */
+	port->ip_card->ic_enable &= ~hooks->intr_clear;
+	ioc3_disable(port->ip_is, idd, hooks->intr_clear);
+	ioc3_ack(port->ip_is, idd, hooks->intr_clear);
+	return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+	if ((port->ip_card->ic_enable & mask) != mask) {
+		port->ip_card->ic_enable |= mask;
+		ioc3_enable(port->ip_is, port->ip_idd, mask);
+	}
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc3_port *port)
+{
+	int spiniter = 0;
+
+	port->ip_flags = INPUT_ENABLE;
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & SSCR_DMA_EN) {
+		writel(port->ip_sscr | SSCR_DMA_PAUSE,
+		       &port->ip_serial_regs->sscr);
+		while ((readl(&port->ip_serial_regs->sscr)
+			& SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER) {
+				NOT_PROGRESS();
+				return -1;
+			}
+		}
+	}
+
+	/* Reset the input fifo.  If the uart received chars while the port
+	 * was closed and DMA is not enabled, the uart may have a bunch of
+	 * chars hanging around in its rx fifo which will not be discarded
+	 * by rclr in the upper layer. We must get rid of them here.
+	 */
+	writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+	       &port->ip_uart_regs->iu_fcr);
+
+	writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
+	/* UART_LCR_STOP == 1 stop */
+
+	/* Re-enable DMA, set default threshold to intr whenever there is
+	 * data available.
+	 */
+	port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+	port->ip_sscr |= 1;	/* default threshold */
+
+	/* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+	 * flag if it was set above
+	 */
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	port->ip_tx_lowat = 1;
+	return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
+{
+	int threshold;
+
+	port->ip_rx_timeout = timeout;
+
+	/* Timeout is in ticks.  Let's figure out how many chars we
+	 * can receive at the current baud rate in that interval
+	 * and set the rx threshold to that amount.  There are 4 chars
+	 * per ring entry, so we'll divide the number of chars that will
+	 * arrive in timeout by 4.
+	 * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+	 */
+	threshold = timeout * port->ip_baud / 4000;
+	if (threshold == 0)
+		threshold = 1;	/* otherwise we'll intr all the time! */
+
+	if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
+		return 1;
+
+	port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+	port->ip_sscr |= threshold;
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Now set the rx timeout to the given value
+	 * again timeout * SRTR_HZ / HZ
+	 */
+	timeout = timeout * SRTR_HZ / 100;
+	if (timeout > SRTR_CNT)
+		timeout = SRTR_CNT;
+	writel(timeout, &port->ip_serial_regs->srtr);
+	return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc3_port *port,
+	    int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+	char lcr, sizebits;
+	int spiniter = 0;
+
+	DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
+			"parodd %d\n",
+		       __FUNCTION__, ((struct uart_port *)port->ip_port)->line,
+			baud, byte_size, stop_bits, parenb, parodd));
+
+	if (set_baud(port, baud))
+		return 1;
+
+	switch (byte_size) {
+	case 5:
+		sizebits = UART_LCR_WLEN5;
+		break;
+	case 6:
+		sizebits = UART_LCR_WLEN6;
+		break;
+	case 7:
+		sizebits = UART_LCR_WLEN7;
+		break;
+	case 8:
+		sizebits = UART_LCR_WLEN8;
+		break;
+	default:
+		return 1;
+	}
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & SSCR_DMA_EN) {
+		writel(port->ip_sscr | SSCR_DMA_PAUSE,
+		       &port->ip_serial_regs->sscr);
+		while ((readl(&port->ip_serial_regs->sscr)
+			& SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER)
+				return -1;
+		}
+	}
+
+	/* Clear relevant fields in lcr */
+	lcr = readb(&port->ip_uart_regs->iu_lcr);
+	lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+		 UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+	/* Set byte size in lcr */
+	lcr |= sizebits;
+
+	/* Set parity */
+	if (parenb) {
+		lcr |= UART_LCR_PARITY;
+		if (!parodd)
+			lcr |= UART_LCR_EPAR;
+	}
+
+	/* Set stop bits */
+	if (stop_bits)
+		lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+	writeb(lcr, &port->ip_uart_regs->iu_lcr);
+
+	/* Re-enable the DMA interface if necessary */
+	if (port->ip_sscr & SSCR_DMA_EN) {
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+	port->ip_baud = baud;
+
+	/* When we get within this number of ring entries of filling the
+	 * entire ring on tx, place an EXPLICIT intr to generate a lowat
+	 * notification when output has drained.
+	 */
+	port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+	if (port->ip_tx_lowat == 0)
+		port->ip_tx_lowat = 1;
+
+	set_rx_timeout(port, 2);
+	return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *			actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc3_port *port, char *buf, int len)
+{
+	int prod_ptr, cons_ptr, total = 0;
+	struct ring *outring;
+	struct ring_entry *entry;
+	struct port_hooks *hooks = port->ip_hooks;
+
+	BUG_ON(!(len >= 0));
+
+	prod_ptr = port->ip_tx_prod;
+	cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+	outring = port->ip_outring;
+
+	/* Maintain a 1-entry red-zone.  The ring buffer is full when
+	 * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+	 * in the body of the loop, I'll do it now.
+	 */
+	cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+	/* Stuff the bytes into the output */
+	while ((prod_ptr != cons_ptr) && (len > 0)) {
+		int xx;
+
+		/* Get 4 bytes (one ring entry) at a time */
+		entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+		/* Invalidate all entries */
+		entry->ring_allsc = 0;
+
+		/* Copy in some bytes */
+		for (xx = 0; (xx < 4) && (len > 0); xx++) {
+			entry->ring_data[xx] = *buf++;
+			entry->ring_sc[xx] = TXCB_VALID;
+			len--;
+			total++;
+		}
+
+		/* If we are within some small threshold of filling up the
+		 * entire ring buffer, we must place an EXPLICIT intr here
+		 * to generate a lowat interrupt in case we subsequently
+		 * really do fill up the ring and the caller goes to sleep.
+		 * No need to place more than one though.
+		 */
+		if (!(port->ip_flags & LOWAT_WRITTEN) &&
+		    ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+		    <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
+			port->ip_flags |= LOWAT_WRITTEN;
+			entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
+		}
+
+		/* Go on to next entry */
+		prod_ptr += sizeof(struct ring_entry);
+		prod_ptr &= PROD_CONS_MASK;
+	}
+
+	/* If we sent something, start DMA if necessary */
+	if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
+		port->ip_sscr |= SSCR_DMA_EN;
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+
+	/* Store the new producer pointer.  If tx is disabled, we stuff the
+	 * data into the ring buffer, but we don't actually start tx.
+	 */
+	if (!uart_tx_stopped(port->ip_port)) {
+		writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+		/* If we are now transmitting, enable tx_mt interrupt so we
+		 * can disable DMA if necessary when the tx finishes.
+		 */
+		if (total > 0)
+			enable_intrs(port, hooks->intr_tx_mt);
+	}
+	port->ip_tx_prod = prod_ptr;
+
+	return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+	if (port->ip_card->ic_enable & mask) {
+		ioc3_disable(port->ip_is, port->ip_idd, mask);
+		port->ip_card->ic_enable &= ~mask;
+	}
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc3_port *port, int mask, int set_on)
+{
+	struct port_hooks *hooks = port->ip_hooks;
+	uint32_t intrbits, sscrbits;
+
+	BUG_ON(!mask);
+
+	intrbits = sscrbits = 0;
+
+	if (mask & N_DATA_READY)
+		intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+	if (mask & N_OUTPUT_LOWAT)
+		intrbits |= hooks->intr_tx_explicit;
+	if (mask & N_DDCD) {
+		intrbits |= hooks->intr_delta_dcd;
+		sscrbits |= SSCR_RX_RING_DCD;
+	}
+	if (mask & N_DCTS)
+		intrbits |= hooks->intr_delta_cts;
+
+	if (set_on) {
+		enable_intrs(port, intrbits);
+		port->ip_notify |= mask;
+		port->ip_sscr |= sscrbits;
+	} else {
+		disable_intrs(port, intrbits);
+		port->ip_notify &= ~mask;
+		port->ip_sscr &= ~sscrbits;
+	}
+
+	/* We require DMA if either DATA_READY or DDCD notification is
+	 * currently requested. If neither of these is requested and
+	 * there is currently no tx in progress, DMA may be disabled.
+	 */
+	if (port->ip_notify & (N_DATA_READY | N_DDCD))
+		port->ip_sscr |= SSCR_DMA_EN;
+	else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
+		port->ip_sscr &= ~SSCR_DMA_EN;
+
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+			  int mask1, int mask2)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	uint32_t shadow;
+	int spiniter = 0;
+	char mcr;
+
+	if (!port)
+		return -1;
+
+	/* Pause the DMA interface if necessary */
+	if (port->ip_sscr & SSCR_DMA_EN) {
+		writel(port->ip_sscr | SSCR_DMA_PAUSE,
+		       &port->ip_serial_regs->sscr);
+		while ((readl(&port->ip_serial_regs->sscr)
+			& SSCR_PAUSE_STATE) == 0) {
+			spiniter++;
+			if (spiniter > MAXITER)
+				return -1;
+		}
+	}
+	shadow = readl(&port->ip_serial_regs->shadow);
+	mcr = (shadow & 0xff000000) >> 24;
+
+	/* Set new value */
+	mcr |= mask1;
+	shadow |= mask2;
+	writeb(mcr, &port->ip_uart_regs->iu_mcr);
+	writel(shadow, &port->ip_serial_regs->shadow);
+
+	/* Re-enable the DMA interface if necessary */
+	if (port->ip_sscr & SSCR_DMA_EN) {
+		writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+	}
+	return 0;
+}
+
+/**
+ * ioc3_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc3_set_proto(struct ioc3_port *port, int proto)
+{
+	struct port_hooks *hooks = port->ip_hooks;
+
+	switch (proto) {
+	default:
+	case PROTO_RS232:
+		/* Clear the appropriate GIO pin */
+		DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__));
+		writel(0, (&port->ip_idd->vma->gppr[0]
+					+ hooks->rs422_select_pin));
+		break;
+
+	case PROTO_RS422:
+		/* Set the appropriate GIO pin */
+		DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__));
+		writel(1, (&port->ip_idd->vma->gppr[0]
+					+ hooks->rs422_select_pin));
+		break;
+	}
+	return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with the_port->lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+	int xmit_count, tail, head;
+	int result;
+	char *start;
+	struct tty_struct *tty;
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	struct uart_info *info;
+
+	if (!the_port)
+		return;
+	if (!port)
+		return;
+
+	info = the_port->info;
+	tty = info->tty;
+
+	if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
+		/* Nothing to do or hw stopped */
+		set_notification(port, N_ALL_OUTPUT, 0);
+		return;
+	}
+
+	head = info->xmit.head;
+	tail = info->xmit.tail;
+	start = (char *)&info->xmit.buf[tail];
+
+	/* write out all the data or until the end of the buffer */
+	xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+	if (xmit_count > 0) {
+		result = do_write(port, start, xmit_count);
+		if (result > 0) {
+			/* booking */
+			xmit_count -= result;
+			the_port->icount.tx += result;
+			/* advance the pointers */
+			tail += result;
+			tail &= UART_XMIT_SIZE - 1;
+			info->xmit.tail = tail;
+			start = (char *)&info->xmit.buf[tail];
+		}
+	}
+	if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(the_port);
+
+	if (uart_circ_empty(&info->xmit)) {
+		set_notification(port, N_OUTPUT_LOWAT, 0);
+	} else {
+		set_notification(port, N_OUTPUT_LOWAT, 1);
+	}
+}
+
+/**
+ * ioc3_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc3_change_speed(struct uart_port *the_port,
+		  struct termios *new_termios, struct termios *old_termios)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	unsigned int cflag;
+	int baud;
+	int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+	struct uart_info *info = the_port->info;
+
+	cflag = new_termios->c_cflag;
+
+	switch (cflag & CSIZE) {
+	case CS5:
+		new_data = 5;
+		break;
+	case CS6:
+		new_data = 6;
+		break;
+	case CS7:
+		new_data = 7;
+		break;
+	case CS8:
+		new_data = 8;
+		break;
+	default:
+		/* cuz we always need a default ... */
+		new_data = 5;
+		break;
+	}
+	if (cflag & CSTOPB) {
+		new_stop = 1;
+	}
+	if (cflag & PARENB) {
+		new_parity_enable = 1;
+		if (cflag & PARODD)
+			new_parity = 1;
+	}
+	baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+				  MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+	DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud,
+				the_port->line));
+
+	if (!the_port->fifosize)
+		the_port->fifosize = FIFO_SIZE;
+	uart_update_timeout(the_port, cflag, baud);
+
+	the_port->ignore_status_mask = N_ALL_INPUT;
+
+	info->tty->low_latency = 1;
+
+	if (I_IGNPAR(info->tty))
+		the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+						  | N_FRAMING_ERROR);
+	if (I_IGNBRK(info->tty)) {
+		the_port->ignore_status_mask &= ~N_BREAK;
+		if (I_IGNPAR(info->tty))
+			the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+	}
+	if (!(cflag & CREAD)) {
+		/* ignore everything */
+		the_port->ignore_status_mask &= ~N_DATA_READY;
+	}
+
+	if (cflag & CRTSCTS) {
+		/* enable hardware flow control */
+		port->ip_sscr |= SSCR_HFC_EN;
+	}
+	else {
+		/* disable hardware flow control */
+		port->ip_sscr &= ~SSCR_HFC_EN;
+	}
+	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+	/* Set the configuration and proper notification call */
+	DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
+		       "config_port(baud %d data %d stop %d penable %d "
+			" parity %d), notification 0x%x\n",
+		       __FUNCTION__, (void *)port, the_port->line, cflag, baud,
+		       new_data, new_stop, new_parity_enable, new_parity,
+		       the_port->ignore_status_mask));
+
+	if ((config_port(port, baud,	/* baud */
+			 new_data,	/* byte size */
+			 new_stop,	/* stop bits */
+			 new_parity_enable,	/* set parity */
+			 new_parity)) >= 0) {	/* parity 1==odd */
+		set_notification(port, the_port->ignore_status_mask, 1);
+	}
+}
+
+/**
+ * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic3_startup_local(struct uart_port *the_port)
+{
+	struct ioc3_port *port;
+
+	if (!the_port) {
+		NOT_PROGRESS();
+		return -1;
+	}
+
+	port = get_ioc3_port(the_port);
+	if (!port) {
+		NOT_PROGRESS();
+		return -1;
+	}
+
+	local_open(port);
+
+	/* set the protocol */
+	ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
+							PROTO_RS422);
+	return 0;
+}
+
+/*
+ * ioc3_cb_output_lowat - called when the output low water mark is hit
+ * @port: port to output
+ */
+static void ioc3_cb_output_lowat(struct ioc3_port *port)
+{
+	unsigned long pflags;
+
+	/* the_port->lock is set on the call here */
+	if (port->ip_port) {
+		spin_lock_irqsave(&port->ip_port->lock, pflags);
+		transmit_chars(port->ip_port);
+		spin_unlock_irqrestore(&port->ip_port->lock, pflags);
+	}
+}
+
+/*
+ * ioc3_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+	struct uart_icount *icount;
+
+	icount = &the_port->icount;
+
+	if (ncs & NCS_BREAK)
+		icount->brk++;
+	if (ncs & NCS_FRAMING)
+		icount->frame++;
+	if (ncs & NCS_OVERRUN)
+		icount->overrun++;
+	if (ncs & NCS_PARITY)
+		icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *			actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, char *buf, int len)
+{
+	int prod_ptr, cons_ptr, total;
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	struct ring *inring;
+	struct ring_entry *entry;
+	struct port_hooks *hooks = port->ip_hooks;
+	int byte_num;
+	char *sc;
+	int loop_counter;
+
+	BUG_ON(!(len >= 0));
+	BUG_ON(!port);
+
+	/* There is a nasty timing issue in the IOC3. When the rx_timer
+	 * expires or the rx_high condition arises, we take an interrupt.
+	 * At some point while servicing the interrupt, we read bytes from
+	 * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+	 * not started until the first byte is received *after* it is armed,
+	 * and any bytes pending in the rx construction buffers are not drained
+	 * to memory until either there are 4 bytes available or the rx_timer
+	 * expires.  This leads to a potential situation where data is left
+	 * in the construction buffers forever - 1 to 3 bytes were received
+	 * after the interrupt was generated but before the rx_timer was
+	 * re-armed. At that point as long as no subsequent bytes are received
+	 * the timer will never be started and the bytes will remain in the
+	 * construction buffer forever.  The solution is to execute a DRAIN
+	 * command after rearming the timer.  This way any bytes received before
+	 * the DRAIN will be drained to memory, and any bytes received after
+	 * the DRAIN will start the TIMER and be drained when it expires.
+	 * Luckily, this only needs to be done when the DMA buffer is empty
+	 * since there is no requirement that this function return all
+	 * available data as long as it returns some.
+	 */
+	/* Re-arm the timer */
+
+	writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+	prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+	cons_ptr = port->ip_rx_cons;
+
+	if (prod_ptr == cons_ptr) {
+		int reset_dma = 0;
+
+		/* Input buffer appears empty, do a flush. */
+
+		/* DMA must be enabled for this to work. */
+		if (!(port->ip_sscr & SSCR_DMA_EN)) {
+			port->ip_sscr |= SSCR_DMA_EN;
+			reset_dma = 1;
+		}
+
+		/* Potential race condition: we must reload the srpir after
+		 * issuing the drain command, otherwise we could think the rx
+		 * buffer is empty, then take a very long interrupt, and when
+		 * we come back it's full and we wait forever for the drain to
+		 * complete.
+		 */
+		writel(port->ip_sscr | SSCR_RX_DRAIN,
+		       &port->ip_serial_regs->sscr);
+		prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+
+		/* We must not wait for the DRAIN to complete unless there are
+		 * at least 8 bytes (2 ring entries) available to receive the
+		 * data otherwise the DRAIN will never complete and we'll
+		 * deadlock here.
+		 * In fact, to make things easier, I'll just ignore the flush if
+		 * there is any data at all now available.
+		 */
+		if (prod_ptr == cons_ptr) {
+			loop_counter = 0;
+			while (readl(&port->ip_serial_regs->sscr) &
+			       SSCR_RX_DRAIN) {
+				loop_counter++;
+				if (loop_counter > MAXITER)
+					return -1;
+			}
+
+			/* SIGH. We have to reload the prod_ptr *again* since
+			 * the drain may have caused it to change
+			 */
+			prod_ptr = readl(&port->ip_serial_regs->srpir)
+			    & PROD_CONS_MASK;
+		}
+		if (reset_dma) {
+			port->ip_sscr &= ~SSCR_DMA_EN;
+			writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+		}
+	}
+	inring = port->ip_inring;
+	port->ip_flags &= ~READ_ABORTED;
+
+	total = 0;
+	loop_counter = 0xfffff;	/* to avoid hangs */
+
+	/* Grab bytes from the hardware */
+	while ((prod_ptr != cons_ptr) && (len > 0)) {
+		entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
+
+		if (loop_counter-- <= 0) {
+			printk(KERN_WARNING "IOC3 serial: "
+			       "possible hang condition/"
+			       "port stuck on read (line %d).\n",
+				the_port->line);
+			break;
+		}
+
+		/* According to the producer pointer, this ring entry
+		 * must contain some data.  But if the PIO happened faster
+		 * than the DMA, the data may not be available yet, so let's
+		 * wait until it arrives.
+		 */
+		if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+			/* Indicate the read is aborted so we don't disable
+			 * the interrupt thinking that the consumer is
+			 * congested.
+			 */
+			port->ip_flags |= READ_ABORTED;
+			len = 0;
+			break;
+		}
+
+		/* Load the bytes/status out of the ring entry */
+		for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+			sc = &(entry->ring_sc[byte_num]);
+
+			/* Check for change in modem state or overrun */
+			if ((*sc & RXSB_MODEM_VALID)
+			    && (port->ip_notify & N_DDCD)) {
+				/* Notify upper layer if DCD dropped */
+				if ((port->ip_flags & DCD_ON)
+				    && !(*sc & RXSB_DCD)) {
+					/* If we have already copied some data,
+					 * return it.  We'll pick up the carrier
+					 * drop on the next pass.  That way we
+					 * don't throw away the data that has
+					 * already been copied back to
+					 * the caller's buffer.
+					 */
+					if (total > 0) {
+						len = 0;
+						break;
+					}
+					port->ip_flags &= ~DCD_ON;
+
+					/* Turn off this notification so the
+					 * carrier drop protocol won't see it
+					 * again when it does a read.
+					 */
+					*sc &= ~RXSB_MODEM_VALID;
+
+					/* To keep things consistent, we need
+					 * to update the consumer pointer so
+					 * the next reader won't come in and
+					 * try to read the same ring entries
+					 * again. This must be done here before
+					 * the dcd change.
+					 */
+
+					if ((entry->ring_allsc & RING_ANY_VALID)
+					    == 0) {
+						cons_ptr += (int)sizeof
+						    (struct ring_entry);
+						cons_ptr &= PROD_CONS_MASK;
+					}
+					writel(cons_ptr,
+					       &port->ip_serial_regs->srcir);
+					port->ip_rx_cons = cons_ptr;
+
+					/* Notify upper layer of carrier drop */
+					if ((port->ip_notify & N_DDCD)
+					    && port->ip_port) {
+						uart_handle_dcd_change
+							(port->ip_port, 0);
+						wake_up_interruptible
+						    (&the_port->info->
+						     delta_msr_wait);
+					}
+
+					/* If we had any data to return, we
+					 * would have returned it above.
+					 */
+					return 0;
+				}
+			}
+			if (*sc & RXSB_MODEM_VALID) {
+				/* Notify that an input overrun occurred */
+				if ((*sc & RXSB_OVERRUN)
+				    && (port->ip_notify & N_OVERRUN_ERROR)) {
+					ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
+				}
+				/* Don't look at this byte again */
+				*sc &= ~RXSB_MODEM_VALID;
+			}
+
+			/* Check for valid data or RX errors */
+			if ((*sc & RXSB_DATA_VALID) &&
+			    ((*sc & (RXSB_PAR_ERR
+				     | RXSB_FRAME_ERR | RXSB_BREAK))
+			     && (port->ip_notify & (N_PARITY_ERROR
+						    | N_FRAMING_ERROR
+						    | N_BREAK)))) {
+				/* There is an error condition on the next byte.
+				 * If we have already transferred some bytes,
+				 * we'll stop here. Otherwise if this is the
+				 * first byte to be read, we'll just transfer
+				 * it alone after notifying the
+				 * upper layer of its status.
+				 */
+				if (total > 0) {
+					len = 0;
+					break;
+				} else {
+					if ((*sc & RXSB_PAR_ERR) &&
+					    (port->
+					     ip_notify & N_PARITY_ERROR)) {
+						ioc3_cb_post_ncs(the_port,
+								 NCS_PARITY);
+					}
+					if ((*sc & RXSB_FRAME_ERR) &&
+					    (port->
+					     ip_notify & N_FRAMING_ERROR)) {
+						ioc3_cb_post_ncs(the_port,
+								 NCS_FRAMING);
+					}
+					if ((*sc & RXSB_BREAK)
+					    && (port->ip_notify & N_BREAK)) {
+						ioc3_cb_post_ncs
+						    (the_port, NCS_BREAK);
+					}
+					len = 1;
+				}
+			}
+			if (*sc & RXSB_DATA_VALID) {
+				*sc &= ~RXSB_DATA_VALID;
+				*buf = entry->ring_data[byte_num];
+				buf++;
+				len--;
+				total++;
+			}
+		}
+
+		/* If we used up this entry entirely, go on to the next one,
+		 * otherwise we must have run out of buffer space, so
+		 * leave the consumer pointer here for the next read in case
+		 * there are still unread bytes in this entry.
+		 */
+		if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+			cons_ptr += (int)sizeof(struct ring_entry);
+			cons_ptr &= PROD_CONS_MASK;
+		}
+	}
+
+	/* Update consumer pointer and re-arm rx timer interrupt */
+	writel(cons_ptr, &port->ip_serial_regs->srcir);
+	port->ip_rx_cons = cons_ptr;
+
+	/* If we have now dipped below the rx high water mark and we have
+	 * rx_high interrupt turned off, we can now turn it back on again.
+	 */
+	if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+					       & PROD_CONS_MASK) <
+					      ((port->
+						ip_sscr &
+						SSCR_RX_THRESHOLD)
+					       << PROD_CONS_PTR_OFF))) {
+		port->ip_flags &= ~INPUT_HIGH;
+		enable_intrs(port, hooks->intr_rx_high);
+	}
+	return total;
+}
+
+/**
+ * receive_chars - upper level read.
+ * @the_port: port to read from
+ */
+static int receive_chars(struct uart_port *the_port)
+{
+	struct tty_struct *tty;
+	unsigned char ch[MAX_CHARS];
+	int read_count = 0, read_room, flip = 0;
+	struct uart_info *info = the_port->info;
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	unsigned long pflags;
+
+	/* Make sure all the pointers are "good" ones */
+	if (!info)
+		return 0;
+	if (!info->tty)
+		return 0;
+
+	if (!(port->ip_flags & INPUT_ENABLE))
+		return 0;
+
+	spin_lock_irqsave(&the_port->lock, pflags);
+	tty = info->tty;
+
+	read_count = do_read(the_port, ch, MAX_CHARS);
+	if (read_count > 0) {
+		flip = 1;
+		read_room = tty_buffer_request_room(tty, read_count);
+		tty_insert_flip_string(tty, ch, read_room);
+		the_port->icount.rx += read_count;
+	}
+	spin_unlock_irqrestore(&the_port->lock, pflags);
+
+	if (flip)
+		tty_flip_buffer_push(tty);
+
+	return read_count;
+}
+
+/**
+ * ioc3uart_intr_one - lowest level (per port) interrupt handler.
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ * @regs: pt_regs
+ */
+
+static int inline
+ioc3uart_intr_one(struct ioc3_submodule *is,
+			struct ioc3_driver_data *idd,
+			unsigned int pending, struct pt_regs *regs)
+{
+	int port_num = GET_PORT_FROM_SIO_IR(pending);
+	struct port_hooks *hooks;
+	unsigned int rx_high_rd_aborted = 0;
+	unsigned long flags;
+	struct uart_port *the_port;
+	struct ioc3_port *port;
+	int loop_counter;
+	struct ioc3_card *card_ptr;
+	unsigned int sio_ir;
+
+	card_ptr = idd->data[is->id];
+	port = card_ptr->ic_port[port_num].icp_port;
+	hooks = port->ip_hooks;
+
+	/* Possible race condition here: The tx_mt interrupt bit may be
+	 * cleared without the intervention of the interrupt handler,
+	 * e.g. by a write.  If the top level interrupt handler reads a
+	 * tx_mt, then some other processor does a write, starting up
+	 * output, then we come in here, see the tx_mt and stop DMA, the
+	 * output started by the other processor will hang.  Thus we can
+	 * only rely on tx_mt being legitimate if it is read while the
+	 * port lock is held.  Therefore this bit must be ignored in the
+	 * passed in interrupt mask which was read by the top level
+	 * interrupt handler since the port lock was not held at the time
+	 * it was read.  We can only rely on this bit being accurate if it
+	 * is read while the port lock is held.  So we'll clear it for now,
+	 * and reload it later once we have the port lock.
+	 */
+
+	sio_ir = pending & ~(hooks->intr_tx_mt);
+	spin_lock_irqsave(&port->ip_lock, flags);
+
+	loop_counter = MAXITER;	/* to avoid hangs */
+
+	do {
+		uint32_t shadow;
+
+		if (loop_counter-- <= 0) {
+			printk(KERN_WARNING "IOC3 serial: "
+			       "possible hang condition/"
+			       "port stuck on interrupt (line %d).\n",
+				((struct uart_port *)port->ip_port)->line);
+			break;
+		}
+		/* Handle a DCD change */
+		if (sio_ir & hooks->intr_delta_dcd) {
+			ioc3_ack(is, idd, hooks->intr_delta_dcd);
+			shadow = readl(&port->ip_serial_regs->shadow);
+
+			if ((port->ip_notify & N_DDCD)
+			    && (shadow & SHADOW_DCD)
+			    && (port->ip_port)) {
+				the_port = port->ip_port;
+				uart_handle_dcd_change(the_port,
+						shadow & SHADOW_DCD);
+				wake_up_interruptible
+				    (&the_port->info->delta_msr_wait);
+			} else if ((port->ip_notify & N_DDCD)
+				   && !(shadow & SHADOW_DCD)) {
+				/* Flag delta DCD/no DCD */
+				uart_handle_dcd_change(port->ip_port,
+						shadow & SHADOW_DCD);
+				port->ip_flags |= DCD_ON;
+			}
+		}
+
+		/* Handle a CTS change */
+		if (sio_ir & hooks->intr_delta_cts) {
+			ioc3_ack(is, idd, hooks->intr_delta_cts);
+			shadow = readl(&port->ip_serial_regs->shadow);
+
+			if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
+				the_port = port->ip_port;
+				uart_handle_cts_change(the_port, shadow
+						& SHADOW_CTS);
+				wake_up_interruptible
+				    (&the_port->info->delta_msr_wait);
+			}
+		}
+
+		/* rx timeout interrupt.  Must be some data available.  Put this
+		 * before the check for rx_high since servicing this condition
+		 * may cause that condition to clear.
+		 */
+		if (sio_ir & hooks->intr_rx_timer) {
+			ioc3_ack(is, idd, hooks->intr_rx_timer);
+			if ((port->ip_notify & N_DATA_READY)
+						&& (port->ip_port)) {
+				receive_chars(port->ip_port);
+			}
+		}
+
+		/* rx high interrupt. Must be after rx_timer.  */
+		else if (sio_ir & hooks->intr_rx_high) {
+			/* Data available, notify upper layer */
+			if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
+				receive_chars(port->ip_port);
+			}
+
+			/* We can't ACK this interrupt.  If receive_chars didn't
+			 * cause the condition to clear, we'll have to disable
+			 * the interrupt until the data is drained.
+			 * If the read was aborted, don't disable the interrupt
+			 * as this may cause us to hang indefinitely.  An
+			 * aborted read generally means that this interrupt
+			 * hasn't been delivered to the cpu yet anyway, even
+			 * though we see it as asserted when we read the sio_ir.
+			 */
+			if ((sio_ir = PENDING(card_ptr, idd))
+					& hooks->intr_rx_high) {
+				if (port->ip_flags & READ_ABORTED) {
+					rx_high_rd_aborted++;
+				}
+				else {
+					card_ptr->ic_enable &= ~hooks->intr_rx_high;
+					port->ip_flags |= INPUT_HIGH;
+				}
+			}
+		}
+
+		/* We got a low water interrupt: notify upper layer to
+		 * send more data.  Must come before tx_mt since servicing
+		 * this condition may cause that condition to clear.
+		 */
+		if (sio_ir & hooks->intr_tx_explicit) {
+			port->ip_flags &= ~LOWAT_WRITTEN;
+			ioc3_ack(is, idd, hooks->intr_tx_explicit);
+			if (port->ip_notify & N_OUTPUT_LOWAT)
+				ioc3_cb_output_lowat(port);
+		}
+
+		/* Handle tx_mt.  Must come after tx_explicit.  */
+		else if (sio_ir & hooks->intr_tx_mt) {
+			/* If we are expecting a lowat notification
+			 * and we get to this point it probably means that for
+			 * some reason the tx_explicit didn't work as expected
+			 * (that can legitimately happen if the output buffer is
+			 * filled up in just the right way).
+			 * So send the notification now.
+			 */
+			if (port->ip_notify & N_OUTPUT_LOWAT) {
+				ioc3_cb_output_lowat(port);
+
+				/* We need to reload the sio_ir since the lowat
+				 * call may have caused another write to occur,
+				 * clearing the tx_mt condition.
+				 */
+				sio_ir = PENDING(card_ptr, idd);
+			}
+
+			/* If the tx_mt condition still persists even after the
+			 * lowat call, we've got some work to do.
+			 */
+			if (sio_ir & hooks->intr_tx_mt) {
+				/* If we are not currently expecting DMA input,
+				 * and the transmitter has just gone idle,
+				 * there is no longer any reason for DMA, so
+				 * disable it.
+				 */
+				if (!(port->ip_notify
+				      & (N_DATA_READY | N_DDCD))) {
+					BUG_ON(!(port->ip_sscr
+						 & SSCR_DMA_EN));
+					port->ip_sscr &= ~SSCR_DMA_EN;
+					writel(port->ip_sscr,
+					       &port->ip_serial_regs->sscr);
+				}
+				/* Prevent infinite tx_mt interrupt */
+				card_ptr->ic_enable &= ~hooks->intr_tx_mt;
+			}
+		}
+		sio_ir = PENDING(card_ptr, idd);
+
+		/* if the read was aborted and only hooks->intr_rx_high,
+		 * clear hooks->intr_rx_high, so we do not loop forever.
+		 */
+
+		if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+			sio_ir &= ~hooks->intr_rx_high;
+		}
+	} while (sio_ir & hooks->intr_all);
+
+	spin_unlock_irqrestore(&port->ip_lock, flags);
+	ioc3_enable(is, idd, card_ptr->ic_enable);
+	return 0;
+}
+
+/**
+ * ioc3uart_intr - field all serial interrupts
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ * @regs: pt_regs
+ *
+ */
+
+static int ioc3uart_intr(struct ioc3_submodule *is,
+			struct ioc3_driver_data *idd,
+			unsigned int pending, struct pt_regs *regs)
+{
+	int ret = 0;
+
+	/*
+	 * The upper level interrupt handler sends interrupts for both ports
+	 * here. So we need to call for each port with its interrupts.
+	 */
+
+	if (pending & SIO_IR_SA)
+		ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA, regs);
+	if (pending & SIO_IR_SB)
+		ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB, regs);
+
+	return ret;
+}
+
+/**
+ * ic3_type
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic3_type(struct uart_port *the_port)
+{
+	if (IS_RS232(the_port->line))
+		return "SGI IOC3 Serial [rs232]";
+	else
+		return "SGI IOC3 Serial [rs422]";
+}
+
+/**
+ * ic3_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic3_tx_empty(struct uart_port *the_port)
+{
+	unsigned int ret = 0;
+	struct ioc3_port *port = get_ioc3_port(the_port);
+
+	if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
+		ret = TIOCSER_TEMT;
+	return ret;
+}
+
+/**
+ * ic3_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_tx(struct uart_port *the_port)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+
+	if (port)
+		set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * ic3_stop_rx - stop the receiver
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_rx(struct uart_port *the_port)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+
+	if (port)
+		port->ip_flags &= ~INPUT_ENABLE;
+}
+
+/**
+ * null_void_function
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic3_shutdown - shut down the port - free irq and disable
+ * @port: port to shut down
+ *
+ */
+static void ic3_shutdown(struct uart_port *the_port)
+{
+	unsigned long port_flags;
+	struct ioc3_port *port;
+	struct uart_info *info;
+
+	port = get_ioc3_port(the_port);
+	if (!port)
+		return;
+
+	info = the_port->info;
+	wake_up_interruptible(&info->delta_msr_wait);
+
+	spin_lock_irqsave(&the_port->lock, port_flags);
+	set_notification(port, N_ALL, 0);
+	spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+	unsigned char mcr = 0;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	set_mcr(the_port, mcr, SHADOW_DTR);
+}
+
+/**
+ * ic3_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic3_get_mctrl(struct uart_port *the_port)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+	uint32_t shadow;
+	unsigned int ret = 0;
+
+	if (!port)
+		return 0;
+
+	shadow = readl(&port->ip_serial_regs->shadow);
+	if (shadow & SHADOW_DCD)
+		ret |= TIOCM_CD;
+	if (shadow & SHADOW_DR)
+		ret |= TIOCM_DSR;
+	if (shadow & SHADOW_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+/**
+ * ic3_start_tx - Start transmitter. Called with the_port->lock
+ * @port: Port to operate on
+ *
+ */
+static void ic3_start_tx(struct uart_port *the_port)
+{
+	struct ioc3_port *port = get_ioc3_port(the_port);
+
+	if (port) {
+		set_notification(port, N_OUTPUT_LOWAT, 1);
+		enable_intrs(port, port->ip_hooks->intr_tx_mt);
+	}
+}
+
+/**
+ * ic3_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic3_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic3_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int ic3_startup(struct uart_port *the_port)
+{
+	int retval;
+	struct ioc3_port *port;
+	struct ioc3_card *card_ptr;
+	unsigned long port_flags;
+
+	if (!the_port) {
+		NOT_PROGRESS();
+		return -ENODEV;
+	}
+	port = get_ioc3_port(the_port);
+	if (!port) {
+		NOT_PROGRESS();
+		return -ENODEV;
+	}
+	card_ptr = port->ip_card;
+	port->ip_port = the_port;
+
+	if (!card_ptr) {
+		NOT_PROGRESS();
+		return -ENODEV;
+	}
+
+	/* Start up the serial port */
+	spin_lock_irqsave(&the_port->lock, port_flags);
+	retval = ic3_startup_local(the_port);
+	spin_unlock_irqrestore(&the_port->lock, port_flags);
+	return retval;
+}
+
+/**
+ * ic3_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic3_set_termios(struct uart_port *the_port,
+		struct termios *termios, struct termios *old_termios)
+{
+	unsigned long port_flags;
+
+	spin_lock_irqsave(&the_port->lock, port_flags);
+	ioc3_change_speed(the_port, termios, old_termios);
+	spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic3_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+static struct uart_ops ioc3_ops = {
+	.tx_empty = ic3_tx_empty,
+	.set_mctrl = ic3_set_mctrl,
+	.get_mctrl = ic3_get_mctrl,
+	.stop_tx = ic3_stop_tx,
+	.start_tx = ic3_start_tx,
+	.stop_rx = ic3_stop_rx,
+	.enable_ms = null_void_function,
+	.break_ctl = ic3_break_ctl,
+	.startup = ic3_startup,
+	.shutdown = ic3_shutdown,
+	.set_termios = ic3_set_termios,
+	.type = ic3_type,
+	.release_port = null_void_function,
+	.request_port = ic3_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc3_uart = {
+	.owner = THIS_MODULE,
+	.driver_name = "ioc3_serial",
+	.dev_name = DEVICE_NAME,
+	.major = DEVICE_MAJOR,
+	.minor = DEVICE_MINOR,
+	.nr = MAX_LOGICAL_PORTS
+};
+
+/**
+ * ioc3_serial_core_attach - register with serial core
+ *		This is done during pci probing
+ * @is: submodule struct for this
+ * @idd: handle for this card
+ */
+static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
+				struct ioc3_driver_data *idd)
+{
+	struct ioc3_port *port;
+	struct uart_port *the_port;
+	struct ioc3_card *card_ptr = idd->data[is->id];
+	int ii, phys_port;
+	struct pci_dev *pdev = idd->pdev;
+
+	DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
+		       __FUNCTION__, pdev, (void *)card_ptr));
+
+	if (!card_ptr)
+		return -ENODEV;
+
+	/* once around for each logical port on this card */
+	for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+		phys_port = GET_PHYSICAL_PORT(ii);
+		the_port = &card_ptr->ic_port[phys_port].
+				icp_uart_port[GET_LOGICAL_PORT(ii)];
+		port = card_ptr->ic_port[phys_port].icp_port;
+		port->ip_port = the_port;
+
+		DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
+			__FUNCTION__, (void *)the_port, (void *)port,
+				phys_port, ii));
+
+		/* membase, iobase and mapbase just need to be non-0 */
+		the_port->membase = (unsigned char __iomem *)1;
+		the_port->iobase = (pdev->bus->number << 16) |  ii;
+		the_port->line = (Num_of_ioc3_cards << 2) | ii;
+		the_port->mapbase = 1;
+		the_port->type = PORT_16550A;
+		the_port->fifosize = FIFO_SIZE;
+		the_port->ops = &ioc3_ops;
+		the_port->irq = idd->irq_io;
+		the_port->dev = &pdev->dev;
+
+		if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
+			printk(KERN_WARNING
+		          "%s: unable to add port %d bus %d\n",
+			       __FUNCTION__, the_port->line, pdev->bus->number);
+		} else {
+			DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
+		          the_port->line, the_port->irq, pdev->bus->number));
+		}
+
+		/* all ports are rs232 for now */
+		if (IS_PHYSICAL_PORT(ii))
+			ioc3_set_proto(port, PROTO_RS232);
+	}
+	return 0;
+}
+
+/**
+ * ioc3uart_remove - register detach function
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this submodule
+ */
+
+static int ioc3uart_remove(struct ioc3_submodule *is,
+			struct ioc3_driver_data *idd)
+{
+	struct ioc3_card *card_ptr = idd->data[is->id];
+	struct uart_port *the_port;
+	struct ioc3_port *port;
+	int ii;
+
+	if (card_ptr) {
+		for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+			the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+					icp_uart_port[GET_LOGICAL_PORT(ii)];
+			if (the_port)
+				uart_remove_one_port(&ioc3_uart, the_port);
+			port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
+			if (port && IS_PHYSICAL_PORT(ii)
+					&& (GET_PHYSICAL_PORT(ii) == 0)) {
+				pci_free_consistent(port->ip_idd->pdev,
+					TOTAL_RING_BUF_SIZE,
+					(void *)port->ip_cpu_ringbuf,
+					port->ip_dma_ringbuf);
+				kfree(port);
+				card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+							icp_port = NULL;
+			}
+		}
+		kfree(card_ptr);
+		idd->data[is->id] = NULL;
+	}
+	return 0;
+}
+
+/**
+ * ioc3uart_probe - card probe function called from shim driver
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this card
+ */
+
+static int __devinit
+ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+	struct pci_dev *pdev = idd->pdev;
+	struct ioc3_card *card_ptr;
+	int ret = 0;
+	struct ioc3_port *port;
+	struct ioc3_port *ports[PORTS_PER_CARD];
+	int phys_port;
+
+	DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
+
+	card_ptr = kmalloc(sizeof(struct ioc3_card), GFP_KERNEL);
+	if (!card_ptr) {
+		printk(KERN_WARNING "ioc3_attach_one"
+		       ": unable to get memory for the IOC3\n");
+		return -ENOMEM;
+	}
+	memset(card_ptr, 0, sizeof(struct ioc3_card));
+	idd->data[is->id] = card_ptr;
+	Submodule_slot = is->id;
+
+	writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
+		((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
+		(0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
+
+	pci_write_config_dword(pdev, PCI_LAT, 0xff00);
+
+	/* Enable serial port mode select generic PIO pins as outputs */
+	ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
+
+	/* Create port structures for each port */
+	for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
+		port = kmalloc(sizeof(struct ioc3_port), GFP_KERNEL);
+		if (!port) {
+			printk(KERN_WARNING
+			       "IOC3 serial memory not available for port\n");
+			goto out4;
+		}
+		memset(port, 0, sizeof(struct ioc3_port));
+		spin_lock_init(&port->ip_lock);
+
+		/* we need to remember the previous ones, to point back to
+		 * them farther down - setting up the ring buffers.
+		 */
+		ports[phys_port] = port;
+
+		/* init to something useful */
+		card_ptr->ic_port[phys_port].icp_port = port;
+		port->ip_is = is;
+		port->ip_idd = idd;
+		port->ip_baud = 9600;
+		port->ip_card = card_ptr;
+		port->ip_hooks = &hooks_array[phys_port];
+
+		/* Setup each port */
+		if (phys_port == 0) {
+			port->ip_serial_regs = &idd->vma->port_a;
+			port->ip_uart_regs = &idd->vma->sregs.uarta;
+
+			DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
+				       "ip_uart_regs 0x%p\n",
+				       __FUNCTION__,
+				       (void *)port->ip_serial_regs,
+				       (void *)port->ip_uart_regs));
+
+			/* setup ring buffers */
+			port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
+				TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
+
+			BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
+				  (TOTAL_RING_BUF_SIZE - 1)) == 0));
+			port->ip_inring = RING(port, RX_A);
+			port->ip_outring = RING(port, TX_A);
+			DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
+				       "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+					"ip_outring 0x%p\n",
+				       __FUNCTION__,
+				       (void *)port->ip_cpu_ringbuf,
+				       (void *)port->ip_dma_ringbuf,
+				       (void *)port->ip_inring,
+				       (void *)port->ip_outring));
+		}
+		else {
+			port->ip_serial_regs = &idd->vma->port_b;
+			port->ip_uart_regs = &idd->vma->sregs.uartb;
+
+			DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
+				       "ip_uart_regs 0x%p\n",
+				       __FUNCTION__,
+				       (void *)port->ip_serial_regs,
+				       (void *)port->ip_uart_regs));
+
+			/* share the ring buffers */
+			port->ip_dma_ringbuf =
+			    ports[phys_port - 1]->ip_dma_ringbuf;
+			port->ip_cpu_ringbuf =
+			    ports[phys_port - 1]->ip_cpu_ringbuf;
+			port->ip_inring = RING(port, RX_B);
+			port->ip_outring = RING(port, TX_B);
+			DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
+				       "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+					"ip_outring 0x%p\n",
+				       __FUNCTION__,
+				       (void *)port->ip_cpu_ringbuf,
+				       (void *)port->ip_dma_ringbuf,
+				       (void *)port->ip_inring,
+				       (void *)port->ip_outring));
+		}
+
+		DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
+			       __FUNCTION__,
+			       phys_port, (void *)port, (void *)card_ptr));
+		DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+			       (void *)port->ip_serial_regs,
+			       (void *)port->ip_uart_regs));
+
+		/* Initialize the hardware for IOC3 */
+		port_init(port);
+
+		DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
+			       "outring 0x%p\n",
+			       __FUNCTION__,
+			       phys_port, (void *)port,
+			       (void *)port->ip_inring,
+			       (void *)port->ip_outring));
+
+	}
+
+	/* register port with the serial core */
+
+	if ((ret = ioc3_serial_core_attach(is, idd)))
+		goto out4;
+
+	Num_of_ioc3_cards++;
+
+	return ret;
+
+	/* error exits that give back resources */
+out4:
+	kfree(card_ptr);
+	return ret;
+}
+
+static struct ioc3_submodule ioc3uart_submodule = {
+	.name = "IOC3uart",
+	.probe = ioc3uart_probe,
+	.remove = ioc3uart_remove,
+	/* call .intr for both ports initially */
+	.irq_mask = SIO_IR_SA | SIO_IR_SB,
+	.intr = ioc3uart_intr,
+	.owner = THIS_MODULE,
+};
+
+/**
+ * ioc3_detect - module init called,
+ */
+static int __devinit ioc3uart_init(void)
+{
+	int ret;
+
+	/* register with serial core */
+	if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
+		printk(KERN_WARNING
+		       "%s: Couldn't register IOC3 uart serial driver\n",
+		       __FUNCTION__);
+		return ret;
+	}
+	ret = ioc3_register_submodule(&ioc3uart_submodule);
+	if (ret)
+		uart_unregister_driver(&ioc3_uart);
+	return ret;
+}
+
+static void __devexit ioc3uart_exit(void)
+{
+	ioc3_unregister_submodule(&ioc3uart_submodule);
+	uart_unregister_driver(&ioc3_uart);
+}
+
+module_init(ioc3uart_init);
+module_exit(ioc3uart_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 7bdab2a..94b2290 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -175,8 +175,6 @@
 {
 	drv->drv.name	= drv->name;
 	drv->drv.bus	= &superhyway_bus_type;
-	drv->drv.probe	= superhyway_device_probe;
-	drv->drv.remove	= superhyway_device_remove;
 
 	return driver_register(&drv->drv);
 }
@@ -213,6 +211,8 @@
 #ifdef CONFIG_SYSFS
 	.dev_attrs	= superhyway_dev_attrs,
 #endif
+	.probe		= superhyway_device_probe,
+	.remove		= superhyway_device_remove,
 };
 
 static int __init superhyway_bus_init(void)
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
index 13b8d24..d95265b1 100644
--- a/drivers/sn/Kconfig
+++ b/drivers/sn/Kconfig
@@ -17,4 +17,18 @@
 	If you have an SGI Altix with an IOC4-based
 	I/O controller say Y.  Otherwise say N.
 
+config SGI_IOC3
+	tristate "SGI IOC3 Base IO support"
+	depends on (IA64_GENERIC || IA64_SGI_SN2)
+	default m
+	---help---
+	This option enables basic support for the SGI IOC3-based Base IO
+	controller card.  This option does not enable any specific
+	functions on such a card, but provides necessary infrastructure
+	for other drivers to utilize.
+
+	If you have an SGI Altix with an IOC3-based
+	I/O controller or a PCI IOC3 serial card say Y.
+	Otherwise say N.
+
 endmenu
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
index c2a2841..2cda011 100644
--- a/drivers/sn/Makefile
+++ b/drivers/sn/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_SGI_IOC4) += ioc4.o
+obj-$(CONFIG_SGI_IOC3) += ioc3.o
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
new file mode 100644
index 0000000..aaa009f
--- /dev/null
+++ b/drivers/sn/ioc3.c
@@ -0,0 +1,851 @@
+/*
+ * SGI IOC3 master driver and IRQ demuxer
+ *
+ * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
+ * Heavily based on similar work by:
+ *   Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
+ *   Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ioc3.h>
+#include <linux/rwsem.h>
+
+#define IOC3_PCI_SIZE 0x100000
+
+static LIST_HEAD(ioc3_devices);
+static int ioc3_counter;
+static DECLARE_RWSEM(ioc3_devices_rwsem);
+
+static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
+static struct ioc3_submodule *ioc3_ethernet;
+static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED;
+
+/* NIC probing code */
+
+#define GPCR_MLAN_EN    0x00200000      /* enable MCR to pin 8 */
+
+static inline unsigned mcr_pack(unsigned pulse, unsigned sample)
+{
+	return (pulse << 10) | (sample << 2);
+}
+
+static int nic_wait(struct ioc3_driver_data *idd)
+{
+	volatile unsigned mcr;
+
+        do {
+                mcr = (volatile unsigned)idd->vma->mcr;
+        } while (!(mcr & 2));
+
+        return mcr & 1;
+}
+
+static int nic_reset(struct ioc3_driver_data *idd)
+{
+        int presence;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	idd->vma->mcr = mcr_pack(500, 65);
+	presence = nic_wait(idd);
+	local_irq_restore(flags);
+
+	udelay(500);
+
+        return presence;
+}
+
+static inline int nic_read_bit(struct ioc3_driver_data *idd)
+{
+	int result;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	idd->vma->mcr = mcr_pack(6, 13);
+	result = nic_wait(idd);
+	local_irq_restore(flags);
+
+	udelay(500);
+
+	return result;
+}
+
+static inline void nic_write_bit(struct ioc3_driver_data *idd, int bit)
+{
+	if (bit)
+		idd->vma->mcr = mcr_pack(6, 110);
+	else
+		idd->vma->mcr = mcr_pack(80, 30);
+
+	nic_wait(idd);
+}
+
+static unsigned nic_read_byte(struct ioc3_driver_data *idd)
+{
+	unsigned result = 0;
+	int i;
+
+	for (i = 0; i < 8; i++)
+		result = (result >> 1) | (nic_read_bit(idd) << 7);
+
+	return result;
+}
+
+static void nic_write_byte(struct ioc3_driver_data *idd, int byte)
+{
+	int i, bit;
+
+	for (i = 8; i; i--) {
+		bit = byte & 1;
+		byte >>= 1;
+
+		nic_write_bit(idd, bit);
+	}
+}
+
+static unsigned long
+nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr)
+{
+	int a, b, index, disc;
+
+	nic_reset(idd);
+
+	/* Search ROM.  */
+	nic_write_byte(idd, 0xF0);
+
+	/* Algorithm from ``Book of iButton Standards''.  */
+	for (index = 0, disc = 0; index < 64; index++) {
+		a = nic_read_bit(idd);
+		b = nic_read_bit(idd);
+
+		if (a && b) {
+			printk(KERN_WARNING "IOC3 NIC search failed.\n");
+			*last = 0;
+			return 0;
+		}
+
+		if (!a && !b) {
+			if (index == *last) {
+				addr |= 1UL << index;
+			} else if (index > *last) {
+				addr &= ~(1UL << index);
+				disc = index;
+			} else if ((addr & (1UL << index)) == 0)
+				disc = index;
+			nic_write_bit(idd, (addr>>index)&1);
+			continue;
+		} else {
+			if (a)
+				addr |= 1UL << index;
+			else
+				addr &= ~(1UL << index);
+			nic_write_bit(idd, a);
+			continue;
+		}
+	}
+	*last = disc;
+	return addr;
+}
+
+static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr)
+{
+	int index;
+
+	nic_reset(idd);
+	nic_write_byte(idd, 0xF0);
+	for (index = 0; index < 64; index++) {
+		nic_read_bit(idd);
+		nic_read_bit(idd);
+		nic_write_bit(idd, (addr>>index)&1);
+	}
+}
+
+static void crc16_byte(unsigned int *crc, unsigned char db)
+{
+	int i;
+
+	for(i=0;i<8;i++) {
+		*crc <<= 1;
+		if((db^(*crc>>16)) & 1)
+			*crc ^= 0x8005;
+		db >>= 1;
+	}
+	*crc &= 0xFFFF;
+}
+
+static unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc)
+{
+	while(size--)
+		crc16_byte(&crc, *(dbs++));
+	return crc;
+}
+
+static void crc8_byte(unsigned int *crc, unsigned char db)
+{
+	int i,f;
+
+	for(i=0;i<8;i++) {
+		f = (*crc ^ db) & 1;
+		*crc >>= 1;
+		db >>= 1;
+		if(f)
+			*crc ^= 0x8c;
+	}
+	*crc &= 0xff;
+}
+
+static unsigned int crc8_addr(unsigned long addr)
+{
+	int i;
+	unsigned int crc = 0x00;
+
+	for(i=0;i<8;i++)
+		crc8_byte(&crc, addr>>(i<<3));
+	return crc;
+}
+
+static void
+read_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page,
+			unsigned char *redir, unsigned char *data)
+{
+	int loops = 16, i;
+
+	while(redir[page] != 0xFF) {
+		page = redir[page]^0xFF;
+		loops--;
+		if(loops<0) {
+			printk(KERN_ERR "IOC3: NIC circular redirection\n");
+			return;
+		}
+	}
+	loops = 3;
+	while(loops>0) {
+		nic_addr(idd, addr);
+		nic_write_byte(idd, 0xF0);
+		nic_write_byte(idd, (page << 5) & 0xE0);
+		nic_write_byte(idd, (page >> 3) & 0x1F);
+		for(i=0;i<0x20;i++)
+			data[i] = nic_read_byte(idd);
+		if(crc16_area(data, 0x20, 0x0000) == 0x800d)
+			return;
+		loops--;
+	}
+	printk(KERN_ERR "IOC3: CRC error in data page\n");
+	for(i=0;i<0x20;i++)
+		data[i] = 0x00;
+}
+
+static void
+read_redir_map(struct ioc3_driver_data *idd, unsigned long addr,
+					 unsigned char *redir)
+{
+	int i,j,loops = 3,crc_ok;
+	unsigned int crc;
+
+	while(loops>0) {
+		crc_ok = 1;
+		nic_addr(idd, addr);
+		nic_write_byte(idd, 0xAA);
+		nic_write_byte(idd, 0x00);
+		nic_write_byte(idd, 0x01);
+		for(i=0;i<64;i+=8) {
+			for(j=0;j<8;j++)
+				redir[i+j] = nic_read_byte(idd);
+			crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000);
+			crc16_byte(&crc, nic_read_byte(idd));
+			crc16_byte(&crc, nic_read_byte(idd));
+			if(crc != 0x800d)
+				crc_ok = 0;
+		}
+		if(crc_ok)
+			return;
+		loops--;
+	}
+	printk(KERN_ERR "IOC3: CRC error in redirection page\n");
+	for(i=0;i<64;i++)
+		redir[i] = 0xFF;
+}
+
+static void read_nic(struct ioc3_driver_data *idd, unsigned long addr)
+{
+	unsigned char redir[64];
+	unsigned char data[64],part[32];
+	int i,j;
+
+	/* read redirections */
+	read_redir_map(idd, addr, redir);
+	/* read data pages */
+	read_redir_page(idd, addr, 0, redir, data);
+	read_redir_page(idd, addr, 1, redir, data+32);
+	/* assemble the part # */
+	j=0;
+	for(i=0;i<19;i++)
+		if(data[i+11] != ' ')
+			part[j++] = data[i+11];
+	for(i=0;i<6;i++)
+		if(data[i+32] != ' ')
+			part[j++] = data[i+32];
+	part[j] = 0;
+	/* skip Octane power supplies */
+	if(!strncmp(part, "060-0035-", 9))
+		return;
+	if(!strncmp(part, "060-0038-", 9))
+		return;
+	strcpy(idd->nic_part, part);
+	/* assemble the serial # */
+	j=0;
+	for(i=0;i<10;i++)
+		if(data[i+1] != ' ')
+			idd->nic_serial[j++] = data[i+1];
+	idd->nic_serial[j] = 0;
+}
+
+static void read_mac(struct ioc3_driver_data *idd, unsigned long addr)
+{
+	int i, loops = 3;
+	unsigned char data[13];
+
+	while(loops>0) {
+		nic_addr(idd, addr);
+		nic_write_byte(idd, 0xF0);
+		nic_write_byte(idd, 0x00);
+		nic_write_byte(idd, 0x00);
+		nic_read_byte(idd);
+		for(i=0;i<13;i++)
+			data[i] = nic_read_byte(idd);
+		if(crc16_area(data, 13, 0x0000) == 0x800d) {
+			for(i=10;i>4;i--)
+				idd->nic_mac[10-i] = data[i];
+			return;
+		}
+		loops--;
+	}
+	printk(KERN_ERR "IOC3: CRC error in MAC address\n");
+	for(i=0;i<6;i++)
+		idd->nic_mac[i] = 0x00;
+}
+
+static void probe_nic(struct ioc3_driver_data *idd)
+{
+        int save = 0, loops = 3;
+        unsigned long first, addr;
+
+        idd->vma->gpcr_s = GPCR_MLAN_EN;
+
+        while(loops>0) {
+                idd->nic_part[0] = 0;
+                idd->nic_serial[0] = 0;
+                addr = first = nic_find(idd, &save, 0);
+                if(!first)
+                        return;
+                while(1) {
+                        if(crc8_addr(addr))
+                                break;
+                        else {
+                                switch(addr & 0xFF) {
+                                case 0x0B:
+                                        read_nic(idd, addr);
+                                        break;
+                                case 0x09:
+                                case 0x89:
+                                case 0x91:
+                                        read_mac(idd, addr);
+                                        break;
+                                }
+                        }
+                        addr = nic_find(idd, &save, addr);
+                        if(addr == first)
+                                return;
+                }
+                loops--;
+        }
+        printk(KERN_ERR "IOC3: CRC error in NIC address\n");
+}
+
+/* Interrupts */
+
+static inline void
+write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&idd->ir_lock, flags);
+	switch (which) {
+	case IOC3_W_IES:
+		writel(val, &idd->vma->sio_ies);
+		break;
+	case IOC3_W_IEC:
+		writel(val, &idd->vma->sio_iec);
+		break;
+	}
+	spin_unlock_irqrestore(&idd->ir_lock, flags);
+}
+static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd)
+{
+	unsigned long flag;
+	uint32_t intrs = 0;
+
+	spin_lock_irqsave(&idd->ir_lock, flag);
+	intrs = readl(&idd->vma->sio_ir);
+	intrs &= readl(&idd->vma->sio_ies);
+	spin_unlock_irqrestore(&idd->ir_lock, flag);
+	return intrs;
+}
+
+static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+	int handled = 1, id;
+	unsigned int pending;
+
+	read_lock_irqsave(&ioc3_submodules_lock, flags);
+
+	if(idd->dual_irq && idd->vma->eisr) {
+		/* send Ethernet IRQ to the driver */
+		if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
+						ioc3_ethernet->intr) {
+			handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
+							idd, 0, regs);
+		}
+	}
+	pending = get_pending_intrs(idd);	/* look at the IO IRQs */
+
+	for(id=0;id<IOC3_MAX_SUBMODULES;id++) {
+		if(idd->active[id] && ioc3_submodules[id]
+				&& (pending & ioc3_submodules[id]->irq_mask)
+				&& ioc3_submodules[id]->intr) {
+			write_ireg(idd, ioc3_submodules[id]->irq_mask,
+							IOC3_W_IEC);
+			if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
+				   idd, pending & ioc3_submodules[id]->irq_mask,
+					regs))
+				pending &= ~ioc3_submodules[id]->irq_mask;
+			if (ioc3_submodules[id]->reset_mask)
+				write_ireg(idd, ioc3_submodules[id]->irq_mask,
+							IOC3_W_IES);
+		}
+	}
+	read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+	if(pending) {
+		printk(KERN_WARNING
+		  "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending);
+		write_ireg(idd, pending, IOC3_W_IEC);
+		handled = 1;
+	}
+	return handled?IRQ_HANDLED:IRQ_NONE;
+}
+
+static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+	int handled = 1;
+
+	if(!idd->dual_irq)
+		return IRQ_NONE;
+	read_lock_irqsave(&ioc3_submodules_lock, flags);
+	if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
+				&& ioc3_ethernet->intr)
+		handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0,
+								regs);
+	read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+	return handled?IRQ_HANDLED:IRQ_NONE;
+}
+
+void ioc3_enable(struct ioc3_submodule *is,
+				struct ioc3_driver_data *idd, unsigned int irqs)
+{
+	write_ireg(idd, irqs & is->irq_mask, IOC3_W_IES);
+}
+
+void ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd,
+				unsigned int irqs)
+{
+	writel(irqs & is->irq_mask, &idd->vma->sio_ir);
+}
+
+void ioc3_disable(struct ioc3_submodule *is,
+				struct ioc3_driver_data *idd, unsigned int irqs)
+{
+	write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC);
+}
+
+void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&idd->gpio_lock, flags);
+	writel(val, &idd->vma->gpcr_s);
+	spin_unlock_irqrestore(&idd->gpio_lock, flags);
+}
+
+/* Keep it simple, stupid! */
+static int find_slot(void **tab, int max)
+{
+	int i;
+	for(i=0;i<max;i++)
+		if(!(tab[i]))
+			return i;
+	return -1;
+}
+
+/* Register an IOC3 submodule */
+int ioc3_register_submodule(struct ioc3_submodule *is)
+{
+	struct ioc3_driver_data *idd;
+	int alloc_id;
+	unsigned long flags;
+
+	write_lock_irqsave(&ioc3_submodules_lock, flags);
+	alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES);
+	if(alloc_id != -1) {
+		ioc3_submodules[alloc_id] = is;
+		if(is->ethernet) {
+			if(ioc3_ethernet==NULL)
+				ioc3_ethernet=is;
+			else
+				printk(KERN_WARNING
+				  "IOC3 Ethernet module already registered!\n");
+		}
+	}
+	write_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
+	if(alloc_id == -1) {
+		printk(KERN_WARNING "Increase IOC3_MAX_SUBMODULES!\n");
+		return -ENOMEM;
+	}
+
+	is->id=alloc_id;
+
+	/* Initialize submodule for each IOC3 */
+	if (!is->probe)
+		return 0;
+
+	down_read(&ioc3_devices_rwsem);
+	list_for_each_entry(idd, &ioc3_devices, list) {
+		/* set to 1 for IRQs in probe */
+		idd->active[alloc_id] = 1;
+		idd->active[alloc_id] = !is->probe(is, idd);
+	}
+	up_read(&ioc3_devices_rwsem);
+
+	return 0;
+}
+
+/* Unregister an IOC3 submodule */
+void ioc3_unregister_submodule(struct ioc3_submodule *is)
+{
+	struct ioc3_driver_data *idd;
+	unsigned long flags;
+
+	write_lock_irqsave(&ioc3_submodules_lock, flags);
+	if(ioc3_submodules[is->id]==is)
+		ioc3_submodules[is->id]=NULL;
+	else
+		printk(KERN_WARNING
+			"IOC3 submodule %s has wrong ID.\n",is->name);
+	if(ioc3_ethernet==is)
+		ioc3_ethernet = NULL;
+	write_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
+	/* Remove submodule for each IOC3 */
+	down_read(&ioc3_devices_rwsem);
+	list_for_each_entry(idd, &ioc3_devices, list)
+		if(idd->active[is->id]) {
+			if(is->remove)
+				if(is->remove(is, idd))
+					printk(KERN_WARNING
+					       "%s: IOC3 submodule %s remove failed "
+					       "for pci_dev %s.\n",
+					       __FUNCTION__, module_name(is->owner),
+					       pci_name(idd->pdev));
+			idd->active[is->id] = 0;
+			if(is->irq_mask)
+				write_ireg(idd, is->irq_mask, IOC3_W_IEC);
+		}
+	up_read(&ioc3_devices_rwsem);
+}
+
+/*********************
+ * Device management *
+ *********************/
+
+static char *
+ioc3_class_names[]={"unknown", "IP27 BaseIO", "IP30 system", "MENET 1/2/3",
+			"MENET 4", "CADduo", "Altix Serial"};
+
+static int ioc3_class(struct ioc3_driver_data *idd)
+{
+	int res = IOC3_CLASS_NONE;
+	/* NIC-based logic */
+	if(!strncmp(idd->nic_part, "030-0891-", 9))
+		res = IOC3_CLASS_BASE_IP30;
+	if(!strncmp(idd->nic_part, "030-1155-", 9))
+		res = IOC3_CLASS_CADDUO;
+	if(!strncmp(idd->nic_part, "030-1657-", 9))
+		res = IOC3_CLASS_SERIAL;
+	if(!strncmp(idd->nic_part, "030-1664-", 9))
+		res = IOC3_CLASS_SERIAL;
+	/* total random heuristics */
+#ifdef CONFIG_SGI_IP27
+	if(!idd->nic_part[0])
+		res = IOC3_CLASS_BASE_IP27;
+#endif
+	/* print educational message */
+	printk(KERN_INFO "IOC3 part: [%s], serial: [%s] => class %s\n",
+			idd->nic_part, idd->nic_serial, ioc3_class_names[res]);
+	return res;
+}
+/* Adds a new instance of an IOC3 card */
+static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+	struct ioc3_driver_data *idd;
+	uint32_t pcmd;
+	int ret, id;
+
+	/* Enable IOC3 and take ownership of it */
+	if ((ret = pci_enable_device(pdev))) {
+		printk(KERN_WARNING
+		       "%s: Failed to enable IOC3 device for pci_dev %s.\n",
+		       __FUNCTION__, pci_name(pdev));
+		goto out;
+	}
+	pci_set_master(pdev);
+
+#ifdef USE_64BIT_DMA
+        ret = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+        if (!ret) {
+                ret = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+                if (ret < 0) {
+                        printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA "
+                               "for consistent allocations\n",
+				__FUNCTION__);
+                }
+	}
+#endif
+
+	/* Set up per-IOC3 data */
+	idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+	if (!idd) {
+		printk(KERN_WARNING
+		       "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
+		       __FUNCTION__, pci_name(pdev));
+		ret = -ENODEV;
+		goto out_idd;
+	}
+	memset(idd, 0, sizeof(struct ioc3_driver_data));
+	spin_lock_init(&idd->ir_lock);
+	spin_lock_init(&idd->gpio_lock);
+	idd->pdev = pdev;
+
+	/* Map all IOC3 registers.  These are shared between subdevices
+	 * so the main IOC3 module manages them.
+	 */
+	idd->pma = pci_resource_start(pdev, 0);
+	if (!idd->pma) {
+		printk(KERN_WARNING
+		       "%s: Unable to find IOC3 resource "
+		       "for pci_dev %s.\n",
+		       __FUNCTION__, pci_name(pdev));
+		ret = -ENODEV;
+		goto out_pci;
+	}
+	if (!request_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
+		printk(KERN_WARNING
+		       "%s: Unable to request IOC3 region "
+		       "for pci_dev %s.\n",
+		       __FUNCTION__, pci_name(pdev));
+		ret = -ENODEV;
+		goto out_pci;
+	}
+	idd->vma = ioremap(idd->pma, IOC3_PCI_SIZE);
+	if (!idd->vma) {
+		printk(KERN_WARNING
+		       "%s: Unable to remap IOC3 region "
+		       "for pci_dev %s.\n",
+		       __FUNCTION__, pci_name(pdev));
+		ret = -ENODEV;
+		goto out_misc_region;
+	}
+
+	/* Track PCI-device specific data */
+	pci_set_drvdata(pdev, idd);
+	down_write(&ioc3_devices_rwsem);
+	list_add(&idd->list, &ioc3_devices);
+	idd->id = ioc3_counter++;
+	up_write(&ioc3_devices_rwsem);
+
+	idd->gpdr_shadow = idd->vma->gpdr;
+
+	/* Read IOC3 NIC contents */
+	probe_nic(idd);
+
+	/* Detect IOC3 class */
+	idd->class = ioc3_class(idd);
+
+	/* Initialize IOC3 */
+       pci_read_config_dword(pdev, PCI_COMMAND, &pcmd);
+       pci_write_config_dword(pdev, PCI_COMMAND,
+                               pcmd | PCI_COMMAND_MEMORY |
+                               PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
+                               PCI_SCR_DROP_MODE_EN);
+
+	write_ireg(idd, ~0, IOC3_W_IEC);
+	writel(~0, &idd->vma->sio_ir);
+
+	/* Set up IRQs */
+	if(idd->class == IOC3_CLASS_BASE_IP30
+				|| idd->class == IOC3_CLASS_BASE_IP27) {
+		writel(0, &idd->vma->eier);
+		writel(~0, &idd->vma->eisr);
+
+		idd->dual_irq = 1;
+		if (!request_irq(pdev->irq, ioc3_intr_eth, SA_SHIRQ,
+				 "ioc3-eth", (void *)idd)) {
+			idd->irq_eth = pdev->irq;
+		} else {
+			printk(KERN_WARNING
+			       "%s : request_irq fails for IRQ 0x%x\n ",
+			       __FUNCTION__, pdev->irq);
+		}
+		if (!request_irq(pdev->irq+2, ioc3_intr_io, SA_SHIRQ,
+				 "ioc3-io", (void *)idd)) {
+			idd->irq_io = pdev->irq+2;
+		} else {
+			printk(KERN_WARNING
+			       "%s : request_irq fails for IRQ 0x%x\n ",
+			       __FUNCTION__, pdev->irq+2);
+		}
+	} else {
+		if (!request_irq(pdev->irq, ioc3_intr_io, SA_SHIRQ,
+				 "ioc3", (void *)idd)) {
+			idd->irq_io = pdev->irq;
+		} else {
+			printk(KERN_WARNING
+			       "%s : request_irq fails for IRQ 0x%x\n ",
+			       __FUNCTION__, pdev->irq);
+		}
+	}
+
+	/* Add this IOC3 to all submodules */
+	read_lock(&ioc3_submodules_lock);
+	for(id=0;id<IOC3_MAX_SUBMODULES;id++)
+		if(ioc3_submodules[id] && ioc3_submodules[id]->probe) {
+			idd->active[id] = 1;
+			idd->active[id] = !ioc3_submodules[id]->probe
+						(ioc3_submodules[id], idd);
+		}
+	read_unlock(&ioc3_submodules_lock);
+
+	printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev));
+
+	return 0;
+
+out_misc_region:
+	release_region(idd->pma, IOC3_PCI_SIZE);
+out_pci:
+	kfree(idd);
+out_idd:
+	pci_disable_device(pdev);
+out:
+	return ret;
+}
+
+/* Removes a particular instance of an IOC3 card. */
+static void ioc3_remove(struct pci_dev *pdev)
+{
+	int id;
+	struct ioc3_driver_data *idd;
+
+	idd = pci_get_drvdata(pdev);
+
+	/* Remove this IOC3 from all submodules */
+	read_lock(&ioc3_submodules_lock);
+	for(id=0;id<IOC3_MAX_SUBMODULES;id++)
+		if(idd->active[id]) {
+			if(ioc3_submodules[id] && ioc3_submodules[id]->remove)
+				if(ioc3_submodules[id]->remove(ioc3_submodules[id],
+								idd))
+					printk(KERN_WARNING
+					       "%s: IOC3 submodule 0x%s remove failed "
+					       "for pci_dev %s.\n",
+					        __FUNCTION__,
+						module_name(ioc3_submodules[id]->owner),
+					        pci_name(pdev));
+			idd->active[id] = 0;
+		}
+	read_unlock(&ioc3_submodules_lock);
+
+	/* Clear and disable all IRQs */
+	write_ireg(idd, ~0, IOC3_W_IEC);
+	writel(~0, &idd->vma->sio_ir);
+
+	/* Release resources */
+	free_irq(idd->irq_io, (void *)idd);
+	if(idd->dual_irq)
+		free_irq(idd->irq_eth, (void *)idd);
+	iounmap(idd->vma);
+	release_region(idd->pma, IOC3_PCI_SIZE);
+
+	/* Disable IOC3 and relinquish */
+	pci_disable_device(pdev);
+
+	/* Remove and free driver data */
+	down_write(&ioc3_devices_rwsem);
+	list_del(&idd->list);
+	up_write(&ioc3_devices_rwsem);
+	kfree(idd);
+}
+
+static struct pci_device_id ioc3_id_table[] = {
+	{PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID},
+	{0}
+};
+
+static struct pci_driver ioc3_driver = {
+	.name = "IOC3",
+	.id_table = ioc3_id_table,
+	.probe = ioc3_probe,
+	.remove = ioc3_remove,
+};
+
+MODULE_DEVICE_TABLE(pci, ioc3_id_table);
+
+/*********************
+ * Module management *
+ *********************/
+
+/* Module load */
+static int __devinit ioc3_init(void)
+{
+	if (ia64_platform_is("sn2"))
+		return pci_register_driver(&ioc3_driver);
+	return 0;
+}
+
+/* Module unload */
+static void __devexit ioc3_exit(void)
+{
+	pci_unregister_driver(&ioc3_driver);
+}
+
+module_init(ioc3_init);
+module_exit(ioc3_exit);
+
+MODULE_AUTHOR("Stanislaw Skowronek <skylark@linux-mips.org>");
+MODULE_DESCRIPTION("PCI driver for SGI IOC3");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc3_register_submodule);
+EXPORT_SYMBOL(ioc3_unregister_submodule);
+EXPORT_SYMBOL(ioc3_ack);
+EXPORT_SYMBOL(ioc3_gpcr_set);
+EXPORT_SYMBOL(ioc3_disable);
+EXPORT_SYMBOL(ioc3_enable);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
new file mode 100644
index 0000000..b77dbd6
--- /dev/null
+++ b/drivers/spi/Kconfig
@@ -0,0 +1,109 @@
+#
+# SPI driver configuration
+#
+# NOTE:  the reason this doesn't show SPI slave support is mostly that
+# nobody's needed a slave side API yet.  The master-role API is not
+# fully appropriate there, so it'd need some thought to do well.
+#
+menu "SPI support"
+
+config SPI
+	bool "SPI support"
+	help
+	  The "Serial Peripheral Interface" is a low level synchronous
+	  protocol.  Chips that support SPI can have data transfer rates
+	  up to several tens of Mbit/sec.  Chips are addressed with a
+	  controller and a chipselect.  Most SPI slaves don't support
+	  dynamic device discovery; some are even write-only or read-only.
+
+	  SPI is widely used by microcontollers to talk with sensors,
+	  eeprom and flash memory, codecs and various other controller
+	  chips, analog to digital (and d-to-a) converters, and more.
+	  MMC and SD cards can be accessed using SPI protocol; and for
+	  DataFlash cards used in MMC sockets, SPI must always be used.
+
+	  SPI is one of a family of similar protocols using a four wire
+	  interface (select, clock, data in, data out) including Microwire
+	  (half duplex), SSP, SSI, and PSP.  This driver framework should
+	  work with most such devices and controllers.
+
+config SPI_DEBUG
+	boolean "Debug support for SPI drivers"
+	depends on SPI && DEBUG_KERNEL
+	help
+	  Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
+	  sysfs, and debugfs support in SPI controller and protocol drivers.
+
+#
+# MASTER side ... talking to discrete SPI slave chips including microcontrollers
+#
+
+config SPI_MASTER
+#	boolean "SPI Master Support"
+	boolean
+	default SPI
+	help
+	  If your system has an master-capable SPI controller (which
+	  provides the clock and chipselect), you can enable that
+	  controller and the protocol drivers for the SPI slave chips
+	  that are connected.
+
+comment "SPI Master Controller Drivers"
+	depends on SPI_MASTER
+
+config SPI_BITBANG
+	tristate "Bitbanging SPI master"
+	depends on SPI_MASTER && EXPERIMENTAL
+	help
+	  With a few GPIO pins, your system can bitbang the SPI protocol.
+	  Select this to get SPI support through I/O pins (GPIO, parallel
+	  port, etc).  Or, some systems' SPI master controller drivers use
+	  this code to manage the per-word or per-transfer accesses to the
+	  hardware shift registers.
+
+	  This is library code, and is automatically selected by drivers that
+	  need it.  You only need to select this explicitly to support driver
+	  modules that aren't part of this kernel tree.
+
+config SPI_BUTTERFLY
+	tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+	depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+	select SPI_BITBANG
+	help
+	  This uses a custom parallel port cable to connect to an AVR
+	  Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+	  inexpensive battery powered microcontroller evaluation board.
+	  This same cable can be used to flash new firmware.
+
+config SPI_BUTTERFLY
+	tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+	depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+	select SPI_BITBANG
+	help
+	  This uses a custom parallel port cable to connect to an AVR
+	  Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+	  inexpensive battery powered microcontroller evaluation board.
+	  This same cable can be used to flash new firmware.
+
+#
+# Add new SPI master controllers in alphabetical order above this line
+#
+
+
+#
+# There are lots of SPI device types, with sensors and memory
+# being probably the most widely used ones.
+#
+comment "SPI Protocol Masters"
+	depends on SPI_MASTER
+
+
+#
+# Add new SPI protocol masters in alphabetical order above this line
+#
+
+
+# (slave support would go here)
+
+endmenu # "SPI support"
+
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
new file mode 100644
index 0000000..c2c87e8
--- /dev/null
+++ b/drivers/spi/Makefile
@@ -0,0 +1,25 @@
+#
+# Makefile for kernel SPI drivers.
+#
+
+ifeq ($(CONFIG_SPI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+# small core, mostly translating board-specific
+# config declarations into driver model code
+obj-$(CONFIG_SPI_MASTER)		+= spi.o
+
+# SPI master controller drivers (bus)
+obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
+obj-$(CONFIG_SPI_BUTTERFLY)		+= spi_butterfly.o
+# 	... add above this line ...
+
+# SPI protocol drivers (device/link on bus)
+# 	... add above this line ...
+
+# SPI slave controller drivers (upstream link)
+# 	... add above this line ...
+
+# SPI slave drivers (protocol for that link)
+# 	... add above this line ...
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
new file mode 100644
index 0000000..791c4dc
--- /dev/null
+++ b/drivers/spi/spi.c
@@ -0,0 +1,642 @@
+/*
+ * spi.c - SPI init/core code
+ *
+ * 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.
+ *
+ * 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/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/spi/spi.h>
+
+
+/* SPI bustype and spi_master class are registered after board init code
+ * provides the SPI device tables, ensuring that both are present by the
+ * time controller driver registration causes spi_devices to "enumerate".
+ */
+static void spidev_release(struct device *dev)
+{
+	const struct spi_device	*spi = to_spi_device(dev);
+
+	/* spi masters may cleanup for released devices */
+	if (spi->master->cleanup)
+		spi->master->cleanup(spi);
+
+	spi_master_put(spi->master);
+	kfree(dev);
+}
+
+static ssize_t
+modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+{
+	const struct spi_device	*spi = to_spi_device(dev);
+
+	return snprintf(buf, BUS_ID_SIZE + 1, "%s\n", spi->modalias);
+}
+
+static struct device_attribute spi_dev_attrs[] = {
+	__ATTR_RO(modalias),
+	__ATTR_NULL,
+};
+
+/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
+ * and the sysfs version makes coldplug work too.
+ */
+
+static int spi_match_device(struct device *dev, struct device_driver *drv)
+{
+	const struct spi_device	*spi = to_spi_device(dev);
+
+	return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
+}
+
+static int spi_uevent(struct device *dev, char **envp, int num_envp,
+		char *buffer, int buffer_size)
+{
+	const struct spi_device		*spi = to_spi_device(dev);
+
+	envp[0] = buffer;
+	snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
+	envp[1] = NULL;
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+/*
+ * NOTE:  the suspend() method for an spi_master controller driver
+ * should verify that all its child devices are marked as suspended;
+ * suspend requests delivered through sysfs power/state files don't
+ * enforce such constraints.
+ */
+static int spi_suspend(struct device *dev, pm_message_t message)
+{
+	int			value;
+	struct spi_driver	*drv = to_spi_driver(dev->driver);
+
+	if (!drv->suspend)
+		return 0;
+
+	/* suspend will stop irqs and dma; no more i/o */
+	value = drv->suspend(to_spi_device(dev), message);
+	if (value == 0)
+		dev->power.power_state = message;
+	return value;
+}
+
+static int spi_resume(struct device *dev)
+{
+	int			value;
+	struct spi_driver	*drv = to_spi_driver(dev->driver);
+
+	if (!drv->resume)
+		return 0;
+
+	/* resume may restart the i/o queue */
+	value = drv->resume(to_spi_device(dev));
+	if (value == 0)
+		dev->power.power_state = PMSG_ON;
+	return value;
+}
+
+#else
+#define spi_suspend	NULL
+#define spi_resume	NULL
+#endif
+
+struct bus_type spi_bus_type = {
+	.name		= "spi",
+	.dev_attrs	= spi_dev_attrs,
+	.match		= spi_match_device,
+	.uevent		= spi_uevent,
+	.suspend	= spi_suspend,
+	.resume		= spi_resume,
+};
+EXPORT_SYMBOL_GPL(spi_bus_type);
+
+
+static int spi_drv_probe(struct device *dev)
+{
+	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
+
+	return sdrv->probe(to_spi_device(dev));
+}
+
+static int spi_drv_remove(struct device *dev)
+{
+	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
+
+	return sdrv->remove(to_spi_device(dev));
+}
+
+static void spi_drv_shutdown(struct device *dev)
+{
+	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
+
+	sdrv->shutdown(to_spi_device(dev));
+}
+
+int spi_register_driver(struct spi_driver *sdrv)
+{
+	sdrv->driver.bus = &spi_bus_type;
+	if (sdrv->probe)
+		sdrv->driver.probe = spi_drv_probe;
+	if (sdrv->remove)
+		sdrv->driver.remove = spi_drv_remove;
+	if (sdrv->shutdown)
+		sdrv->driver.shutdown = spi_drv_shutdown;
+	return driver_register(&sdrv->driver);
+}
+EXPORT_SYMBOL_GPL(spi_register_driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* SPI devices should normally not be created by SPI device drivers; that
+ * would make them board-specific.  Similarly with SPI master drivers.
+ * Device registration normally goes into like arch/.../mach.../board-YYY.c
+ * with other readonly (flashable) information about mainboard devices.
+ */
+
+struct boardinfo {
+	struct list_head	list;
+	unsigned		n_board_info;
+	struct spi_board_info	board_info[0];
+};
+
+static LIST_HEAD(board_list);
+static DECLARE_MUTEX(board_lock);
+
+
+/* On typical mainboards, this is purely internal; and it's not needed
+ * after board init creates the hard-wired devices.  Some development
+ * platforms may not be able to use spi_register_board_info though, and
+ * this is exported so that for example a USB or parport based adapter
+ * driver could add devices (which it would learn about out-of-band).
+ */
+struct spi_device *__init_or_module
+spi_new_device(struct spi_master *master, struct spi_board_info *chip)
+{
+	struct spi_device	*proxy;
+	struct device		*dev = master->cdev.dev;
+	int			status;
+
+	/* NOTE:  caller did any chip->bus_num checks necessary */
+
+	if (!spi_master_get(master))
+		return NULL;
+
+	proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
+	if (!proxy) {
+		dev_err(dev, "can't alloc dev for cs%d\n",
+			chip->chip_select);
+		goto fail;
+	}
+	proxy->master = master;
+	proxy->chip_select = chip->chip_select;
+	proxy->max_speed_hz = chip->max_speed_hz;
+	proxy->irq = chip->irq;
+	proxy->modalias = chip->modalias;
+
+	snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
+			"%s.%u", master->cdev.class_id,
+			chip->chip_select);
+	proxy->dev.parent = dev;
+	proxy->dev.bus = &spi_bus_type;
+	proxy->dev.platform_data = (void *) chip->platform_data;
+	proxy->controller_data = chip->controller_data;
+	proxy->controller_state = NULL;
+	proxy->dev.release = spidev_release;
+
+	/* drivers may modify this default i/o setup */
+	status = master->setup(proxy);
+	if (status < 0) {
+		dev_dbg(dev, "can't %s %s, status %d\n",
+				"setup", proxy->dev.bus_id, status);
+		goto fail;
+	}
+
+	/* driver core catches callers that misbehave by defining
+	 * devices that already exist.
+	 */
+	status = device_register(&proxy->dev);
+	if (status < 0) {
+		dev_dbg(dev, "can't %s %s, status %d\n",
+				"add", proxy->dev.bus_id, status);
+		goto fail;
+	}
+	dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
+	return proxy;
+
+fail:
+	spi_master_put(master);
+	kfree(proxy);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_new_device);
+
+/*
+ * Board-specific early init code calls this (probably during arch_initcall)
+ * with segments of the SPI device table.  Any device nodes are created later,
+ * after the relevant parent SPI controller (bus_num) is defined.  We keep
+ * this table of devices forever, so that reloading a controller driver will
+ * not make Linux forget about these hard-wired devices.
+ *
+ * Other code can also call this, e.g. a particular add-on board might provide
+ * SPI devices through its expansion connector, so code initializing that board
+ * would naturally declare its SPI devices.
+ *
+ * The board info passed can safely be __initdata ... but be careful of
+ * any embedded pointers (platform_data, etc), they're copied as-is.
+ */
+int __init
+spi_register_board_info(struct spi_board_info const *info, unsigned n)
+{
+	struct boardinfo	*bi;
+
+	bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+	if (!bi)
+		return -ENOMEM;
+	bi->n_board_info = n;
+	memcpy(bi->board_info, info, n * sizeof *info);
+
+	down(&board_lock);
+	list_add_tail(&bi->list, &board_list);
+	up(&board_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_register_board_info);
+
+/* FIXME someone should add support for a __setup("spi", ...) that
+ * creates board info from kernel command lines
+ */
+
+static void __init_or_module
+scan_boardinfo(struct spi_master *master)
+{
+	struct boardinfo	*bi;
+	struct device		*dev = master->cdev.dev;
+
+	down(&board_lock);
+	list_for_each_entry(bi, &board_list, list) {
+		struct spi_board_info	*chip = bi->board_info;
+		unsigned		n;
+
+		for (n = bi->n_board_info; n > 0; n--, chip++) {
+			if (chip->bus_num != master->bus_num)
+				continue;
+			/* some controllers only have one chip, so they
+			 * might not use chipselects.  otherwise, the
+			 * chipselects are numbered 0..max.
+			 */
+			if (chip->chip_select >= master->num_chipselect
+					&& master->num_chipselect) {
+				dev_dbg(dev, "cs%d > max %d\n",
+					chip->chip_select,
+					master->num_chipselect);
+				continue;
+			}
+			(void) spi_new_device(master, chip);
+		}
+	}
+	up(&board_lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_master_release(struct class_device *cdev)
+{
+	struct spi_master *master;
+
+	master = container_of(cdev, struct spi_master, cdev);
+	kfree(master);
+}
+
+static struct class spi_master_class = {
+	.name		= "spi_master",
+	.owner		= THIS_MODULE,
+	.release	= spi_master_release,
+};
+
+
+/**
+ * spi_alloc_master - allocate SPI master controller
+ * @dev: the controller, possibly using the platform_bus
+ * @size: how much driver-private data to preallocate; the pointer to this
+ * 	memory is in the class_data field of the returned class_device,
+ *	accessible with spi_master_get_devdata().
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers.  It's how they allocate
+ * an spi_master structure, prior to calling spi_add_master().
+ *
+ * This must be called from context that can sleep.  It returns the SPI
+ * master structure on success, else NULL.
+ *
+ * The caller is responsible for assigning the bus number and initializing
+ * the master's methods before calling spi_add_master(); and (after errors
+ * adding the device) calling spi_master_put() to prevent a memory leak.
+ */
+struct spi_master * __init_or_module
+spi_alloc_master(struct device *dev, unsigned size)
+{
+	struct spi_master	*master;
+
+	if (!dev)
+		return NULL;
+
+	master = kzalloc(size + sizeof *master, SLAB_KERNEL);
+	if (!master)
+		return NULL;
+
+	class_device_initialize(&master->cdev);
+	master->cdev.class = &spi_master_class;
+	master->cdev.dev = get_device(dev);
+	spi_master_set_devdata(master, &master[1]);
+
+	return master;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_master);
+
+/**
+ * spi_register_master - register SPI master controller
+ * @master: initialized master, originally from spi_alloc_master()
+ *
+ * SPI master controllers connect to their drivers using some non-SPI bus,
+ * such as the platform bus.  The final stage of probe() in that code
+ * includes calling spi_register_master() to hook up to this SPI bus glue.
+ *
+ * SPI controllers use board specific (often SOC specific) bus numbers,
+ * and board-specific addressing for SPI devices combines those numbers
+ * with chip select numbers.  Since SPI does not directly support dynamic
+ * device identification, boards need configuration tables telling which
+ * chip is at which address.
+ *
+ * This must be called from context that can sleep.  It returns zero on
+ * success, else a negative error code (dropping the master's refcount).
+ * After a successful return, the caller is responsible for calling
+ * spi_unregister_master().
+ */
+int __init_or_module
+spi_register_master(struct spi_master *master)
+{
+	static atomic_t		dyn_bus_id = ATOMIC_INIT(0);
+	struct device		*dev = master->cdev.dev;
+	int			status = -ENODEV;
+	int			dynamic = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	/* convention:  dynamically assigned bus IDs count down from the max */
+	if (master->bus_num == 0) {
+		master->bus_num = atomic_dec_return(&dyn_bus_id);
+		dynamic = 1;
+	}
+
+	/* register the device, then userspace will see it.
+	 * registration fails if the bus ID is in use.
+	 */
+	snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
+		"spi%u", master->bus_num);
+	status = class_device_add(&master->cdev);
+	if (status < 0)
+		goto done;
+	dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
+			dynamic ? " (dynamic)" : "");
+
+	/* populate children from any spi device tables */
+	scan_boardinfo(master);
+	status = 0;
+done:
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_register_master);
+
+
+static int __unregister(struct device *dev, void *unused)
+{
+	/* note: before about 2.6.14-rc1 this would corrupt memory: */
+	spi_unregister_device(to_spi_device(dev));
+	return 0;
+}
+
+/**
+ * spi_unregister_master - unregister SPI master controller
+ * @master: the master being unregistered
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers.
+ *
+ * This must be called from context that can sleep.
+ */
+void spi_unregister_master(struct spi_master *master)
+{
+	(void) device_for_each_child(master->cdev.dev, NULL, __unregister);
+	class_device_unregister(&master->cdev);
+	master->cdev.dev = NULL;
+}
+EXPORT_SYMBOL_GPL(spi_unregister_master);
+
+/**
+ * spi_busnum_to_master - look up master associated with bus_num
+ * @bus_num: the master's bus number
+ *
+ * This call may be used with devices that are registered after
+ * arch init time.  It returns a refcounted pointer to the relevant
+ * spi_master (which the caller must release), or NULL if there is
+ * no such master registered.
+ */
+struct spi_master *spi_busnum_to_master(u16 bus_num)
+{
+	if (bus_num) {
+		char			name[8];
+		struct kobject		*bus;
+
+		snprintf(name, sizeof name, "spi%u", bus_num);
+		bus = kset_find_obj(&spi_master_class.subsys.kset, name);
+		if (bus)
+			return container_of(bus, struct spi_master, cdev.kobj);
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_complete(void *arg)
+{
+	complete(arg);
+}
+
+/**
+ * spi_sync - blocking/synchronous SPI data transfers
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers
+ *
+ * This call may only be used from a context that may sleep.  The sleep
+ * is non-interruptible, and has no timeout.  Low-overhead controller
+ * drivers may DMA directly into and out of the message buffers.
+ *
+ * Note that the SPI device's chip select is active during the message,
+ * and then is normally disabled between messages.  Drivers for some
+ * frequently-used devices may want to minimize costs of selecting a chip,
+ * by leaving it selected in anticipation that the next message will go
+ * to the same chip.  (That may increase power usage.)
+ *
+ * Also, the caller is guaranteeing that the memory associated with the
+ * message will not be freed before this call returns.
+ *
+ * The return value is a negative error code if the message could not be
+ * submitted, else zero.  When the value is zero, then message->status is
+ * also defined:  it's the completion code for the transfer, either zero
+ * or a negative error code from the controller driver.
+ */
+int spi_sync(struct spi_device *spi, struct spi_message *message)
+{
+	DECLARE_COMPLETION(done);
+	int status;
+
+	message->complete = spi_complete;
+	message->context = &done;
+	status = spi_async(spi, message);
+	if (status == 0)
+		wait_for_completion(&done);
+	message->context = NULL;
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_sync);
+
+#define	SPI_BUFSIZ	(SMP_CACHE_BYTES)
+
+static u8	*buf;
+
+/**
+ * spi_write_then_read - SPI synchronous write followed by read
+ * @spi: device with which data will be exchanged
+ * @txbuf: data to be written (need not be dma-safe)
+ * @n_tx: size of txbuf, in bytes
+ * @rxbuf: buffer into which data will be read
+ * @n_rx: size of rxbuf, in bytes (need not be dma-safe)
+ *
+ * This performs a half duplex MicroWire style transaction with the
+ * device, sending txbuf and then reading rxbuf.  The return value
+ * is zero for success, else a negative errno status code.
+ * This call may only be used from a context that may sleep.
+ *
+ * Parameters to this routine are always copied using a small buffer;
+ * performance-sensitive or bulk transfer code should instead use
+ * spi_{async,sync}() calls with dma-safe buffers.
+ */
+int spi_write_then_read(struct spi_device *spi,
+		const u8 *txbuf, unsigned n_tx,
+		u8 *rxbuf, unsigned n_rx)
+{
+	static DECLARE_MUTEX(lock);
+
+	int			status;
+	struct spi_message	message;
+	struct spi_transfer	x[2];
+	u8			*local_buf;
+
+	/* Use preallocated DMA-safe buffer.  We can't avoid copying here,
+	 * (as a pure convenience thing), but we can keep heap costs
+	 * out of the hot path ...
+	 */
+	if ((n_tx + n_rx) > SPI_BUFSIZ)
+		return -EINVAL;
+
+	spi_message_init(&message);
+	memset(x, 0, sizeof x);
+	if (n_tx) {
+		x[0].len = n_tx;
+		spi_message_add_tail(&x[0], &message);
+	}
+	if (n_rx) {
+		x[1].len = n_rx;
+		spi_message_add_tail(&x[1], &message);
+	}
+
+	/* ... unless someone else is using the pre-allocated buffer */
+	if (down_trylock(&lock)) {
+		local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
+		if (!local_buf)
+			return -ENOMEM;
+	} else
+		local_buf = buf;
+
+	memcpy(local_buf, txbuf, n_tx);
+	x[0].tx_buf = local_buf;
+	x[1].rx_buf = local_buf + n_tx;
+
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		memcpy(rxbuf, x[1].rx_buf, n_rx);
+		status = message.status;
+	}
+
+	if (x[0].tx_buf == buf)
+		up(&lock);
+	else
+		kfree(local_buf);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_write_then_read);
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spi_init(void)
+{
+	int	status;
+
+	buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
+	if (!buf) {
+		status = -ENOMEM;
+		goto err0;
+	}
+
+	status = bus_register(&spi_bus_type);
+	if (status < 0)
+		goto err1;
+
+	status = class_register(&spi_master_class);
+	if (status < 0)
+		goto err2;
+	return 0;
+
+err2:
+	bus_unregister(&spi_bus_type);
+err1:
+	kfree(buf);
+	buf = NULL;
+err0:
+	return status;
+}
+
+/* board_info is normally registered in arch_initcall(),
+ * but even essential drivers wait till later
+ *
+ * REVISIT only boardinfo really needs static linking. the rest (device and
+ * driver registration) _could_ be dynamically linked (modular) ... costs
+ * include needing to have boardinfo data structures be much more public.
+ */
+subsys_initcall(spi_init);
+
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
new file mode 100644
index 0000000..f037e55
--- /dev/null
+++ b/drivers/spi/spi_bitbang.c
@@ -0,0 +1,472 @@
+/*
+ * spi_bitbang.c - polling/bitbanging SPI master controller driver utilities
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * FIRST PART (OPTIONAL):  word-at-a-time spi_transfer support.
+ * Use this for GPIO or shift-register level hardware APIs.
+ *
+ * spi_bitbang_cs is in spi_device->controller_state, which is unavailable
+ * to glue code.  These bitbang setup() and cleanup() routines are always
+ * used, though maybe they're called from controller-aware code.
+ *
+ * chipselect() and friends may use use spi_device->controller_data and
+ * controller registers as appropriate.
+ *
+ *
+ * NOTE:  SPI controller pins can often be used as GPIO pins instead,
+ * which means you could use a bitbang driver either to get hardware
+ * working quickly, or testing for differences that aren't speed related.
+ */
+
+struct spi_bitbang_cs {
+	unsigned	nsecs;	/* (clock cycle time)/2 */
+	u32		(*txrx_word)(struct spi_device *spi, unsigned nsecs,
+					u32 word, u8 bits);
+	unsigned	(*txrx_bufs)(struct spi_device *,
+					u32 (*txrx_word)(
+						struct spi_device *spi,
+						unsigned nsecs,
+						u32 word, u8 bits),
+					unsigned, struct spi_transfer *);
+};
+
+static unsigned bitbang_txrx_8(
+	struct spi_device	*spi,
+	u32			(*txrx_word)(struct spi_device *spi,
+					unsigned nsecs,
+					u32 word, u8 bits),
+	unsigned		ns,
+	struct spi_transfer	*t
+) {
+	unsigned		bits = spi->bits_per_word;
+	unsigned		count = t->len;
+	const u8		*tx = t->tx_buf;
+	u8			*rx = t->rx_buf;
+
+	while (likely(count > 0)) {
+		u8		word = 0;
+
+		if (tx)
+			word = *tx++;
+		word = txrx_word(spi, ns, word, bits);
+		if (rx)
+			*rx++ = word;
+		count -= 1;
+	}
+	return t->len - count;
+}
+
+static unsigned bitbang_txrx_16(
+	struct spi_device	*spi,
+	u32			(*txrx_word)(struct spi_device *spi,
+					unsigned nsecs,
+					u32 word, u8 bits),
+	unsigned		ns,
+	struct spi_transfer	*t
+) {
+	unsigned		bits = spi->bits_per_word;
+	unsigned		count = t->len;
+	const u16		*tx = t->tx_buf;
+	u16			*rx = t->rx_buf;
+
+	while (likely(count > 1)) {
+		u16		word = 0;
+
+		if (tx)
+			word = *tx++;
+		word = txrx_word(spi, ns, word, bits);
+		if (rx)
+			*rx++ = word;
+		count -= 2;
+	}
+	return t->len - count;
+}
+
+static unsigned bitbang_txrx_32(
+	struct spi_device	*spi,
+	u32			(*txrx_word)(struct spi_device *spi,
+					unsigned nsecs,
+					u32 word, u8 bits),
+	unsigned		ns,
+	struct spi_transfer	*t
+) {
+	unsigned		bits = spi->bits_per_word;
+	unsigned		count = t->len;
+	const u32		*tx = t->tx_buf;
+	u32			*rx = t->rx_buf;
+
+	while (likely(count > 3)) {
+		u32		word = 0;
+
+		if (tx)
+			word = *tx++;
+		word = txrx_word(spi, ns, word, bits);
+		if (rx)
+			*rx++ = word;
+		count -= 4;
+	}
+	return t->len - count;
+}
+
+/**
+ * spi_bitbang_setup - default setup for per-word I/O loops
+ */
+int spi_bitbang_setup(struct spi_device *spi)
+{
+	struct spi_bitbang_cs	*cs = spi->controller_state;
+	struct spi_bitbang	*bitbang;
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	if (!cs) {
+		cs = kzalloc(sizeof *cs, SLAB_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+	bitbang = spi_master_get_devdata(spi->master);
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	/* spi_transfer level calls that work per-word */
+	if (spi->bits_per_word <= 8)
+		cs->txrx_bufs = bitbang_txrx_8;
+	else if (spi->bits_per_word <= 16)
+		cs->txrx_bufs = bitbang_txrx_16;
+	else if (spi->bits_per_word <= 32)
+		cs->txrx_bufs = bitbang_txrx_32;
+	else
+		return -EINVAL;
+
+	/* per-word shift register access, in hardware or bitbanging */
+	cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
+	if (!cs->txrx_word)
+		return -EINVAL;
+
+	/* nsecs = (clock period)/2 */
+	cs->nsecs = (1000000000/2) / (spi->max_speed_hz);
+	if (cs->nsecs > MAX_UDELAY_MS * 1000)
+		return -EINVAL;
+
+	dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+			__FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+			spi->bits_per_word, 2 * cs->nsecs);
+
+	/* NOTE we _need_ to call chipselect() early, ideally with adapter
+	 * setup, unless the hardware defaults cooperate to avoid confusion
+	 * between normal (active low) and inverted chipselects.
+	 */
+
+	/* deselect chip (low or high) */
+	spin_lock(&bitbang->lock);
+	if (!bitbang->busy) {
+		bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+		ndelay(cs->nsecs);
+	}
+	spin_unlock(&bitbang->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_setup);
+
+/**
+ * spi_bitbang_cleanup - default cleanup for per-word I/O loops
+ */
+void spi_bitbang_cleanup(const struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
+
+static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct spi_bitbang_cs	*cs = spi->controller_state;
+	unsigned		nsecs = cs->nsecs;
+
+	return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * SECOND PART ... simple transfer queue runner.
+ *
+ * This costs a task context per controller, running the queue by
+ * performing each transfer in sequence.  Smarter hardware can queue
+ * several DMA transfers at once, and process several controller queues
+ * in parallel; this driver doesn't match such hardware very well.
+ *
+ * Drivers can provide word-at-a-time i/o primitives, or provide
+ * transfer-at-a-time ones to leverage dma or fifo hardware.
+ */
+static void bitbang_work(void *_bitbang)
+{
+	struct spi_bitbang	*bitbang = _bitbang;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&bitbang->lock, flags);
+	bitbang->busy = 1;
+	while (!list_empty(&bitbang->queue)) {
+		struct spi_message	*m;
+		struct spi_device	*spi;
+		unsigned		nsecs;
+		struct spi_transfer	*t = NULL;
+		unsigned		tmp;
+		unsigned		cs_change;
+		int			status;
+
+		m = container_of(bitbang->queue.next, struct spi_message,
+				queue);
+		list_del_init(&m->queue);
+		spin_unlock_irqrestore(&bitbang->lock, flags);
+
+		/* FIXME this is made-up ... the correct value is known to
+		 * word-at-a-time bitbang code, and presumably chipselect()
+		 * should enforce these requirements too?
+		 */
+		nsecs = 100;
+
+		spi = m->spi;
+		tmp = 0;
+		cs_change = 1;
+		status = 0;
+
+		list_for_each_entry (t, &m->transfers, transfer_list) {
+			if (bitbang->shutdown) {
+				status = -ESHUTDOWN;
+				break;
+			}
+
+			/* set up default clock polarity, and activate chip;
+			 * this implicitly updates clock and spi modes as
+			 * previously recorded for this device via setup().
+			 * (and also deselects any other chip that might be
+			 * selected ...)
+			 */
+			if (cs_change) {
+				bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+				ndelay(nsecs);
+			}
+			cs_change = t->cs_change;
+			if (!t->tx_buf && !t->rx_buf && t->len) {
+				status = -EINVAL;
+				break;
+			}
+
+			/* transfer data.  the lower level code handles any
+			 * new dma mappings it needs. our caller always gave
+			 * us dma-safe buffers.
+			 */
+			if (t->len) {
+				/* REVISIT dma API still needs a designated
+				 * DMA_ADDR_INVALID; ~0 might be better.
+				 */
+				if (!m->is_dma_mapped)
+					t->rx_dma = t->tx_dma = 0;
+				status = bitbang->txrx_bufs(spi, t);
+			}
+			if (status != t->len) {
+				if (status > 0)
+					status = -EMSGSIZE;
+				break;
+			}
+			m->actual_length += status;
+			status = 0;
+
+			/* protocol tweaks before next transfer */
+			if (t->delay_usecs)
+				udelay(t->delay_usecs);
+
+			if (!cs_change)
+				continue;
+			if (t->transfer_list.next == &m->transfers)
+				break;
+
+			/* sometimes a short mid-message deselect of the chip
+			 * may be needed to terminate a mode or command
+			 */
+			ndelay(nsecs);
+			bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+			ndelay(nsecs);
+		}
+
+		m->status = status;
+		m->complete(m->context);
+
+		/* normally deactivate chipselect ... unless no error and
+		 * cs_change has hinted that the next message will probably
+		 * be for this chip too.
+		 */
+		if (!(status == 0 && cs_change)) {
+			ndelay(nsecs);
+			bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+			ndelay(nsecs);
+		}
+
+		spin_lock_irqsave(&bitbang->lock, flags);
+	}
+	bitbang->busy = 0;
+	spin_unlock_irqrestore(&bitbang->lock, flags);
+}
+
+/**
+ * spi_bitbang_transfer - default submit to transfer queue
+ */
+int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct spi_bitbang	*bitbang;
+	unsigned long		flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	bitbang = spi_master_get_devdata(spi->master);
+	if (bitbang->shutdown)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&bitbang->lock, flags);
+	list_add_tail(&m->queue, &bitbang->queue);
+	queue_work(bitbang->workqueue, &bitbang->work);
+	spin_unlock_irqrestore(&bitbang->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * spi_bitbang_start - start up a polled/bitbanging SPI master driver
+ * @bitbang: driver handle
+ *
+ * Caller should have zero-initialized all parts of the structure, and then
+ * provided callbacks for chip selection and I/O loops.  If the master has
+ * a transfer method, its final step should call spi_bitbang_transfer; or,
+ * that's the default if the transfer routine is not initialized.  It should
+ * also set up the bus number and number of chipselects.
+ *
+ * For i/o loops, provide callbacks either per-word (for bitbanging, or for
+ * hardware that basically exposes a shift register) or per-spi_transfer
+ * (which takes better advantage of hardware like fifos or DMA engines).
+ *
+ * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and
+ * spi_bitbang_cleanup to handle those spi master methods.  Those methods are
+ * the defaults if the bitbang->txrx_bufs routine isn't initialized.
+ *
+ * This routine registers the spi_master, which will process requests in a
+ * dedicated task, keeping IRQs unblocked most of the time.  To stop
+ * processing those requests, call spi_bitbang_stop().
+ */
+int spi_bitbang_start(struct spi_bitbang *bitbang)
+{
+	int	status;
+
+	if (!bitbang->master || !bitbang->chipselect)
+		return -EINVAL;
+
+	INIT_WORK(&bitbang->work, bitbang_work, bitbang);
+	spin_lock_init(&bitbang->lock);
+	INIT_LIST_HEAD(&bitbang->queue);
+
+	if (!bitbang->master->transfer)
+		bitbang->master->transfer = spi_bitbang_transfer;
+	if (!bitbang->txrx_bufs) {
+		bitbang->use_dma = 0;
+		bitbang->txrx_bufs = spi_bitbang_bufs;
+		if (!bitbang->master->setup) {
+			bitbang->master->setup = spi_bitbang_setup;
+			bitbang->master->cleanup = spi_bitbang_cleanup;
+		}
+	} else if (!bitbang->master->setup)
+		return -EINVAL;
+
+	/* this task is the only thing to touch the SPI bits */
+	bitbang->busy = 0;
+	bitbang->workqueue = create_singlethread_workqueue(
+			bitbang->master->cdev.dev->bus_id);
+	if (bitbang->workqueue == NULL) {
+		status = -EBUSY;
+		goto err1;
+	}
+
+	/* driver may get busy before register() returns, especially
+	 * if someone registered boardinfo for devices
+	 */
+	status = spi_register_master(bitbang->master);
+	if (status < 0)
+		goto err2;
+
+	return status;
+
+err2:
+	destroy_workqueue(bitbang->workqueue);
+err1:
+	return status;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_start);
+
+/**
+ * spi_bitbang_stop - stops the task providing spi communication
+ */
+int spi_bitbang_stop(struct spi_bitbang *bitbang)
+{
+	unsigned	limit = 500;
+
+	spin_lock_irq(&bitbang->lock);
+	bitbang->shutdown = 0;
+	while (!list_empty(&bitbang->queue) && limit--) {
+		spin_unlock_irq(&bitbang->lock);
+
+		dev_dbg(bitbang->master->cdev.dev, "wait for queue\n");
+		msleep(10);
+
+		spin_lock_irq(&bitbang->lock);
+	}
+	spin_unlock_irq(&bitbang->lock);
+	if (!list_empty(&bitbang->queue)) {
+		dev_err(bitbang->master->cdev.dev, "queue didn't empty\n");
+		return -EBUSY;
+	}
+
+	destroy_workqueue(bitbang->workqueue);
+
+	spi_unregister_master(bitbang->master);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_stop);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
new file mode 100644
index 0000000..79a3c59
--- /dev/null
+++ b/drivers/spi/spi_butterfly.c
@@ -0,0 +1,423 @@
+/*
+ * spi_butterfly.c - parport-to-butterfly adapter
+ *
+ * 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.
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/partitions.h>
+
+
+/*
+ * This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
+ * with a battery powered AVR microcontroller and lots of goodies.  You
+ * can use GCC to develop firmware for this.
+ *
+ * See Documentation/spi/butterfly for information about how to build
+ * and use this custom parallel port cable.
+ */
+
+#undef	HAVE_USI	/* nyet */
+
+
+/* DATA output bits (pins 2..9 == D0..D7) */
+#define	butterfly_nreset (1 << 1)		/* pin 3 */
+
+#define	spi_sck_bit	(1 << 0)		/* pin 2 */
+#define	spi_mosi_bit	(1 << 7)		/* pin 9 */
+
+#define	usi_sck_bit	(1 << 3)		/* pin 5 */
+#define	usi_mosi_bit	(1 << 4)		/* pin 6 */
+
+#define	vcc_bits	((1 << 6) | (1 << 5))	/* pins 7, 8 */
+
+/* STATUS input bits */
+#define	spi_miso_bit	PARPORT_STATUS_BUSY	/* pin 11 */
+
+#define	usi_miso_bit	PARPORT_STATUS_PAPEROUT	/* pin 12 */
+
+/* CONTROL output bits */
+#define	spi_cs_bit	PARPORT_CONTROL_SELECT	/* pin 17 */
+/* USI uses no chipselect */
+
+
+
+static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
+{
+	return spi->controller_data;
+}
+
+static inline int is_usidev(struct spi_device *spi)
+{
+#ifdef	HAVE_USI
+	return spi->chip_select != 1;
+#else
+	return 0;
+#endif
+}
+
+
+struct butterfly {
+	/* REVISIT ... for now, this must be first */
+	struct spi_bitbang	bitbang;
+
+	struct parport		*port;
+	struct pardevice	*pd;
+
+	u8			lastbyte;
+
+	struct spi_device	*dataflash;
+	struct spi_device	*butterfly;
+	struct spi_board_info	info[2];
+
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * these routines may be slower than necessary because they're hiding
+ * the fact that there are two different SPI busses on this cable: one
+ * to the DataFlash chip (or AVR SPI controller), the other to the
+ * AVR USI controller.
+ */
+
+static inline void
+setsck(struct spi_device *spi, int is_on)
+{
+	struct butterfly	*pp = spidev_to_pp(spi);
+	u8			bit, byte = pp->lastbyte;
+
+	if (is_usidev(spi))
+		bit = usi_sck_bit;
+	else
+		bit = spi_sck_bit;
+
+	if (is_on)
+		byte |= bit;
+	else
+		byte &= ~bit;
+	parport_write_data(pp->port, byte);
+	pp->lastbyte = byte;
+}
+
+static inline void
+setmosi(struct spi_device *spi, int is_on)
+{
+	struct butterfly	*pp = spidev_to_pp(spi);
+	u8			bit, byte = pp->lastbyte;
+
+	if (is_usidev(spi))
+		bit = usi_mosi_bit;
+	else
+		bit = spi_mosi_bit;
+
+	if (is_on)
+		byte |= bit;
+	else
+		byte &= ~bit;
+	parport_write_data(pp->port, byte);
+	pp->lastbyte = byte;
+}
+
+static inline int getmiso(struct spi_device *spi)
+{
+	struct butterfly	*pp = spidev_to_pp(spi);
+	int			value;
+	u8			bit;
+
+	if (is_usidev(spi))
+		bit = usi_miso_bit;
+	else
+		bit = spi_miso_bit;
+
+	/* only STATUS_BUSY is NOT negated */
+	value = !(parport_read_status(pp->port) & bit);
+	return (bit == PARPORT_STATUS_BUSY) ? value : !value;
+}
+
+static void butterfly_chipselect(struct spi_device *spi, int value)
+{
+	struct butterfly	*pp = spidev_to_pp(spi);
+
+	/* set default clock polarity */
+	if (value)
+		setsck(spi, spi->mode & SPI_CPOL);
+
+	/* no chipselect on this USI link config */
+	if (is_usidev(spi))
+		return;
+
+	/* here, value == "activate or not" */
+
+	/* most PARPORT_CONTROL_* bits are negated */
+	if (spi_cs_bit == PARPORT_CONTROL_INIT)
+		value = !value;
+
+	/* here, value == "bit value to write in control register"  */
+
+	parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
+}
+
+
+/* we only needed to implement one mode here, and choose SPI_MODE_0 */
+
+#define	spidelay(X)	do{}while(0)
+//#define	spidelay	ndelay
+
+#define	EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32
+butterfly_txrx_word_mode0(struct spi_device *spi,
+		unsigned nsecs,
+		u32 word, u8 bits)
+{
+	return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* override default partitioning with cmdlinepart */
+static struct mtd_partition partitions[] = { {
+	/* JFFS2 wants partitions of 4*N blocks for this device ... */
+
+	/* sector 0 = 8 pages * 264 bytes/page (1 block)
+	 * sector 1 = 248 pages * 264 bytes/page
+	 */
+	.name		= "bookkeeping",	// 66 KB
+	.offset		= 0,
+	.size		= (8 + 248) * 264,
+//	.mask_flags	= MTD_WRITEABLE,
+}, {
+	/* sector 2 = 256 pages * 264 bytes/page
+	 * sectors 3-5 = 512 pages * 264 bytes/page
+	 */
+	.name		= "filesystem",		// 462 KB
+	.offset		= MTDPART_OFS_APPEND,
+	.size		= MTDPART_SIZ_FULL,
+} };
+
+static struct flash_platform_data flash = {
+	.name		= "butterflash",
+	.parts		= partitions,
+	.nr_parts	= ARRAY_SIZE(partitions),
+};
+
+
+/* REVISIT remove this ugly global and its "only one" limitation */
+static struct butterfly *butterfly;
+
+static void butterfly_attach(struct parport *p)
+{
+	struct pardevice	*pd;
+	int			status;
+	struct butterfly	*pp;
+	struct spi_master	*master;
+	struct platform_device	*pdev;
+
+	if (butterfly)
+		return;
+
+	/* REVISIT:  this just _assumes_ a butterfly is there ... no probe,
+	 * and no way to be selective about what it binds to.
+	 */
+
+	/* FIXME where should master->cdev.dev come from?
+	 * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc
+	 * setting up a platform device like this is an ugly kluge...
+	 */
+	pdev = platform_device_register_simple("butterfly", -1, NULL, 0);
+
+	master = spi_alloc_master(&pdev->dev, sizeof *pp);
+	if (!master) {
+		status = -ENOMEM;
+		goto done;
+	}
+	pp = spi_master_get_devdata(master);
+
+	/*
+	 * SPI and bitbang hookup
+	 *
+	 * use default setup(), cleanup(), and transfer() methods; and
+	 * only bother implementing mode 0.  Start it later.
+	 */
+	master->bus_num = 42;
+	master->num_chipselect = 2;
+
+	pp->bitbang.master = spi_master_get(master);
+	pp->bitbang.chipselect = butterfly_chipselect;
+	pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
+
+	/*
+	 * parport hookup
+	 */
+	pp->port = p;
+	pd = parport_register_device(p, "spi_butterfly",
+			NULL, NULL, NULL,
+			0 /* FLAGS */, pp);
+	if (!pd) {
+		status = -ENOMEM;
+		goto clean0;
+	}
+	pp->pd = pd;
+
+	status = parport_claim(pd);
+	if (status < 0)
+		goto clean1;
+
+	/*
+	 * Butterfly reset, powerup, run firmware
+	 */
+	pr_debug("%s: powerup/reset Butterfly\n", p->name);
+
+	/* nCS for dataflash (this bit is inverted on output) */
+	parport_frob_control(pp->port, spi_cs_bit, 0);
+
+	/* stabilize power with chip in reset (nRESET), and
+	 * both spi_sck_bit and usi_sck_bit clear (CPOL=0)
+	 */
+	pp->lastbyte |= vcc_bits;
+	parport_write_data(pp->port, pp->lastbyte);
+	msleep(5);
+
+	/* take it out of reset; assume long reset delay */
+	pp->lastbyte |= butterfly_nreset;
+	parport_write_data(pp->port, pp->lastbyte);
+	msleep(100);
+
+
+	/*
+	 * Start SPI ... for now, hide that we're two physical busses.
+	 */
+	status = spi_bitbang_start(&pp->bitbang);
+	if (status < 0)
+		goto clean2;
+
+	/* Bus 1 lets us talk to at45db041b (firmware disables AVR)
+	 * or AVR (firmware resets at45, acts as spi slave)
+	 */
+	pp->info[0].max_speed_hz = 15 * 1000 * 1000;
+	strcpy(pp->info[0].modalias, "mtd_dataflash");
+	pp->info[0].platform_data = &flash;
+	pp->info[0].chip_select = 1;
+	pp->info[0].controller_data = pp;
+	pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
+	if (pp->dataflash)
+		pr_debug("%s: dataflash at %s\n", p->name,
+				pp->dataflash->dev.bus_id);
+
+#ifdef	HAVE_USI
+	/* even more custom AVR firmware */
+	pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000;
+	strcpy(pp->info[1].modalias, "butterfly");
+	// pp->info[1].platform_data = ... TBD ... ;
+	pp->info[1].chip_select = 2,
+	pp->info[1].controller_data = pp;
+	pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]);
+	if (pp->butterfly)
+		pr_debug("%s: butterfly at %s\n", p->name,
+				pp->butterfly->dev.bus_id);
+
+	/* FIXME setup ACK for the IRQ line ...  */
+#endif
+
+	// dev_info(_what?_, ...)
+	pr_info("%s: AVR Butterfly\n", p->name);
+	butterfly = pp;
+	return;
+
+clean2:
+	/* turn off VCC */
+	parport_write_data(pp->port, 0);
+
+	parport_release(pp->pd);
+clean1:
+	parport_unregister_device(pd);
+clean0:
+	(void) spi_master_put(pp->bitbang.master);
+done:
+	platform_device_unregister(pdev);
+	pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
+}
+
+static void butterfly_detach(struct parport *p)
+{
+	struct butterfly	*pp;
+	struct platform_device	*pdev;
+	int			status;
+
+	/* FIXME this global is ugly ... but, how to quickly get from
+	 * the parport to the "struct butterfly" associated with it?
+	 * "old school" driver-internal device lists?
+	 */
+	if (!butterfly || butterfly->port != p)
+		return;
+	pp = butterfly;
+	butterfly = NULL;
+
+#ifdef	HAVE_USI
+	spi_unregister_device(pp->butterfly);
+	pp->butterfly = NULL;
+#endif
+	spi_unregister_device(pp->dataflash);
+	pp->dataflash = NULL;
+
+	status = spi_bitbang_stop(&pp->bitbang);
+
+	/* turn off VCC */
+	parport_write_data(pp->port, 0);
+	msleep(10);
+
+	parport_release(pp->pd);
+	parport_unregister_device(pp->pd);
+
+	pdev = to_platform_device(pp->bitbang.master->cdev.dev);
+
+	(void) spi_master_put(pp->bitbang.master);
+
+	platform_device_unregister(pdev);
+}
+
+static struct parport_driver butterfly_driver = {
+	.name =		"spi_butterfly",
+	.attach =	butterfly_attach,
+	.detach =	butterfly_detach,
+};
+
+
+static int __init butterfly_init(void)
+{
+	return parport_register_driver(&butterfly_driver);
+}
+device_initcall(butterfly_init);
+
+static void __exit butterfly_exit(void)
+{
+	parport_unregister_driver(&butterfly_driver);
+}
+module_exit(butterfly_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 9baa629..7af1883 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -207,7 +207,7 @@
 **  urbs  **
 ************/
 
-static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
+static struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
 {
 	struct urb *urb;
 
@@ -224,7 +224,7 @@
 	return urb;
 }
 
-static inline int usbatm_submit_urb(struct urb *urb)
+static int usbatm_submit_urb(struct urb *urb)
 {
 	struct usbatm_channel *channel = urb->context;
 	int ret;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 8f402f8..afc84cf 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2534,9 +2534,6 @@
 	.driver 	= {
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
-		// .shutdown = ...
-		// .suspend = ...
-		// .resume = ...
 	},
 };
 
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index c6c279d..9a4edc5 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1738,9 +1738,6 @@
 
 	.driver 	= {
 		.name		= (char *) shortname,
-		// .shutdown = ...
-		// .suspend = ...
-		// .resume = ...
 	},
 };
 
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 2e6926b..ba9acd5 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -374,9 +374,6 @@
 	.disconnect =		gs_disconnect,
 	.driver = {
 		.name =		GS_SHORT_NAME,
-		/* .shutdown = ... */
-		/* .suspend = ...  */
-		/* .resume = ...   */
 	},
 };
 
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 6c58636..2fc110d 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1303,9 +1303,6 @@
 	.driver 	= {
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
-		// .shutdown = ...
-		// .suspend = ...
-		// .resume = ...
 	},
 };
 
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 509dd0a..5246b35 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -37,6 +37,16 @@
 
 	  If unsure, say Y.
 
+config USB_HIDINPUT_POWERBOOK
+	bool "Enable support for iBook/PowerBook special keys"
+	default n
+	depends on USB_HIDINPUT
+	help
+	  Say Y here if you want support for the special keys (Fn, Numlock) on
+	  Apple iBooks and PowerBooks.
+
+	  If unsure, say N.
+
 config HID_FF
 	bool "Force feedback support (EXPERIMENTAL)"
 	depends on USB_HIDINPUT && EXPERIMENTAL
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 5f52979..a91e72c 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1450,6 +1450,9 @@
 #define USB_VENDOR_ID_APPLE		0x05ac
 #define USB_DEVICE_ID_APPLE_POWERMOUSE	0x0304
 
+#define USB_VENDOR_ID_CHERRY		0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1580,6 +1583,16 @@
 	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
 
+	{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
+
+	{ USB_VENDOR_ID_APPLE, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
+
 	{ 0, 0 }
 };
 
@@ -1626,6 +1639,20 @@
 		usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
 }
 
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+
+static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
+{
+	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+		info("Fixing up Cherry Cymotion report descriptor");
+		rdesc[11] = rdesc[16] = 0xff;
+		rdesc[12] = rdesc[17] = 0x03;
+	}
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1673,6 +1700,9 @@
 		return NULL;
 	}
 
+	if ((quirks & HID_QUIRK_CYMOTION))
+		hid_fixup_cymotion_descriptor(rdesc, rsize);
+
 #ifdef DEBUG_DATA
 	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
 	for (n = 0; n < rsize; n++)
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 192a03b..cb0d80f 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -73,6 +73,160 @@
 #define map_key_clear(c)	do { map_key(c); clear_bit(c, bit); } while (0)
 #define map_ff_effect(c)	do { set_bit(c, input->ffbit); } while (0)
 
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+
+struct hidinput_key_translation {
+	u16 from;
+	u16 to;
+	u8 flags;
+};
+
+#define POWERBOOK_FLAG_FKEY 0x01
+
+static struct hidinput_key_translation powerbook_fn_keys[] = {
+	{ KEY_BACKSPACE, KEY_DELETE },
+	{ KEY_F1,	KEY_BRIGHTNESSDOWN,	POWERBOOK_FLAG_FKEY },
+	{ KEY_F2,	KEY_BRIGHTNESSUP,	POWERBOOK_FLAG_FKEY },
+	{ KEY_F3,	KEY_MUTE,		POWERBOOK_FLAG_FKEY },
+	{ KEY_F4,	KEY_VOLUMEDOWN,		POWERBOOK_FLAG_FKEY },
+	{ KEY_F5,	KEY_VOLUMEUP,		POWERBOOK_FLAG_FKEY },
+	{ KEY_F6,	KEY_NUMLOCK,		POWERBOOK_FLAG_FKEY },
+	{ KEY_F7,	KEY_SWITCHVIDEOMODE,	POWERBOOK_FLAG_FKEY },
+	{ KEY_F8,	KEY_KBDILLUMTOGGLE,	POWERBOOK_FLAG_FKEY },
+	{ KEY_F9,	KEY_KBDILLUMDOWN,	POWERBOOK_FLAG_FKEY },
+	{ KEY_F10,	KEY_KBDILLUMUP,		POWERBOOK_FLAG_FKEY },
+	{ KEY_UP,	KEY_PAGEUP },
+	{ KEY_DOWN,	KEY_PAGEDOWN },
+	{ KEY_LEFT,	KEY_HOME },
+	{ KEY_RIGHT,	KEY_END },
+	{ }
+};
+
+static struct hidinput_key_translation powerbook_numlock_keys[] = {
+	{ KEY_J,	KEY_KP1 },
+	{ KEY_K,	KEY_KP2 },
+	{ KEY_L,	KEY_KP3 },
+	{ KEY_U,	KEY_KP4 },
+	{ KEY_I,	KEY_KP5 },
+	{ KEY_O,	KEY_KP6 },
+	{ KEY_7,	KEY_KP7 },
+	{ KEY_8,	KEY_KP8 },
+	{ KEY_9,	KEY_KP9 },
+	{ KEY_M,	KEY_KP0 },
+	{ KEY_DOT,	KEY_KPDOT },
+	{ KEY_SLASH,	KEY_KPPLUS },
+	{ KEY_SEMICOLON, KEY_KPMINUS },
+	{ KEY_P,	KEY_KPASTERISK },
+	{ KEY_MINUS,	KEY_KPEQUAL },
+	{ KEY_0,	KEY_KPSLASH },
+	{ KEY_F6,	KEY_NUMLOCK },
+	{ KEY_KPENTER,	KEY_KPENTER },
+	{ KEY_BACKSPACE, KEY_BACKSPACE },
+	{ }
+};
+
+static int usbhid_pb_fnmode = 1;
+module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+	"Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+
+static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
+{
+	struct hidinput_key_translation *trans;
+
+	/* Look for the translation */
+	for (trans = table; trans->from; trans++)
+		if (trans->from == from)
+			return trans;
+
+	return NULL;
+}
+
+static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+			     struct hid_usage *usage, __s32 value)
+{
+	struct hidinput_key_translation *trans;
+
+	if (usage->code == KEY_FN) {
+		if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
+		else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+
+		input_event(input, usage->type, usage->code, value);
+
+		return 1;
+	}
+
+	if (usbhid_pb_fnmode) {
+		int do_translate;
+
+		trans = find_translation(powerbook_fn_keys, usage->code);
+		if (trans) {
+			if (test_bit(usage->code, hid->pb_pressed_fn))
+				do_translate = 1;
+			else if (trans->flags & POWERBOOK_FLAG_FKEY)
+				do_translate =
+					(usbhid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+					(usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+			else
+				do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
+
+			if (do_translate) {
+				if (value)
+					set_bit(usage->code, hid->pb_pressed_fn);
+				else
+					clear_bit(usage->code, hid->pb_pressed_fn);
+
+				input_event(input, usage->type, trans->to, value);
+
+				return 1;
+			}
+		}
+
+		if (test_bit(usage->code, hid->pb_pressed_numlock) ||
+		    test_bit(LED_NUML, input->led)) {
+			trans = find_translation(powerbook_numlock_keys, usage->code);
+
+			if (trans) {
+				if (value)
+					set_bit(usage->code, hid->pb_pressed_numlock);
+				else
+					clear_bit(usage->code, hid->pb_pressed_numlock);
+
+				input_event(input, usage->type, trans->to, value);
+			}
+
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void hidinput_pb_setup(struct input_dev *input)
+{
+	struct hidinput_key_translation *trans;
+
+	set_bit(KEY_NUMLOCK, input->keybit);
+
+	/* Enable all needed keys */
+	for (trans = powerbook_fn_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
+	for (trans = powerbook_numlock_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+}
+#else
+static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+				    struct hid_usage *usage, __s32 value)
+{
+	return 0;
+}
+
+static inline void hidinput_pb_setup(struct input_dev *input)
+{
+}
+#endif
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
@@ -135,8 +289,11 @@
 		case HID_UP_SIMULATION:
 
 			switch (usage->hid & 0xffff) {
-				case 0xba: map_abs(ABS_RUDDER); break;
+				case 0xba: map_abs(ABS_RUDDER);   break;
 				case 0xbb: map_abs(ABS_THROTTLE); break;
+				case 0xc4: map_abs(ABS_GAS);      break;
+				case 0xc5: map_abs(ABS_BRAKE);    break;
+				case 0xc8: map_abs(ABS_WHEEL);    break;
 				default:   goto ignore;
 			}
 			break;
@@ -289,11 +446,19 @@
 				case 0x226: map_key_clear(KEY_STOP);		break;
 				case 0x227: map_key_clear(KEY_REFRESH);		break;
 				case 0x22a: map_key_clear(KEY_BOOKMARKS);	break;
+				case 0x233: map_key_clear(KEY_SCROLLUP);	break;
+				case 0x234: map_key_clear(KEY_SCROLLDOWN);	break;
 				case 0x238: map_rel(REL_HWHEEL);		break;
 				case 0x279: map_key_clear(KEY_REDO);		break;
 				case 0x289: map_key_clear(KEY_REPLY);		break;
 				case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
 				case 0x28c: map_key_clear(KEY_SEND);		break;
+
+				/* Reported on a Cherry Cymotion keyboard */
+				case 0x301: map_key_clear(KEY_PROG1);		break;
+				case 0x302: map_key_clear(KEY_PROG2);		break;
+				case 0x303: map_key_clear(KEY_PROG3);		break;
+
 				default:    goto ignore;
 			}
 			break;
@@ -325,7 +490,12 @@
 
 			set_bit(EV_REP, input->evbit);
 			switch(usage->hid & HID_USAGE) {
-				case 0x003: map_key_clear(KEY_FN);		break;
+				case 0x003:
+					/* The fn key on Apple PowerBooks */
+					map_key_clear(KEY_FN);
+					hidinput_pb_setup(input);
+					break;
+
 				default:    goto ignore;
 			}
 			break;
@@ -482,6 +652,9 @@
 		return;
 	}
 
+	if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
+		return;
+
 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int hat_dir = usage->hat_dir;
 		if (!hat_dir)
@@ -524,7 +697,7 @@
 		return;
 	}
 
-	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
+	if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
 		return;
 
 	input_event(input, usage->type, usage->code, value);
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index ee48a22..8b0d434 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -235,17 +235,20 @@
  * HID device quirks.
  */
 
-#define HID_QUIRK_INVERT			0x001
-#define HID_QUIRK_NOTOUCH			0x002
-#define HID_QUIRK_IGNORE			0x004
-#define HID_QUIRK_NOGET				0x008
-#define HID_QUIRK_HIDDEV			0x010
-#define HID_QUIRK_BADPAD			0x020
-#define HID_QUIRK_MULTI_INPUT			0x040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7		0x080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5		0x100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x200
-#define HID_QUIRK_2WHEEL_POWERMOUSE		0x400
+#define HID_QUIRK_INVERT			0x00000001
+#define HID_QUIRK_NOTOUCH			0x00000002
+#define HID_QUIRK_IGNORE			0x00000004
+#define HID_QUIRK_NOGET				0x00000008
+#define HID_QUIRK_HIDDEV			0x00000010
+#define HID_QUIRK_BADPAD			0x00000020
+#define HID_QUIRK_MULTI_INPUT			0x00000040
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_7		0x00000080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_5		0x00000100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON		0x00000200
+#define HID_QUIRK_2WHEEL_POWERMOUSE		0x00000400
+#define HID_QUIRK_CYMOTION			0x00000800
+#define HID_QUIRK_POWERBOOK_HAS_FN		0x00001000
+#define HID_QUIRK_POWERBOOK_FN_ON		0x00002000
 
 /*
  * This is the global environment of the parser. This information is
@@ -431,6 +434,11 @@
 	void (*ff_exit)(struct hid_device*);                            /* Called by hid_exit_ff(hid) */
 	int (*ff_event)(struct hid_device *hid, struct input_dev *input,
 			unsigned int type, unsigned int code, int value);
+
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+	unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
+	unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
+#endif
 };
 
 #define HID_GLOBAL_STACK_SIZE 4
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
index 19e015d..d9d9f65 100644
--- a/drivers/usb/input/pid.c
+++ b/drivers/usb/input/pid.c
@@ -259,7 +259,7 @@
 int hid_pid_init(struct hid_device *hid)
 {
 	struct hid_ff_pid *private;
-	struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct input_dev *input_dev = hidinput->input;
 
 	private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index 48df4cf..d3e15df 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -95,7 +95,7 @@
 enum {
 	PENPARTNER = 0,
 	GRAPHIRE,
-	G4,
+	WACOM_G4,
 	PL,
 	INTUOS,
 	INTUOS3,
@@ -373,7 +373,7 @@
 
 			case 2: /* Mouse with wheel */
 				input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
-				if (wacom->features->type == G4) {
+				if (wacom->features->type == WACOM_G4) {
 					rw = data[7] & 0x04 ? -(data[7] & 0x03) : (data[7] & 0x03);
 					input_report_rel(dev, REL_WHEEL, rw);
 				} else
@@ -385,7 +385,7 @@
 				id = CURSOR_DEVICE_ID;
 				input_report_key(dev, BTN_LEFT, data[1] & 0x01);
 				input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
-				if (wacom->features->type == G4)
+				if (wacom->features->type == WACOM_G4)
 					input_report_abs(dev, ABS_DISTANCE, data[6]);
 				else
 					input_report_abs(dev, ABS_DISTANCE, data[7]);
@@ -410,7 +410,7 @@
 	input_sync(dev);
 
 	/* send pad data */
-	if (wacom->features->type == G4) {
+	if (wacom->features->type == WACOM_G4) {
 		/* fist time sending pad data */
 		if (wacom->tool[1] != BTN_TOOL_FINGER) {
 			wacom->id[1] = 0;
@@ -713,8 +713,8 @@
 	{ "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, GRAPHIRE,   wacom_graphire_irq },
 	{ "Wacom Graphire3",     8,  10208,  7424,  511, 32, GRAPHIRE,   wacom_graphire_irq },
 	{ "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, GRAPHIRE,   wacom_graphire_irq },
-	{ "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 32, G4,	 wacom_graphire_irq },
-	{ "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 32, G4,	 wacom_graphire_irq },
+	{ "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 32, WACOM_G4,	 wacom_graphire_irq },
+	{ "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 32, WACOM_G4,	 wacom_graphire_irq },
 	{ "Wacom Volito",        8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
 	{ "Wacom PenStation2",   8,   3250,  2320,  255, 32, GRAPHIRE,   wacom_graphire_irq },
 	{ "Wacom Volito2 4x5",   8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
@@ -859,7 +859,7 @@
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
 
 	switch (wacom->features->type) {
-		case G4:
+		case WACOM_G4:
 			input_dev->evbit[0] |= BIT(EV_MSC);
 			input_dev->mscbit[0] |= BIT(MSC_SERIAL);
 			input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 664139a..e9f9f4b 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -37,11 +37,6 @@
 	return 0;
 }
 
-struct bus_type usb_serial_bus_type = {
-	.name =		"usb-serial",
-	.match =	usb_serial_device_match,
-};
-
 static int usb_serial_device_probe (struct device *dev)
 {
 	struct usb_serial_driver *driver;
@@ -109,14 +104,18 @@
 	return retval;
 }
 
+struct bus_type usb_serial_bus_type = {
+	.name =		"usb-serial",
+	.match =	usb_serial_device_match,
+	.probe =	usb_serial_device_probe,
+	.remove =	usb_serial_device_remove,
+};
+
 int usb_serial_bus_register(struct usb_serial_driver *driver)
 {
 	int retval;
 
 	driver->driver.bus = &usb_serial_bus_type;
-	driver->driver.probe = usb_serial_device_probe;
-	driver->driver.remove = usb_serial_device_remove;
-
 	retval = driver_register(&driver->driver);
 
 	return retval;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 9ffff19..0eb883f 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -43,8 +43,6 @@
 #define PL2303_BUF_SIZE		1024
 #define PL2303_TMP_BUF_SIZE	1024
 
-static DECLARE_MUTEX(pl2303_tmp_buf_sem);
-
 struct pl2303_buf {
 	unsigned int	buf_size;
 	char		*buf_buf;
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 3b0ddc5..78488bb 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -102,8 +102,7 @@
 			 u_int transp, struct fb_info *info);
 static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
 			   struct fb_info *info);
-static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
-		    struct vm_area_struct *vma);
+static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 
 static struct fb_ops mc68x328fb_ops = {
 	.fb_check_var	= mc68x328fb_check_var,
@@ -398,8 +397,7 @@
      *  Most drivers don't need their own mmap function 
      */
 
-static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
-		    struct vm_area_struct *vma)
+static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 #ifndef MMU
 	/* this is uClinux (no MMU) specific code */
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 750cebb..b058273 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -883,7 +883,7 @@
  * Note that we are entered with the kernel locked.
  */
 static int
-acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	unsigned long off, start;
 	u32 len;
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0da4083..b218717 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -307,7 +307,7 @@
 	return 0;
 }
 
-static int clcdfb_mmap(struct fb_info *info, struct file *file,
+static int clcdfb_mmap(struct fb_info *info,
 		       struct vm_area_struct *vma)
 {
 	struct clcd_fb *fb = to_clcd(info);
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 2c42a81..3033c72 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1131,9 +1131,7 @@
 			   const struct fb_copyarea *region);
 static void amifb_imageblit(struct fb_info *info,
 			    const struct fb_image *image);
-static int amifb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg,
-		       struct fb_info *info);
+static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
 
 
 	/*
@@ -2172,9 +2170,8 @@
 	 * Amiga Frame Buffer Specific ioctls
 	 */
 
-static int amifb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg,
-		       struct fb_info *info)
+static int amifb_ioctl(struct fb_info *info,
+		       unsigned int cmd, unsigned long arg)
 {
 	union {
 		struct fb_fix_cursorinfo fix;
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 89060b2..df8e566 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -399,9 +399,8 @@
 				image->height);
 }
 
-static int arcfb_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg,
-			  struct fb_info *info)
+static int arcfb_ioctl(struct fb_info *info,
+			  unsigned int cmd, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	struct arcfb_par *par = info->par;
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 15ec129..e69ab65 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2571,8 +2571,7 @@
 }
 
 static int
-atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	       unsigned long arg, int con, struct fb_info *info)
+atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
 #ifdef FBCMD_GET_CURRENTPAR
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index e686185..bfc8a93 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -431,8 +431,7 @@
 static int aty128fb_pan_display(struct fb_var_screeninfo *var,
 			   struct fb_info *fb);
 static int aty128fb_blank(int blank, struct fb_info *fb);
-static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			  u_long arg, struct fb_info *info);
+static int aty128fb_ioctl(struct fb_info *info, u_int cmd, unsigned long arg);
 static int aty128fb_sync(struct fb_info *info);
 
     /*
@@ -2108,8 +2107,7 @@
 /* in param: u32*	backlight value: 0 to 15 */
 #define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32)
 
-static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			  u_long arg, struct fb_info *info)
+static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct aty128fb_par *par = info->par;
 	u32 value;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index ed81005..485be38 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -238,13 +238,12 @@
 	u_int transp, struct fb_info *info);
 static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
 static int atyfb_blank(int blank, struct fb_info *info);
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-	u_long arg, struct fb_info *info);
+static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
 extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
 #ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 #endif
 static int atyfb_sync(struct fb_info *info);
 
@@ -1739,8 +1738,7 @@
 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
 #endif
 
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-	u_long arg, struct fb_info *info)
+static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 #ifdef __sparc__
@@ -1845,7 +1843,7 @@
 }
 
 #ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 	unsigned int size, page, map_size = 0;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 156db84..c9f0c5a 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -864,8 +864,8 @@
 }
 
 
-static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg, struct fb_info *info)
+static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
 {
         struct radeonfb_info *rinfo = info->par;
 	unsigned int tmp;
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index a512980..2406899 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -379,7 +379,7 @@
  * Map video memory in user space. We don't use the generic fb_mmap method mainly
  * to allow the use of the TLB streaming flag (CCA=6)
  */
-int au1100fb_fb_mmap(struct fb_info *fbi, struct file *file, struct vm_area_struct *vma)
+int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
 	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
 	unsigned int len;
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 9248fe1..c029db4 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -35,9 +35,8 @@
 
 static int bw2_blank(int, struct fb_info *);
 
-static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int bw2_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
+static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -169,7 +168,7 @@
 	{ .size = 0 }
 };
 
-static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct bw2_par *par = (struct bw2_par *)info->par;
 
@@ -181,8 +180,7 @@
 				  vma);
 }
 
-static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct bw2_par *par = (struct bw2_par *) info->par;
 
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index a561471..63b6c79 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -31,9 +31,8 @@
 static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
 			 unsigned, struct fb_info *);
 
-static int cg14_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg14_ioctl(struct inode *, struct file *, unsigned int,
-		      unsigned long, struct fb_info *);
+static int cg14_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg14_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -268,7 +267,7 @@
 	return 0;
 }
 
-static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct cg14_par *par = (struct cg14_par *) info->par;
 
@@ -277,8 +276,7 @@
 				  par->iospace, vma);
 }
 
-static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		      unsigned long arg, struct fb_info *info)
+static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct cg14_par *par = (struct cg14_par *) info->par;
 	struct cg14_regs __iomem *regs = par->regs;
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 9fcd896..3de6e1b 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -33,9 +33,8 @@
 			 unsigned, struct fb_info *);
 static int cg3_blank(int, struct fb_info *);
 
-static int cg3_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg3_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -230,7 +229,7 @@
 	{ .size = 0 }
 };
 
-static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct cg3_par *par = (struct cg3_par *)info->par;
 
@@ -240,8 +239,7 @@
 				  vma);
 }
 
-static int cg3_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct cg3_par *par = (struct cg3_par *) info->par;
 
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 050835e3..7aab91e 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -36,9 +36,8 @@
 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
 static int cg6_sync(struct fb_info *);
-static int cg6_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg6_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -524,7 +523,7 @@
 	{ .size	= 0 }
 };
 
-static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct cg6_par *par = (struct cg6_par *)info->par;
 
@@ -534,8 +533,7 @@
 				  vma);
 }
 
-static int cg6_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct cg6_par *par = (struct cg6_par *) info->par;
 
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 03798e9..655301a 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -128,7 +128,7 @@
 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 	u_int transp, struct fb_info *info);
 static int controlfb_blank(int blank_mode, struct fb_info *info);
-static int controlfb_mmap(struct fb_info *info, struct file *file,
+static int controlfb_mmap(struct fb_info *info,
 	struct vm_area_struct *vma);
 static int controlfb_set_par (struct fb_info *info);
 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
@@ -280,7 +280,7 @@
  * for controlfb.
  * Note there's no locking in here; it's done in fb_mmap() in fbmem.c.
  */
-static int controlfb_mmap(struct fb_info *info, struct file *file,
+static int controlfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
        unsigned long off, start;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 32a9b69..d2dede6 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -957,7 +957,7 @@
 	default:
 		if (fb->fb_ioctl == NULL)
 			return -EINVAL;
-		return fb->fb_ioctl(inode, file, cmd, arg, info);
+		return fb->fb_ioctl(info, cmd, arg);
 	}
 }
 
@@ -1107,7 +1107,7 @@
 
 	default:
 		if (fb->fb_compat_ioctl)
-			ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+			ret = fb->fb_compat_ioctl(info, cmd, arg);
 		break;
 	}
 	unlock_kernel();
@@ -1135,7 +1135,7 @@
 	if (fb->fb_mmap) {
 		int res;
 		lock_kernel();
-		res = fb->fb_mmap(info, file, vma);
+		res = fb->fb_mmap(info, vma);
 		unlock_kernel();
 		return res;
 	}
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index c4870d5..9c9b21d 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -37,9 +37,8 @@
 static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
 static int ffb_sync(struct fb_info *);
-static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int ffb_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct vm_area_struct *);
+static int ffb_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -839,7 +838,7 @@
 	{ .size = 0 }
 };
 
-static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct ffb_par *par = (struct ffb_par *)info->par;
 
@@ -848,8 +847,7 @@
 				  0, vma);
 }
 
-static int ffb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct ffb_par *par = (struct ffb_par *) info->par;
 
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index d744c51..38d2272 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -979,7 +979,7 @@
 	return 0;
 }
 
-static int gbefb_mmap(struct fb_info *info, struct file *file,
+static int gbefb_mmap(struct fb_info *info,
 			struct vm_area_struct *vma)
 {
 	unsigned long size = vma->vm_end - vma->vm_start;
@@ -1000,7 +1000,6 @@
 		pgprot_fb(pgprot_val(vma->vm_page_prot));
 
 	vma->vm_flags |= VM_IO | VM_RESERVED;
-	vma->vm_file = file;
 
 	/* look for the starting tile */
 	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
index 8e8da74..20e6915 100644
--- a/drivers/video/geode/gx1fb_core.c
+++ b/drivers/video/geode/gx1fb_core.c
@@ -215,11 +215,11 @@
 	if (ret < 0)
 		return ret;
 
-	ret = pci_request_region(dev, 1, "gx1fb (video)");
+	ret = pci_request_region(dev, 0, "gx1fb (video)");
 	if (ret < 0)
 		return ret;
-	par->vid_regs = ioremap(pci_resource_start(dev, 1),
-				pci_resource_len(dev, 1));
+	par->vid_regs = ioremap(pci_resource_start(dev, 0),
+				pci_resource_len(dev, 0));
 	if (!par->vid_regs)
 		return -ENOMEM;
 
@@ -229,12 +229,9 @@
 	if (!par->dc_regs)
 		return -ENOMEM;
 
-	ret = pci_request_region(dev, 0, "gx1fb (frame buffer)");
-	if (ret < 0 )
-		return -EBUSY;
 	if ((fb_len = gx1_frame_buffer_size()) < 0)
 		return -ENOMEM;
-	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_start = gx_base + 0x800000;
 	info->fix.smem_len = fb_len;
 	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
 	if (!info->screen_base)
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index e326f44..6b88050 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -219,7 +219,7 @@
 }
 
 #ifdef __sparc__
-static int igafb_mmap(struct fb_info *info, struct file *file,
+static int igafb_mmap(struct fb_info *info,
 		      struct vm_area_struct *vma)
 {
 	struct iga_par *par = (struct iga_par *)info->par;
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index a5d8130..ad416ae 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1267,8 +1267,7 @@
 #define FBIMSTT_GETIDXREG	0x545406
 
 static int
-imsttfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-	      u_long arg, struct fb_info *info)
+imsttfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct imstt_par *par = info->par;
 	void __user *argp = (void __user *)arg;
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 0090544..6b8bd3c 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -157,9 +157,8 @@
 
 static int intelfb_sync(struct fb_info *info);
 
-static int intelfb_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg,
-			 struct fb_info *info);
+static int intelfb_ioctl(struct fb_info *info,
+			 unsigned int cmd, unsigned long arg);
 
 static int __devinit intelfb_pci_register(struct pci_dev *pdev,
 					  const struct pci_device_id *ent);
@@ -1380,8 +1379,7 @@
 
 /* When/if we have our own ioctls. */
 static int
-intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	      unsigned long arg, struct fb_info *info)
+intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	int retval = 0;
 
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
index bcd359b..477ad29 100644
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -586,9 +586,8 @@
 }
 #endif
 
-static int kyrofb_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg,
-			struct fb_info *info)
+static int kyrofb_ioctl(struct fb_info *info,
+			unsigned int cmd, unsigned long arg)
 {
 	overlay_create ol_create;
 	overlay_viewport_set ol_viewport_set;
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 494287f..a23cfdb 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -32,9 +32,8 @@
 			 unsigned, struct fb_info *);
 static int leo_blank(int, struct fb_info *);
 
-static int leo_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int leo_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int leo_mmap(struct fb_info *, struct vm_area_struct *);
+static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -363,7 +362,7 @@
 	{ .size = 0 }
 };
 
-static int leo_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct leo_par *par = (struct leo_par *)info->par;
 
@@ -373,8 +372,7 @@
 				  vma);
 }
 
-static int leo_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct leo_par *par = (struct leo_par *) info->par;
 
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 1e74f4c..4055ff6 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -865,9 +865,8 @@
 	.name	 = "Panellink output",
 };
 
-static int matroxfb_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg,
-			  struct fb_info *info)
+static int matroxfb_ioctl(struct fb_info *info,
+			  unsigned int cmd, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
 	MINFO_FROM_INFO(info);
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index d52d7d8..27eb4bb 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -419,11 +419,10 @@
 	return 0;
 }
 
-static int matroxfb_dh_ioctl(struct inode* inode,
-		struct file* file,
+static int matroxfb_dh_ioctl(struct fb_info *info,
 		unsigned int cmd,
-		unsigned long arg,
-		struct fb_info* info) {
+		unsigned long arg)
+{
 #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
@@ -457,7 +456,7 @@
 		case MATROXFB_GET_OUTPUT_MODE:
 		case MATROXFB_GET_ALL_OUTPUTS:
 			{
-				return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon));
+				return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(&ACCESS_FBINFO(fbcon), cmd, arg);
 			}
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index a1f2c5e..6019710 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -968,7 +968,7 @@
 	return 0;
 }
 
-static inline int maven_program_timming(struct maven_data* md,
+static int maven_program_timming(struct maven_data* md,
 		const struct mavenregs* m) {
 	struct i2c_client* c = md->client;
 
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index e18c9f9..747602a 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -853,7 +853,7 @@
 	/* If the user did not specify any display devices, then... */
 	if (par->PanelDispCntlReg1 == 0x00) {
 		/* Default to internal (i.e., LCD) only. */
-		par->PanelDispCntlReg1 |= 0x02;
+		par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
 	}
 
 	/* If we are using a fixed mode, then tell the chip we are. */
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index b251e75..0d19575 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -31,9 +31,8 @@
 			   unsigned, struct fb_info *);
 static int p9100_blank(int, struct fb_info *);
 
-static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int p9100_ioctl(struct inode *, struct file *, unsigned int,
-		       unsigned long, struct fb_info *);
+static int p9100_mmap(struct fb_info *, struct vm_area_struct *);
+static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -222,7 +221,7 @@
 	{ 0,			0,		0		    }
 };
 
-static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct p9100_par *par = (struct p9100_par *)info->par;
 
@@ -232,8 +231,8 @@
 				  vma);
 }
 
-static int p9100_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		       unsigned long arg, struct fb_info *info)
+static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
+		       unsigned long arg)
 {
 	struct p9100_par *par = (struct p9100_par *) info->par;
 
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 2e11b60..0e78ddc 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -657,9 +657,7 @@
 static void pm3fb_detect(void);
 static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
 			     struct fb_info_gen *info);
-static int pm3fb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con,
-		       struct fb_info *info);
+static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
 
 
 /* the struct that hold them together */
@@ -3438,9 +3436,7 @@
 	return 0;
 }
 
-static int pm3fb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con,
-		       struct fb_info *info)
+static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
 	u32 cm, i;
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index 28d1fe5..d92f352 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -299,8 +299,7 @@
 		return -EINVAL;
 }
 
-static int aafb_ioctl(struct inode *inode, struct file *file, u32 cmd,
-		      unsigned long arg, int con, struct fb_info *info)
+static int aafb_ioctl(struct fb_info *info, u32 cmd, unsigned long arg)
 {
 	/* TODO: Not yet implemented */
 	return -ENOIOCTLCMD;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 9fc10b9..53ad61f 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -395,7 +395,7 @@
 	return 0;
 }
 
-static int pxafb_mmap(struct fb_info *info, struct file *file,
+static int pxafb_mmap(struct fb_info *info,
 		      struct vm_area_struct *vma)
 {
 	struct pxafb_info *fbi = (struct pxafb_info *)info;
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
index 600318f..db9fb90 100644
--- a/drivers/video/radeonfb.c
+++ b/drivers/video/radeonfb.c
@@ -1497,8 +1497,8 @@
 }
 
 
-static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg, struct fb_info *info)
+static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
 {
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
 	unsigned int tmp;
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 087e586..8a893ce 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -815,7 +815,7 @@
 	return 0;
 }
 
-static int sa1100fb_mmap(struct fb_info *info, struct file *file,
+static int sa1100fb_mmap(struct fb_info *info,
 			 struct vm_area_struct *vma)
 {
 	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index 7054660..2e6df1f 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -115,7 +115,7 @@
 static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
 			     u_int blue, u_int transp,
 			     struct fb_info *info);
-static int sgivwfb_mmap(struct fb_info *info, struct file *file,
+static int sgivwfb_mmap(struct fb_info *info,
 			struct vm_area_struct *vma);
 
 static struct fb_ops sgivwfb_ops = {
@@ -706,7 +706,7 @@
 	return 0;
 }
 
-static int sgivwfb_mmap(struct fb_info *info, struct file *file,
+static int sgivwfb_mmap(struct fb_info *info,
 			struct vm_area_struct *vma)
 {
 	unsigned long size = vma->vm_end - vma->vm_start;
@@ -723,7 +723,6 @@
 	if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
 						size, vma->vm_page_prot))
 		return -EAGAIN;
-	vma->vm_file = file;
 	printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
 	       offset, vma->vm_start);
 	return 0;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index dea1a46..8adf5bf 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1743,13 +1743,14 @@
 
 /* ----------- FBDev related routines for all series ---------- */
 
-static int
-sisfb_ioctl(struct inode *inode, struct file *file,
-            unsigned int cmd, unsigned long arg,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	    int con,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int	sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+			    unsigned long arg)
+#else
+static int	sisfb_ioctl(struct inode *inode, struct file *file,
+				unsigned int cmd, unsigned long arg,
+				struct fb_info *info)
 #endif
-	    struct fb_info *info)
 {
 	struct sis_video_info	*ivideo = (struct sis_video_info *)info->par;
 	struct sis_memreq	sismemreq;
@@ -1924,19 +1925,6 @@
 	return 0;
 }
 
-#ifdef SIS_NEW_CONFIG_COMPAT
-static long
-sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info)
-{
-	int ret;
-
-	lock_kernel();
-	ret = sisfb_ioctl(NULL, f, cmd, arg, info);
-	unlock_kernel();
-	return ret;
-}
-#endif
-
 static int
 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 {
@@ -2007,7 +1995,7 @@
 #endif
 	.fb_sync	= fbcon_sis_sync,
 #ifdef SIS_NEW_CONFIG_COMPAT
-	.fb_compat_ioctl= sisfb_compat_ioctl,
+	.fb_compat_ioctl= sisfb_ioctl,
 #endif
 	.fb_ioctl	= sisfb_ioctl
 };
diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
index 445bcbb..70b6df3 100644
--- a/drivers/video/sis/sis_main.h
+++ b/drivers/video/sis/sis_main.h
@@ -727,9 +727,14 @@
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int	sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+			    unsigned long arg);
+#else
 static int	sisfb_ioctl(struct inode *inode, struct file *file,
 				unsigned int cmd, unsigned long arg,
 				struct fb_info *info);
+#endif
 static int	sisfb_set_par(struct fb_info *info);
 static int	sisfb_blank(int blank,
 				struct fb_info *info);
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 8a5ce21..99921df 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -771,8 +771,7 @@
 	return 0;
 }
 
-static int sstfb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, struct fb_info *info )
+static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
 	struct sstfb_par *par = info->par;
 	struct pci_dev *sst_dev = par->dev;
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 2b27b44..95b9182 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -33,9 +33,8 @@
 			 unsigned, struct fb_info *);
 static int tcx_blank(int, struct fb_info *);
 
-static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int tcx_ioctl(struct inode *, struct file *, unsigned int,
-		     unsigned long, struct fb_info *);
+static int tcx_mmap(struct fb_info *, struct vm_area_struct *);
+static int tcx_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -302,7 +301,7 @@
 	{ .size = 0 }
 };
 
-static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 	struct tcx_par *par = (struct tcx_par *)info->par;
 
@@ -312,8 +311,8 @@
 				  vma);
 }
 
-static int tcx_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-		     unsigned long arg, struct fb_info *info)
+static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
+		     unsigned long arg)
 {
 	struct tcx_par *par = (struct tcx_par *) info->par;
 
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index ffa1ad4..53208cb 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -81,7 +81,7 @@
 			 u_int transp, struct fb_info *info);
 static int vfb_pan_display(struct fb_var_screeninfo *var,
 			   struct fb_info *info);
-static int vfb_mmap(struct fb_info *info, struct file *file,
+static int vfb_mmap(struct fb_info *info,
 		    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
@@ -368,7 +368,7 @@
      *  Most drivers don't need their own mmap function 
      */
 
-static int vfb_mmap(struct fb_info *info, struct file *file,
+static int vfb_mmap(struct fb_info *info,
 		    struct vm_area_struct *vma)
 {
 	return -EINVAL;
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c
index ccba227..fcbee74 100644
--- a/drivers/zorro/zorro-driver.c
+++ b/drivers/zorro/zorro-driver.c
@@ -77,7 +77,6 @@
 	/* initialize common driver fields */
 	drv->driver.name = drv->name;
 	drv->driver.bus = &zorro_bus_type;
-	drv->driver.probe = zorro_device_probe;
 
 	/* register with core */
 	count = driver_register(&drv->driver);
@@ -132,7 +131,8 @@
 
 struct bus_type zorro_bus_type = {
 	.name	= "zorro",
-	.match	= zorro_bus_match
+	.match	= zorro_bus_match,
+	.probe	= zorro_device_probe,
 };
 
 
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
index 55ccfa1..32a9f99 100644
--- a/fs/9p/conv.c
+++ b/fs/9p/conv.c
@@ -56,7 +56,7 @@
 	return buf->p > buf->ep;
 }
 
-static inline int buf_check_size(struct cbuf *buf, int len)
+static int buf_check_size(struct cbuf *buf, int len)
 {
 	if (buf->p + len > buf->ep) {
 		if (buf->p < buf->ep) {
@@ -72,7 +72,7 @@
 	return 1;
 }
 
-static inline void *buf_alloc(struct cbuf *buf, int len)
+static void *buf_alloc(struct cbuf *buf, int len)
 {
 	void *ret = NULL;
 
@@ -84,7 +84,7 @@
 	return ret;
 }
 
-static inline void buf_put_int8(struct cbuf *buf, u8 val)
+static void buf_put_int8(struct cbuf *buf, u8 val)
 {
 	if (buf_check_size(buf, 1)) {
 		buf->p[0] = val;
@@ -92,7 +92,7 @@
 	}
 }
 
-static inline void buf_put_int16(struct cbuf *buf, u16 val)
+static void buf_put_int16(struct cbuf *buf, u16 val)
 {
 	if (buf_check_size(buf, 2)) {
 		*(__le16 *) buf->p = cpu_to_le16(val);
@@ -100,7 +100,7 @@
 	}
 }
 
-static inline void buf_put_int32(struct cbuf *buf, u32 val)
+static void buf_put_int32(struct cbuf *buf, u32 val)
 {
 	if (buf_check_size(buf, 4)) {
 		*(__le32 *)buf->p = cpu_to_le32(val);
@@ -108,7 +108,7 @@
 	}
 }
 
-static inline void buf_put_int64(struct cbuf *buf, u64 val)
+static void buf_put_int64(struct cbuf *buf, u64 val)
 {
 	if (buf_check_size(buf, 8)) {
 		*(__le64 *)buf->p = cpu_to_le64(val);
@@ -116,7 +116,7 @@
 	}
 }
 
-static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
 {
 	if (buf_check_size(buf, slen + 2)) {
 		buf_put_int16(buf, slen);
@@ -130,7 +130,7 @@
 	buf_put_stringn(buf, s, strlen(s));
 }
 
-static inline u8 buf_get_int8(struct cbuf *buf)
+static u8 buf_get_int8(struct cbuf *buf)
 {
 	u8 ret = 0;
 
@@ -142,7 +142,7 @@
 	return ret;
 }
 
-static inline u16 buf_get_int16(struct cbuf *buf)
+static u16 buf_get_int16(struct cbuf *buf)
 {
 	u16 ret = 0;
 
@@ -154,7 +154,7 @@
 	return ret;
 }
 
-static inline u32 buf_get_int32(struct cbuf *buf)
+static u32 buf_get_int32(struct cbuf *buf)
 {
 	u32 ret = 0;
 
@@ -166,7 +166,7 @@
 	return ret;
 }
 
-static inline u64 buf_get_int64(struct cbuf *buf)
+static u64 buf_get_int64(struct cbuf *buf)
 {
 	u64 ret = 0;
 
@@ -178,7 +178,7 @@
 	return ret;
 }
 
-static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
+static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
 {
 	vstr->len = buf_get_int16(buf);
 	if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
@@ -190,7 +190,7 @@
 	}
 }
 
-static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
+static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
 {
 	qid->type = buf_get_int8(bufp);
 	qid->version = buf_get_int32(bufp);
@@ -254,7 +254,7 @@
  *
  */
 
-static inline void
+static void
 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
 {
 	stat->size = buf_get_int16(bufp);
@@ -427,7 +427,7 @@
 	buf_put_int64(bufp, val);
 }
 
-static inline void
+static void
 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
 {
 	if (data) {
@@ -441,7 +441,7 @@
 	buf_put_stringn(bufp, data, str->len);
 }
 
-static inline int
+static int
 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
 		   unsigned char **pdata)
 {
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index e93a7ae..62d8d4a 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -195,6 +195,8 @@
 		if (!empty)
 			d_invalidate(dentry);
 
+		nd.dentry = dentry;
+		nd.mnt = mnt;
 		nd.flags = LOOKUP_DIRECTORY;
 		status = (dentry->d_op->d_revalidate)(dentry, &nd);
 
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index f979ebb..1b117a4 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1218,7 +1218,7 @@
 	if (!dump_seek(file, (off))) \
 		goto end_coredump;
 
-static inline void fill_elf_header(struct elfhdr *elf, int segs)
+static void fill_elf_header(struct elfhdr *elf, int segs)
 {
 	memcpy(elf->e_ident, ELFMAG, SELFMAG);
 	elf->e_ident[EI_CLASS] = ELF_CLASS;
@@ -1243,7 +1243,7 @@
 	return;
 }
 
-static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
 {
 	phdr->p_type = PT_NOTE;
 	phdr->p_offset = offset;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 9ccc7d8..6a7b730 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -264,7 +264,7 @@
 	return p - from;
 }
 
-static inline char * check_special_flags (char * sfs, Node * e)
+static char * check_special_flags (char * sfs, Node * e)
 {
 	char * p = sfs;
 	int cont = 1;
diff --git a/fs/bio.c b/fs/bio.c
index 7b30695..bbc442b 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -123,7 +123,7 @@
 	bio_free(bio, fs_bio_set);
 }
 
-inline void bio_init(struct bio *bio)
+void bio_init(struct bio *bio)
 {
 	bio->bi_next = NULL;
 	bio->bi_bdev = NULL;
@@ -253,7 +253,7 @@
  *	the actual data it points to. Reference count of returned
  * 	bio will be one.
  */
-inline void __bio_clone(struct bio *bio, struct bio *bio_src)
+void __bio_clone(struct bio *bio, struct bio *bio_src)
 {
 	request_queue_t *q = bdev_get_queue(bio_src->bi_bdev);
 
diff --git a/fs/buffer.c b/fs/buffer.c
index b9bb7ad..7cdf48a 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1165,7 +1165,7 @@
  * some of those buffers may be aliases of filesystem data.
  * grow_dev_page() will go BUG() if this happens.
  */
-static inline int
+static int
 grow_buffers(struct block_device *bdev, sector_t block, int size)
 {
 	struct page *page;
@@ -1391,7 +1391,7 @@
 /*
  * Look up the bh in this cpu's LRU.  If it's there, move it to the head.
  */
-static inline struct buffer_head *
+static struct buffer_head *
 lookup_bh_lru(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *ret = NULL;
@@ -1541,7 +1541,7 @@
 /*
  * Called when truncating a buffer on a page completely.
  */
-static inline void discard_buffer(struct buffer_head * bh)
+static void discard_buffer(struct buffer_head * bh)
 {
 	lock_buffer(bh);
 	clear_buffer_dirty(bh);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 3b1b1ee..21195c4 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -35,7 +35,7 @@
 	unsigned int major;
 	unsigned int baseminor;
 	int minorct;
-	const char *name;
+	char name[64];
 	struct file_operations *fops;
 	struct cdev *cdev;		/* will die */
 } *chrdevs[MAX_PROBE_HASH];
@@ -46,34 +46,84 @@
 	return major % MAX_PROBE_HASH;
 }
 
-/* get char device names in somewhat random order */
-int get_chrdev_list(char *page)
+struct chrdev_info {
+	int index;
+	struct char_device_struct *cd;
+};
+
+void *get_next_chrdev(void *dev)
+{
+	struct chrdev_info *info;
+
+	if (dev == NULL) {
+		info = kmalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
+			goto out;
+		info->index=0;
+		info->cd = chrdevs[info->index];
+		if (info->cd)
+			goto out;
+	} else {
+		info = dev;
+	}
+
+	while (info->index < ARRAY_SIZE(chrdevs)) {
+		if (info->cd)
+			info->cd = info->cd->next;
+		if (info->cd)
+			goto out;
+		/*
+		 * No devices on this chain, move to the next
+		 */
+		info->index++;
+		info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
+			chrdevs[info->index] : NULL;
+		if (info->cd)
+			goto out;
+	}
+
+out:
+	return info;
+}
+
+void *acquire_chrdev_list(void)
+{
+	down(&chrdevs_lock);
+	return get_next_chrdev(NULL);
+}
+
+void release_chrdev_list(void *dev)
+{
+	up(&chrdevs_lock);
+	kfree(dev);
+}
+
+
+int count_chrdev_list(void)
 {
 	struct char_device_struct *cd;
-	int i, len;
+	int i, count;
 
-	len = sprintf(page, "Character devices:\n");
+	count = 0;
 
-	down(&chrdevs_lock);
 	for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-		for (cd = chrdevs[i]; cd; cd = cd->next) {
-			/*
-			 * if the current name, plus the 5 extra characters
-			 * in the device line for this entry
-			 * would run us off the page, we're done
-			 */
-			if ((len+strlen(cd->name) + 5) >= PAGE_SIZE)
-				goto page_full;
-
-
-			len += sprintf(page+len, "%3d %s\n",
-				       cd->major, cd->name);
-		}
+		for (cd = chrdevs[i]; cd; cd = cd->next)
+			count++;
 	}
-page_full:
-	up(&chrdevs_lock);
 
-	return len;
+	return count;
+}
+
+int get_chrdev_info(void *dev, int *major, char **name)
+{
+	struct chrdev_info *info = dev;
+
+	if (info->cd == NULL)
+		return 1;
+
+	*major = info->cd->major;
+	*name = info->cd->name;
+	return 0;
 }
 
 /*
@@ -121,7 +171,7 @@
 	cd->major = major;
 	cd->baseminor = baseminor;
 	cd->minorct = minorct;
-	cd->name = name;
+	strncpy(cd->name,name, 64);
 
 	i = major_to_index(major);
 
diff --git a/fs/compat.c b/fs/compat.c
index 271b75d..2468ac1 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1537,7 +1537,7 @@
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
  * 64-bit unsigned longs.
  */
-static inline
+static
 int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
 			unsigned long *fdset)
 {
@@ -1570,7 +1570,7 @@
 	return 0;
 }
 
-static inline
+static
 void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
 			unsigned long *fdset)
 {
diff --git a/fs/dcache.c b/fs/dcache.c
index 134d677..86bdb93 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -94,7 +94,7 @@
  * d_iput() operation if defined.
  * Called with dcache_lock and per dentry lock held, drops both.
  */
-static inline void dentry_iput(struct dentry * dentry)
+static void dentry_iput(struct dentry * dentry)
 {
 	struct inode *inode = dentry->d_inode;
 	if (inode) {
diff --git a/fs/exec.c b/fs/exec.c
index b5bcf1a..62b40af 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -575,7 +575,7 @@
  * disturbing other processes.  (Other processes might share the signal
  * table via the CLONE_SIGHAND option to clone().)
  */
-static inline int de_thread(struct task_struct *tsk)
+static int de_thread(struct task_struct *tsk)
 {
 	struct signal_struct *sig = tsk->signal;
 	struct sighand_struct *newsighand, *oldsighand = tsk->sighand;
@@ -780,7 +780,7 @@
  * so that a new one can be started
  */
 
-static inline void flush_old_files(struct files_struct * files)
+static void flush_old_files(struct files_struct * files)
 {
 	long j = -1;
 	struct fdtable *fdt;
@@ -964,7 +964,7 @@
 
 EXPORT_SYMBOL(prepare_binprm);
 
-static inline int unsafe_exec(struct task_struct *p)
+static int unsafe_exec(struct task_struct *p)
 {
 	int unsafe = 0;
 	if (p->ptrace & PT_PTRACED) {
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index c551395..ad1432a 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -83,10 +83,7 @@
 		if (!inode)
 			return ERR_PTR(-EACCES);
 	}
-	if (inode)
-		return d_splice_alias(inode, dentry);
-	d_add(dentry, inode);
-	return NULL;
+	return d_splice_alias(inode, dentry);
 }
 
 struct dentry *ext2_get_parent(struct dentry *child)
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index af193a3..8bd8ac0 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1005,10 +1005,7 @@
 		if (!inode)
 			return ERR_PTR(-EACCES);
 	}
-	if (inode)
-		return d_splice_alias(inode, dentry);
-	d_add(dentry, inode);
-	return NULL;
+	return d_splice_alias(inode, dentry);
 }
 
 
diff --git a/fs/fcntl.c b/fs/fcntl.c
index d0767fe..5f96786 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -36,7 +36,7 @@
 	spin_unlock(&files->file_lock);
 }
 
-static inline int get_close_on_exec(unsigned int fd)
+static int get_close_on_exec(unsigned int fd)
 {
 	struct files_struct *files = current->files;
 	struct fdtable *fdt;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index ab4c3a9..f568102 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -402,7 +402,7 @@
 		inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		info = HUGETLBFS_I(inode);
-		mpol_shared_policy_init(&info->policy);
+		mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL);
 		switch (mode & S_IFMT) {
 		default:
 			init_special_inode(inode, mode, dev);
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index e37e82b..e7ba0c3 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -185,8 +185,5 @@
 		}
 	}
 	unlock_kernel();
-	if (inode)
-		return d_splice_alias(inode, dentry);
-	d_add(dentry, inode);
-	return NULL;
+	return d_splice_alias(inode, dentry);
 }
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index fff108b..70f7a89 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -47,7 +47,7 @@
 	     ic = next_inode(&i, ic, (c)))
 
 
-static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
+static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
 					struct jffs2_inode_cache *ic)
 {
 	struct jffs2_full_dirent *fd;
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index c79eebb..b635e16 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -134,7 +134,7 @@
 /*
  * Allocate and initializes a new fragment.
  */
-static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
+static struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
 {
 	struct jffs2_node_frag *newfrag;
 
@@ -513,7 +513,7 @@
  *
  * Checks the node if we are in the checking stage.
  */
-static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
+static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
 {
 	int ret;
 
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index f01e9c0..200fbda 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -44,7 +44,7 @@
 /*
  * XDR functions for basic NLM types
  */
-static inline u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
+static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
 {
 	unsigned int	len;
 
@@ -79,7 +79,7 @@
 	return p;
 }
 
-static inline u32 *
+static u32 *
 nlm_decode_fh(u32 *p, struct nfs_fh *f)
 {
 	unsigned int	len;
@@ -119,7 +119,7 @@
 	return xdr_encode_netobj(p, oh);
 }
 
-static inline u32 *
+static u32 *
 nlm_decode_lock(u32 *p, struct nlm_lock *lock)
 {
 	struct file_lock	*fl = &lock->fl;
diff --git a/fs/mbcache.c b/fs/mbcache.c
index 0f1e453..f5bbe4c 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -126,7 +126,7 @@
 }
 
 
-static inline void
+static void
 __mb_cache_entry_unhash(struct mb_cache_entry *ce)
 {
 	int n;
@@ -139,7 +139,7 @@
 }
 
 
-static inline void
+static void
 __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask)
 {
 	struct mb_cache *cache = ce->e_cache;
@@ -158,7 +158,7 @@
 }
 
 
-static inline void
+static void
 __mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
 {
 	/* Wake up all processes queuing for this cache entry. */
diff --git a/fs/namei.c b/fs/namei.c
index 1e5746e..33fb5bd 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -113,7 +113,7 @@
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static inline int do_getname(const char __user *filename, char *page)
+static int do_getname(const char __user *filename, char *page)
 {
 	int retval;
 	unsigned long len = PATH_MAX;
@@ -396,7 +396,7 @@
  * short-cut DAC fails, then call permission() to do more
  * complete permission check.
  */
-static inline int exec_permission_lite(struct inode *inode,
+static int exec_permission_lite(struct inode *inode,
 				       struct nameidata *nd)
 {
 	umode_t	mode = inode->i_mode;
@@ -486,7 +486,7 @@
 static int __emul_lookup_dentry(const char *, struct nameidata *);
 
 /* SMP-safe */
-static inline int
+static __always_inline int
 walk_init_root(const char *name, struct nameidata *nd)
 {
 	read_lock(&current->fs->lock);
@@ -504,7 +504,7 @@
 	return 1;
 }
 
-static inline int __vfs_follow_link(struct nameidata *nd, const char *link)
+static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
 {
 	int res = 0;
 	char *name;
@@ -544,7 +544,7 @@
 	struct dentry *dentry;
 };
 
-static inline int __do_follow_link(struct path *path, struct nameidata *nd)
+static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
 {
 	int error;
 	void *cookie;
@@ -690,7 +690,7 @@
 	return 0;
 }
 
-static inline void follow_dotdot(struct nameidata *nd)
+static __always_inline void follow_dotdot(struct nameidata *nd)
 {
 	while(1) {
 		struct vfsmount *parent;
@@ -1294,7 +1294,7 @@
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 {
 	int error;
 
@@ -2315,7 +2315,7 @@
 	return error;
 }
 
-static inline int do_rename(const char * oldname, const char * newname)
+static int do_rename(const char * oldname, const char * newname)
 {
 	int error = 0;
 	struct dentry * old_dir, * new_dir;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 8c88392..d277a58 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -716,10 +716,8 @@
 	fput(server->ncp_filp);
 	kill_proc(server->m.wdog_pid, SIGTERM, 1);
 
-	if (server->priv.data) 
-		ncp_kfree_s(server->priv.data, server->priv.len);
-	if (server->auth.object_name)
-		ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
+	kfree(server->priv.data);
+	kfree(server->auth.object_name);
 	vfree(server->packet);
 	sb->s_fs_info = NULL;
 	kfree(server);
@@ -958,11 +956,6 @@
 	return result;
 }
 
-#ifdef DEBUG_NCP_MALLOC
-int ncp_malloced;
-int ncp_current_malloced;
-#endif
-
 static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
@@ -981,10 +974,6 @@
 	int err;
 	DPRINTK("ncpfs: init_module called\n");
 
-#ifdef DEBUG_NCP_MALLOC
-	ncp_malloced = 0;
-	ncp_current_malloced = 0;
-#endif
 	err = init_inodecache();
 	if (err)
 		goto out1;
@@ -1003,10 +992,6 @@
 	DPRINTK("ncpfs: cleanup_module called\n");
 	unregister_filesystem(&ncp_fs_type);
 	destroy_inodecache();
-#ifdef DEBUG_NCP_MALLOC
-	PRINTK("ncp_malloced: %d\n", ncp_malloced);
-	PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
-#endif
 }
 
 module_init(init_ncp_fs)
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index d6e0c08..eb3813a 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -518,10 +518,11 @@
 			if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
 				return -ENOMEM;
 			if (user.object_name_len) {
-				newname = ncp_kmalloc(user.object_name_len, GFP_USER);
-				if (!newname) return -ENOMEM;
+				newname = kmalloc(user.object_name_len, GFP_USER);
+				if (!newname)
+					return -ENOMEM;
 				if (copy_from_user(newname, user.object_name, user.object_name_len)) {
-					ncp_kfree_s(newname, user.object_name_len);
+					kfree(newname);
 					return -EFAULT;
 				}
 			} else {
@@ -540,8 +541,8 @@
 			server->priv.len = 0;
 			server->priv.data = NULL;
 			/* leave critical section */
-			if (oldprivate) ncp_kfree_s(oldprivate, oldprivatelen);
-			if (oldname) ncp_kfree_s(oldname, oldnamelen);
+			kfree(oldprivate);
+			kfree(oldname);
 			return 0;
 		}
 	case NCP_IOC_GETPRIVATEDATA:
@@ -581,10 +582,11 @@
 			if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
 				return -ENOMEM;
 			if (user.len) {
-				new = ncp_kmalloc(user.len, GFP_USER);
-				if (!new) return -ENOMEM;
+				new = kmalloc(user.len, GFP_USER);
+				if (!new)
+					return -ENOMEM;
 				if (copy_from_user(new, user.data, user.len)) {
-					ncp_kfree_s(new, user.len);
+					kfree(new);
 					return -EFAULT;
 				}
 			} else {
@@ -596,7 +598,7 @@
 			server->priv.len = user.len;
 			server->priv.data = new;
 			/* leave critical section */
-			if (old) ncp_kfree_s(old, oldlen);
+			kfree(old);
 			return 0;
 		}
 
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index aa7bb41..e3a0797 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -37,7 +37,7 @@
 /*
  * XDR functions for basic NFS types
  */
-static inline u32 *
+static u32 *
 decode_fh(u32 *p, struct svc_fh *fhp)
 {
 	fh_init(fhp, NFS_FHSIZE);
@@ -151,7 +151,7 @@
 	return p;
 }
 
-static inline u32 *
+static u32 *
 encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
 	     struct kstat *stat)
 {
diff --git a/fs/pipe.c b/fs/pipe.c
index eef0f29..d722579 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -50,7 +50,7 @@
 	mutex_lock(PIPE_MUTEX(*inode));
 }
 
-static inline int
+static int
 pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len)
 {
 	unsigned long copy;
@@ -70,7 +70,7 @@
 	return 0;
 }
 
-static inline int
+static int
 pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len)
 {
 	unsigned long copy;
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index fb117b7..9bdd077 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -81,6 +81,30 @@
 	__proc_device_tree_add_prop(pde, prop);
 }
 
+void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
+				  struct property *prop)
+{
+	remove_proc_entry(prop->name, pde);
+}
+
+void proc_device_tree_update_prop(struct proc_dir_entry *pde,
+				  struct property *newprop,
+				  struct property *oldprop)
+{
+	struct proc_dir_entry *ent;
+
+	for (ent = pde->subdir; ent != NULL; ent = ent->next)
+		if (ent->data == oldprop)
+			break;
+	if (ent == NULL) {
+		printk(KERN_WARNING "device-tree: property \"%s\" "
+		       " does not exist\n", oldprop->name);
+	} else {
+		ent->data = newprop;
+		ent->size = newprop->length;
+	}
+}
+
 /*
  * Process a node, adding entries for its children and its properties.
  */
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 63bf6c0..8f80142 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -20,6 +20,7 @@
 #include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
+#include <linux/fs.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/mman.h>
@@ -62,7 +63,6 @@
  */
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
-extern int get_chrdev_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
@@ -248,6 +248,154 @@
 {
 	return seq_open(file, &cpuinfo_op);
 }
+
+enum devinfo_states {
+	CHR_HDR,
+	CHR_LIST,
+	BLK_HDR,
+	BLK_LIST,
+	DEVINFO_DONE
+};
+
+struct devinfo_state {
+	void *chrdev;
+	void *blkdev;
+	unsigned int num_records;
+	unsigned int cur_record;
+	enum devinfo_states state;
+};
+
+static void *devinfo_start(struct seq_file *f, loff_t *pos)
+{
+	struct devinfo_state *info = f->private;
+
+	if (*pos) {
+		if ((info) && (*pos <= info->num_records))
+			return info;
+		return NULL;
+	}
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	f->private = info;
+	info->chrdev = acquire_chrdev_list();
+	info->blkdev = acquire_blkdev_list();
+	info->state = CHR_HDR;
+	info->num_records = count_chrdev_list();
+	info->num_records += count_blkdev_list();
+	info->num_records += 2; /* Character and Block headers */
+	*pos = 1;
+	info->cur_record = *pos;
+	return info;
+}
+
+static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	int idummy;
+	char *ndummy;
+	struct devinfo_state *info = f->private;
+
+	switch (info->state) {
+		case CHR_HDR:
+			info->state = CHR_LIST;
+			(*pos)++;
+			/*fallthrough*/
+		case CHR_LIST:
+			if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
+				/*
+				 * The character dev list is complete
+				 */
+				info->state = BLK_HDR;
+			} else {
+				info->chrdev = get_next_chrdev(info->chrdev);
+			}
+			(*pos)++;
+			break;
+		case BLK_HDR:
+			info->state = BLK_LIST;
+			(*pos)++;
+			break;
+		case BLK_LIST:
+			if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
+				/*
+				 * The block dev list is complete
+				 */
+				info->state = DEVINFO_DONE;
+			} else {
+				info->blkdev = get_next_blkdev(info->blkdev);
+			}
+			(*pos)++;
+			break;
+		case DEVINFO_DONE:
+			(*pos)++;
+			info->cur_record = *pos;
+			info = NULL;
+			break;
+		default:
+			break;
+	}
+	if (info)
+		info->cur_record = *pos;
+	return info;
+}
+
+static void devinfo_stop(struct seq_file *f, void *v)
+{
+	struct devinfo_state *info = f->private;
+
+	if (info) {
+		release_chrdev_list(info->chrdev);
+		release_blkdev_list(info->blkdev);
+		f->private = NULL;
+		kfree(info);
+	}
+}
+
+static int devinfo_show(struct seq_file *f, void *arg)
+{
+	int major;
+	char *name;
+	struct devinfo_state *info = f->private;
+
+	switch(info->state) {
+		case CHR_HDR:
+			seq_printf(f,"Character devices:\n");
+			/* fallthrough */
+		case CHR_LIST:
+			if (!get_chrdev_info(info->chrdev,&major,&name))
+				seq_printf(f,"%3d %s\n",major,name);
+			break;
+		case BLK_HDR:
+			seq_printf(f,"\nBlock devices:\n");
+			/* fallthrough */
+		case BLK_LIST:
+			if (!get_blkdev_info(info->blkdev,&major,&name))
+				seq_printf(f,"%3d %s\n",major,name);
+			break;
+		default:
+			break;
+	}
+
+	return 0;
+}
+
+static  struct seq_operations devinfo_op = {
+	.start  = devinfo_start,
+	.next   = devinfo_next,
+	.stop   = devinfo_stop,
+	.show   = devinfo_show,
+};
+
+static int devinfo_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &devinfo_op);
+}
+
+static struct file_operations proc_devinfo_operations = {
+	.open		= devinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 static struct file_operations proc_cpuinfo_operations = {
 	.open		= cpuinfo_open,
 	.read		= seq_read,
@@ -450,14 +598,6 @@
 	.release	= single_release,
 };
 
-static int devices_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	int len = get_chrdev_list(page);
-	len += get_blkdev_list(page+len, len);
-	return proc_calc_metrics(page, start, off, count, eof, len);
-}
-
 /*
  * /proc/interrupts
  */
@@ -582,7 +722,6 @@
 #ifdef CONFIG_STRAM_PROC
 		{"stram",	stram_read_proc},
 #endif
-		{"devices",	devices_read_proc},
 		{"filesystems",	filesystems_read_proc},
 		{"cmdline",	cmdline_read_proc},
 		{"locks",	locks_read_proc},
@@ -598,6 +737,7 @@
 	entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
+	create_seq_entry("devices", 0, &proc_devinfo_operations);
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
 	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("stat", 0, &proc_stat_operations);
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index 7afcbb1..a4ef91b 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -35,7 +35,8 @@
  
 	size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
 	if (size != sizeof(struct v2_disk_dqheader)) {
-		printk("failed read\n");
+		printk("quota_v2: failed read expected=%d got=%d\n",
+			sizeof(struct v2_disk_dqheader), size);
 		return 0;
 	}
 	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 3549067..8f8d8d0 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -375,11 +375,7 @@
 		return ERR_PTR(-EIO);
 	}
 
-	if (inode)
-		return d_splice_alias(inode, dentry);
-
-	d_add(dentry, inode);
-	return NULL;
+	return d_splice_alias(inode, dentry);
 }
 
 /* 
diff --git a/fs/smbfs/Makefile b/fs/smbfs/Makefile
index 93246b7..6673ee8 100644
--- a/fs/smbfs/Makefile
+++ b/fs/smbfs/Makefile
@@ -13,7 +13,6 @@
 EXTRA_CFLAGS += -DSMBFS_PARANOIA
 #EXTRA_CFLAGS += -DSMBFS_DEBUG
 #EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE
-#EXTRA_CFLAGS += -DDEBUG_SMB_MALLOC
 #EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP
 #EXTRA_CFLAGS += -Werror
 
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 6ec88bf..02e3e82 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -487,11 +487,11 @@
 	if (server->conn_pid)
 		kill_proc(server->conn_pid, SIGTERM, 1);
 
-	smb_kfree(server->ops);
+	kfree(server->ops);
 	smb_unload_nls(server);
 	sb->s_fs_info = NULL;
 	smb_unlock_server(server);
-	smb_kfree(server);
+	kfree(server);
 }
 
 static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
@@ -519,11 +519,10 @@
 	sb->s_op = &smb_sops;
 	sb->s_time_gran = 100;
 
-	server = smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
+	server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
 	if (!server)
 		goto out_no_server;
 	sb->s_fs_info = server;
-	memset(server, 0, sizeof(struct smb_sb_info));
 
 	server->super_block = sb;
 	server->mnt = NULL;
@@ -542,8 +541,8 @@
 	/* FIXME: move these to the smb_sb_info struct */
 	VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) +
 		sizeof(struct smb_mount_data_kernel));
-	mem = smb_kmalloc(sizeof(struct smb_ops) +
-			  sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
+	mem = kmalloc(sizeof(struct smb_ops) +
+		      sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
 	if (!mem)
 		goto out_no_mem;
 
@@ -621,12 +620,12 @@
 out_no_smbiod:
 	smb_unload_nls(server);
 out_bad_option:
-	smb_kfree(mem);
+	kfree(mem);
 out_no_mem:
 	if (!server->mnt)
 		printk(KERN_ERR "smb_fill_super: allocation failure\n");
 	sb->s_fs_info = NULL;
-	smb_kfree(server);
+	kfree(server);
 	goto out_fail;
 out_wrong_data:
 	printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
@@ -782,12 +781,6 @@
 	return error;
 }
 
-#ifdef DEBUG_SMB_MALLOC
-int smb_malloced;
-int smb_current_kmalloced;
-int smb_current_vmalloced;
-#endif
-
 static struct super_block *smb_get_sb(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data)
 {
@@ -807,12 +800,6 @@
 	int err;
 	DEBUG1("registering ...\n");
 
-#ifdef DEBUG_SMB_MALLOC
-	smb_malloced = 0;
-	smb_current_kmalloced = 0;
-	smb_current_vmalloced = 0;
-#endif
-
 	err = init_inodecache();
 	if (err)
 		goto out_inode;
@@ -837,11 +824,6 @@
 	unregister_filesystem(&smb_fs_type);
 	smb_destroy_request_cache();
 	destroy_inodecache();
-#ifdef DEBUG_SMB_MALLOC
-	printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
-	printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
-	printk(KERN_DEBUG "smb_current_vmalloced: %d\n",smb_current_vmalloced);
-#endif
 }
 
 module_init(init_smb_fs)
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index a0f296d..c71c375 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -68,7 +68,7 @@
 		goto out;
 
 	if (bufsize > 0) {
-		buf = smb_kmalloc(bufsize, GFP_NOFS);
+		buf = kmalloc(bufsize, GFP_NOFS);
 		if (!buf) {
 			kmem_cache_free(req_cachep, req);
 			return NULL;
@@ -124,9 +124,8 @@
 {
 	atomic_dec(&req->rq_server->nr_requests);
 	if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC))
-		smb_kfree(req->rq_buffer);
-	if (req->rq_trans2buffer)
-		smb_kfree(req->rq_trans2buffer);
+		kfree(req->rq_buffer);
+	kfree(req->rq_trans2buffer);
 	kmem_cache_free(req_cachep, req);
 }
 
@@ -183,8 +182,7 @@
 	req->rq_err = 0;
 	req->rq_errno = 0;
 	req->rq_fragment = 0;
-	if (req->rq_trans2buffer)
-		smb_kfree(req->rq_trans2buffer);
+	kfree(req->rq_trans2buffer);
 
 	return 0;
 }
@@ -647,10 +645,9 @@
 			goto out_too_long;
 
 		req->rq_trans2bufsize = buf_len;
-		req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS);
+		req->rq_trans2buffer = kzalloc(buf_len, GFP_NOFS);
 		if (!req->rq_trans2buffer)
 			goto out_no_mem;
-		memset(req->rq_trans2buffer, 0, buf_len);
 
 		req->rq_parm = req->rq_trans2buffer;
 		req->rq_data = req->rq_trans2buffer + parm_tot;
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index a9f4421..3ada9dc 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -49,7 +49,7 @@
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	
 	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
 	
@@ -81,8 +81,9 @@
 	for (i = bit; i < end_bit; i++) {
 		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
 			ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
-		else ufs_error (sb, "ufs_free_fragments",
-			"bit already cleared for fragment %u", i);
+		else 
+			ufs_error (sb, "ufs_free_fragments",
+				   "bit already cleared for fragment %u", i);
 	}
 	
 	DQUOT_FREE_BLOCK (inode, count);
@@ -143,7 +144,7 @@
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 
 	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
 	
@@ -247,7 +248,7 @@
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	*err = -ENOSPC;
 
 	lock_super (sb);
@@ -407,7 +408,7 @@
 	
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first (USPI_UBH);
+	usb1 = ubh_get_usb_first (uspi);
 	count = newcount - oldcount;
 	
 	cgno = ufs_dtog(fragment);
@@ -490,7 +491,7 @@
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	oldcg = cgno;
 	
 	/*
@@ -606,7 +607,7 @@
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	ucg = ubh_get_ucg(UCPI_UBH);
 
 	if (goal == 0) {
@@ -663,7 +664,7 @@
 	UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
 
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first (USPI_UBH);
+	usb1 = ubh_get_usb_first (uspi);
 	ucg = ubh_get_ucg(UCPI_UBH);
 
 	if (goal)
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 0938945..c7a47ed 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -72,7 +72,7 @@
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	
 	ino = inode->i_ino;
 
@@ -167,7 +167,7 @@
 	ufsi = UFS_I(inode);
 	sbi = UFS_SB(sb);
 	uspi = sbi->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 
 	lock_super (sb);
 
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 55f4aa1..e0c04e3 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -61,7 +61,7 @@
 	int n = 0;
 
 
-	UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%d \n",ptrs,double_blocks));
+	UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks));
 	if (i_block < 0) {
 		ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
 	} else if (i_block < direct_blocks) {
@@ -104,7 +104,7 @@
 	unsigned flags = UFS_SB(sb)->s_flags;
 	u64 temp = 0L;
 
-	UFSD((": frag = %lu  depth = %d\n",frag,depth));
+	UFSD((": frag = %llu  depth = %d\n", (unsigned long long)frag, depth));
 	UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));
 
 	if (depth == 0)
@@ -365,9 +365,10 @@
 		sync_dirty_buffer(bh);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
+	UFSD(("result %u\n", tmp + blockoff));
 out:
 	brelse (bh);
-	UFSD(("EXIT, result %u\n", tmp + blockoff))
+	UFSD(("EXIT\n"));
 	return result;
 }
 
@@ -386,7 +387,7 @@
 	
 	if (!create) {
 		phys64 = ufs_frag_map(inode, fragment);
-		UFSD(("phys64 = %lu \n",phys64));
+		UFSD(("phys64 = %llu \n",phys64));
 		if (phys64)
 			map_bh(bh_result, sb, phys64);
 		return 0;
@@ -401,7 +402,7 @@
 
 	lock_kernel();
 
-	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment))
 	if (fragment < 0)
 		goto abort_negative;
 	if (fragment >
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index e9a42c7..d4aacee 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -221,7 +221,7 @@
 	va_list args;
 
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
@@ -253,7 +253,7 @@
 	va_list args;
 	
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
 	
 	if (!(sb->s_flags & MS_RDONLY)) {
 		usb1->fs_clean = UFS_FSBAD;
@@ -420,21 +420,18 @@
 		if (i + uspi->s_fpb > blks)
 			size = (blks - i) * uspi->s_fsize;
 
-		if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 
 			ubh = ubh_bread(sb,
 				fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
-			if (!ubh)
-				goto failed;
-			ubh_ubhcpymem (space, ubh, size);
-			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-		}
-		else {
+		else 
 			ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-			if (!ubh)
-				goto failed;
-			ubh_ubhcpymem(space, ubh, size);
-			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-		}
+		
+		if (!ubh)
+			goto failed;
+
+		ubh_ubhcpymem (space, ubh, size);
+		sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+
 		space += size;
 		ubh_brelse (ubh);
 		ubh = NULL;
@@ -539,6 +536,7 @@
 	struct inode *inode;
 	unsigned block_size, super_block_size;
 	unsigned flags;
+	unsigned super_block_offset;
 
 	uspi = NULL;
 	ubh = NULL;
@@ -586,10 +584,11 @@
 	if (!uspi)
 		goto failed;
 
+	super_block_offset=UFS_SBLOCK;
+
 	/* Keep 2Gig file limit. Some UFS variants need to override 
 	   this but as I don't know which I'll let those in the know loosen
 	   the rules */
-	   
 	switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
 	case UFS_MOUNT_UFSTYPE_44BSD:
 		UFSD(("ufstype=44bsd\n"))
@@ -601,7 +600,8 @@
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
 		break;
 	case UFS_MOUNT_UFSTYPE_UFS2:
-		UFSD(("ufstype=ufs2\n"))
+		UFSD(("ufstype=ufs2\n"));
+		super_block_offset=SBLOCK_UFS2;
 		uspi->s_fsize = block_size = 512;
 		uspi->s_fmask = ~(512 - 1);
 		uspi->s_fshift = 9;
@@ -725,19 +725,16 @@
 	/*
 	 * read ufs super block from device
 	 */
-	if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
-		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size);
-	}
-	else {
-		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
-	}
+
+	ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + super_block_offset/block_size, super_block_size);
+	
 	if (!ubh) 
             goto failed;
 
 	
-	usb1 = ubh_get_usb_first(USPI_UBH);
-	usb2 = ubh_get_usb_second(USPI_UBH);
-	usb3 = ubh_get_usb_third(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
+	usb2 = ubh_get_usb_second(uspi);
+	usb3 = ubh_get_usb_third(uspi);
 	usb  = (struct ufs_super_block *)
 		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
@@ -1006,8 +1003,8 @@
 	UFSD(("ENTER\n"))
 	flags = UFS_SB(sb)->s_flags;
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
-	usb3 = ubh_get_usb_third(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
+	usb3 = ubh_get_usb_third(uspi);
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		usb1->fs_time = cpu_to_fs32(sb, get_seconds());
@@ -1049,8 +1046,8 @@
 	
 	uspi = UFS_SB(sb)->s_uspi;
 	flags = UFS_SB(sb)->s_flags;
-	usb1 = ubh_get_usb_first(USPI_UBH);
-	usb3 = ubh_get_usb_third(USPI_UBH);
+	usb1 = ubh_get_usb_first(uspi);
+	usb3 = ubh_get_usb_third(uspi);
 	
 	/*
 	 * Allow the "check" option to be passed as a remount option.
@@ -1124,7 +1121,7 @@
 	lock_kernel();
 
 	uspi = UFS_SB(sb)->s_uspi;
-	usb1 = ubh_get_usb_first (USPI_UBH);
+	usb1 = ubh_get_usb_first (uspi);
 	usb  = (struct ufs_super_block *)
 		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 	
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index b264007..48d6d9b 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -249,18 +249,28 @@
 
 
 /*
- * macros to get important structures from ufs_buffer_head
+ * macros and inline function to get important structures from ufs_sb_private_info
  */
-#define ubh_get_usb_first(ubh) \
-	((struct ufs_super_block_first *)((ubh)->bh[0]->b_data))
 
-#define ubh_get_usb_second(ubh) \
-	((struct ufs_super_block_second *)(ubh)-> \
-	bh[UFS_SECTOR_SIZE >> uspi->s_fshift]->b_data + (UFS_SECTOR_SIZE & ~uspi->s_fmask))
+static inline void *get_usb_offset(struct ufs_sb_private_info *uspi,
+				   unsigned int offset)
+{
+	unsigned int index;
+	
+	index = offset >> uspi->s_fshift;
+	offset &= ~uspi->s_fmask;
+	return uspi->s_ubh.bh[index]->b_data + offset;
+}
 
-#define ubh_get_usb_third(ubh) \
-	((struct ufs_super_block_third *)((ubh)-> \
-	bh[UFS_SECTOR_SIZE*2 >> uspi->s_fshift]->b_data + (UFS_SECTOR_SIZE*2 & ~uspi->s_fmask)))
+#define ubh_get_usb_first(uspi) \
+	((struct ufs_super_block_first *)get_usb_offset((uspi), 0))
+
+#define ubh_get_usb_second(uspi) \
+	((struct ufs_super_block_second *)get_usb_offset((uspi), UFS_SECTOR_SIZE))
+
+#define ubh_get_usb_third(uspi)	\
+	((struct ufs_super_block_third *)get_usb_offset((uspi), 2*UFS_SECTOR_SIZE))
+
 
 #define ubh_get_ucg(ubh) \
 	((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data))
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
index 8cf70ff..2b57f91 100644
--- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h
+++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
@@ -26,6 +26,8 @@
  * fc000000	da000000	16M		PCI CFG0
  * fd000000	d8000000	16M		PCI I/O
  * fe[0-7]00000			8M		per-platform mappings
+ * fe900000	80000000	1M		SRAM #0 (first MB)
+ * fea00000	cb400000	1M		SCRATCH ring get/put
  * feb00000	c8000000	1M		MSF
  * fec00000	df000000	1M		PCI CSRs
  * fed00000	de000000	1M		PCI CREG
@@ -91,6 +93,14 @@
 #define IXP2000_MSF_VIRT_BASE		0xfeb00000
 #define IXP2000_MSF_SIZE		0x00100000
 
+#define IXP2000_SCRATCH_RING_PHYS_BASE	0xcb400000
+#define IXP2000_SCRATCH_RING_VIRT_BASE	0xfea00000
+#define IXP2000_SCRATCH_RING_SIZE	0x00100000
+
+#define IXP2000_SRAM0_PHYS_BASE		0x80000000
+#define IXP2000_SRAM0_VIRT_BASE		0xfe900000
+#define IXP2000_SRAM0_SIZE		0x00100000
+
 #define IXP2000_PCI_IO_PHYS_BASE	0xd8000000
 #define	IXP2000_PCI_IO_VIRT_BASE	0xfd000000
 #define IXP2000_PCI_IO_SIZE     	0x01000000
diff --git a/include/asm-arm/arch-versatile/entry-macro.S b/include/asm-arm/arch-versatile/entry-macro.S
index 58f0d71..feff771 100644
--- a/include/asm-arm/arch-versatile/entry-macro.S
+++ b/include/asm-arm/arch-versatile/entry-macro.S
@@ -8,6 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 #include <asm/hardware.h>
+#include <asm/hardware/vic.h>
 
 		.macro	disable_fiq
 		.endm
diff --git a/include/asm-arm/arch-versatile/platform.h b/include/asm-arm/arch-versatile/platform.h
index cbdd9fb..72ef874 100644
--- a/include/asm-arm/arch-versatile/platform.h
+++ b/include/asm-arm/arch-versatile/platform.h
@@ -293,26 +293,7 @@
  * 	VERSATILE_SYS_IC 
  * 
  */
-#define VIC_IRQ_STATUS                  0
-#define VIC_FIQ_STATUS                  0x04
-#define VIC_IRQ_RAW_STATUS              0x08
-#define VIC_INT_SELECT                  0x0C	/* 1 = FIQ, 0 = IRQ */
-#define VIC_IRQ_ENABLE                  0x10	/* 1 = enable, 0 = disable */
-#define VIC_IRQ_ENABLE_CLEAR            0x14
-#define VIC_IRQ_SOFT                    0x18
-#define VIC_IRQ_SOFT_CLEAR              0x1C
-#define VIC_PROTECT                     0x20
-#define VIC_VECT_ADDR                   0x30
-#define VIC_DEF_VECT_ADDR               0x34
-#define VIC_VECT_ADDR0                  0x100	/* 0 to 15 */
-#define VIC_VECT_CNTL0                  0x200	/* 0 to 15 */
-#define VIC_ITCR                        0x300   /* VIC test control register */
-
-#define VIC_FIQ_RAW_STATUS              0x08
-#define VIC_FIQ_ENABLE                  0x10	/* 1 = enable, 0 = disable */
-#define VIC_FIQ_ENABLE_CLEAR            0x14
-#define VIC_FIQ_SOFT                    0x18
-#define VIC_FIQ_SOFT_CLEAR              0x1C
+/* VIC definitions in include/asm-arm/hardware/vic.h */
 
 #define SIC_IRQ_STATUS                  0
 #define SIC_IRQ_RAW_STATUS              0x04
@@ -325,8 +306,6 @@
 #define SIC_INT_PIC_ENABLES             0x20	/* set interrupt pass through bits */
 #define SIC_INT_PIC_ENABLEC             0x24	/* Clear interrupt pass through bits */
 
-#define VICVectCntl_Enable		(1 << 5)
-
 /* ------------------------------------------------------------------------
  *  Interrupts - bit assignment (primary)
  * ------------------------------------------------------------------------
diff --git a/include/asm-arm/hardware/vic.h b/include/asm-arm/hardware/vic.h
new file mode 100644
index 0000000..81825eb
--- /dev/null
+++ b/include/asm-arm/hardware/vic.h
@@ -0,0 +1,45 @@
+/*
+ *  linux/include/asm-arm/hardware/vic.h
+ *
+ *  Copyright (c) ARM Limited 2003.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARM_HARDWARE_VIC_H
+#define __ASM_ARM_HARDWARE_VIC_H
+
+#define VIC_IRQ_STATUS			0x00
+#define VIC_FIQ_STATUS			0x04
+#define VIC_RAW_STATUS			0x08
+#define VIC_INT_SELECT			0x0c	/* 1 = FIQ, 0 = IRQ */
+#define VIC_INT_ENABLE			0x10	/* 1 = enable, 0 = disable */
+#define VIC_INT_ENABLE_CLEAR		0x14
+#define VIC_INT_SOFT			0x18
+#define VIC_INT_SOFT_CLEAR		0x1c
+#define VIC_PROTECT			0x20
+#define VIC_VECT_ADDR			0x30
+#define VIC_DEF_VECT_ADDR		0x34
+
+#define VIC_VECT_ADDR0			0x100	/* 0 to 15 */
+#define VIC_VECT_CNTL0			0x200	/* 0 to 15 */
+#define VIC_ITCR			0x300	/* VIC test control register */
+
+#define VIC_VECT_CNTL_ENABLE		(1 << 5)
+
+#ifndef __ASSEMBLY__
+void vic_init(void __iomem *base, u32 vic_sources);
+#endif
+
+#endif
diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h
index eb262e07..8222bf9 100644
--- a/include/asm-arm/mach/arch.h
+++ b/include/asm-arm/mach/arch.h
@@ -20,7 +20,7 @@
 	 * by assembler code in head-armv.S
 	 */
 	unsigned int		nr;		/* architecture number	*/
-	unsigned int		phys_ram;	/* start of physical ram */
+	unsigned int __deprecated phys_ram;	/* start of physical ram */
 	unsigned int		phys_io;	/* start of physical io	*/
 	unsigned int		io_pg_offst;	/* byte offset for io 
 						 * page tabe entry	*/
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
index 4da1d53..416320d 100644
--- a/include/asm-arm/page.h
+++ b/include/asm-arm/page.h
@@ -170,6 +170,13 @@
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+/*
+ * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
+ */
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define ARCH_SLAB_MINALIGN 8
+#endif
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/page.h>
diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h
index 3129069..04f4d34 100644
--- a/include/asm-arm/processor.h
+++ b/include/asm-arm/processor.h
@@ -49,6 +49,12 @@
 
 #define INIT_THREAD  {	}
 
+#ifdef CONFIG_MMU
+#define nommu_start_thread(regs) do { } while (0)
+#else
+#define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
+#endif
+
 #define start_thread(regs,pc,sp)					\
 ({									\
 	unsigned long *stack = (unsigned long *)sp;			\
@@ -65,6 +71,7 @@
 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
 	regs->ARM_r1 = stack[1];	/* r1 (argv) */			\
 	regs->ARM_r0 = stack[0];	/* r0 (argc) */			\
+	nommu_start_thread(regs);					\
 })
 
 /* Forward declaration, a strange C thing */
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
index 4377e22..77adb7f 100644
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -23,6 +23,9 @@
 #define PTRACE_OLDSETOPTIONS	21
 
 #define PTRACE_GET_THREAD_AREA	22
+
+#define PTRACE_SET_SYSCALL	23
+
 /*
  * PSR bits
  */
@@ -60,9 +63,11 @@
 
 #ifndef __ASSEMBLY__
 
-/* this struct defines the way the registers are stored on the
-   stack during a system call. */
-
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call.  Note that sizeof(struct pt_regs)
+ * has to be a multiple of 8.
+ */
 struct pt_regs {
 	long uregs[18];
 };
diff --git a/include/asm-arm/stat.h b/include/asm-arm/stat.h
index ec4e2c2..42c0c13 100644
--- a/include/asm-arm/stat.h
+++ b/include/asm-arm/stat.h
@@ -70,14 +70,7 @@
 
 	long long	st_size;
 	unsigned long	st_blksize;
-
-#if defined(__ARMEB__)
-	unsigned long   __pad4;		/* Future possible st_blocks hi bits */
-	unsigned long   st_blocks;	/* Number 512-byte blocks allocated. */
-#else /* Must be little */
-	unsigned long   st_blocks;	/* Number 512-byte blocks allocated. */
-	unsigned long   __pad4;		/* Future possible st_blocks hi bits */
-#endif
+	unsigned long long st_blocks;	/* Number 512-byte blocks allocated. */
 
 	unsigned long	st_atime;
 	unsigned long	st_atime_nsec;
@@ -89,6 +82,6 @@
 	unsigned long	st_ctime_nsec;
 
 	unsigned long long	st_ino;
-} __attribute__((packed));
+};
 
 #endif
diff --git a/include/asm-arm/statfs.h b/include/asm-arm/statfs.h
index e81f827..a02e6a8 100644
--- a/include/asm-arm/statfs.h
+++ b/include/asm-arm/statfs.h
@@ -1,6 +1,42 @@
 #ifndef _ASMARM_STATFS_H
 #define _ASMARM_STATFS_H
 
-#include <asm-generic/statfs.h>
+#ifndef __KERNEL_STRICT_NAMES
+# include <linux/types.h>
+typedef __kernel_fsid_t	fsid_t;
+#endif
+
+struct statfs {
+	__u32 f_type;
+	__u32 f_bsize;
+	__u32 f_blocks;
+	__u32 f_bfree;
+	__u32 f_bavail;
+	__u32 f_files;
+	__u32 f_ffree;
+	__kernel_fsid_t f_fsid;
+	__u32 f_namelen;
+	__u32 f_frsize;
+	__u32 f_spare[5];
+};
+
+/*
+ * With EABI there is 4 bytes of padding added to this structure.
+ * Let's pack it so the padding goes away to simplify dual ABI support.
+ * Note that user space does NOT have to pack this structure.
+ */
+struct statfs64 {
+	__u32 f_type;
+	__u32 f_bsize;
+	__u64 f_blocks;
+	__u64 f_bfree;
+	__u64 f_bavail;
+	__u64 f_files;
+	__u64 f_ffree;
+	__kernel_fsid_t f_fsid;
+	__u32 f_namelen;
+	__u32 f_frsize;
+	__u32 f_spare[5];
+} __attribute__ ((packed,aligned(4)));
 
 #endif
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index d626e70..77430d6 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -15,10 +15,12 @@
 
 #include <linux/linkage.h>
 
-#if defined(__thumb__)
+#define __NR_OABI_SYSCALL_BASE	0x900000
+
+#if defined(__thumb__) || defined(__ARM_EABI__)
 #define __NR_SYSCALL_BASE	0
 #else
-#define __NR_SYSCALL_BASE	0x900000
+#define __NR_SYSCALL_BASE	__NR_OABI_SYSCALL_BASE
 #endif
 
 /*
@@ -373,13 +375,13 @@
 #define __sys1(x) __sys2(x)
 
 #ifndef __syscall
-#if defined(__thumb__)
-#define __syscall(name)					\
-	"push	{r7}\n\t"				\
-	"mov	r7, #" __sys1(__NR_##name) "\n\t"	\
-	"swi	0\n\t"					\
-	"pop	{r7}"
+#if defined(__thumb__) || defined(__ARM_EABI__)
+#define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name;
+#define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs
+#define __syscall(name) "swi\t0"
 #else
+#define __SYS_REG(name)
+#define __SYS_REG_LIST(regs...) regs
 #define __syscall(name) "swi\t" __sys1(__NR_##name) ""
 #endif
 #endif
@@ -395,33 +397,34 @@
 
 #define _syscall0(type,name)						\
 type name(void) {							\
+  __SYS_REG(name)							\
   register long __res_r0 __asm__("r0");					\
   long __res;								\
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	:								\
-	: "lr");							\
+	: __SYS_REG_LIST() );						\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
 
 #define _syscall1(type,name,type1,arg1) 				\
 type name(type1 arg1) { 						\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __res_r0 __asm__("r0");					\
   long __res;								\
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0)							\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0) ) );				\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2)			\
 type name(type1 arg1,type2 arg2) {					\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __r1 __asm__("r1") = (long)arg2;			\
   register long __res_r0 __asm__("r0");					\
@@ -429,8 +432,7 @@
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0),"r" (__r1) 					\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) );			\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
@@ -438,6 +440,7 @@
 
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
 type name(type1 arg1,type2 arg2,type3 arg3) {				\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __r1 __asm__("r1") = (long)arg2;			\
   register long __r2 __asm__("r2") = (long)arg3;			\
@@ -446,8 +449,7 @@
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0),"r" (__r1),"r" (__r2)				\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) );	\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
@@ -455,6 +457,7 @@
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {		\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __r1 __asm__("r1") = (long)arg2;			\
   register long __r2 __asm__("r2") = (long)arg3;			\
@@ -464,8 +467,7 @@
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3)			\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
@@ -473,6 +475,7 @@
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)	\
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {	\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __r1 __asm__("r1") = (long)arg2;			\
   register long __r2 __asm__("r2") = (long)arg3;			\
@@ -483,14 +486,15 @@
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4)	\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),		\
+			  "r" (__r3), "r" (__r4) ) );			\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
 
 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6)	\
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) {	\
+  __SYS_REG(name)							\
   register long __r0 __asm__("r0") = (long)arg1;			\
   register long __r1 __asm__("r1") = (long)arg2;			\
   register long __r2 __asm__("r2") = (long)arg3;			\
@@ -502,30 +506,33 @@
   __asm__ __volatile__ (						\
   __syscall(name)							\
 	: "=r" (__res_r0)						\
-	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5)		\
-	: "lr");							\
+	: __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),		\
+			  "r" (__r3), "r" (__r4), "r" (__r5) ) );	\
   __res = __res_r0;							\
   __syscall_return(type,__res);						\
 }
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_SOCKETCALL
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_SYS_SOCKETCALL
+#endif
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index fe0819f..88e6ca24 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -247,7 +247,7 @@
 static int test_bit(int nr, const volatile void * addr);
 #endif
 
-static inline int constant_test_bit(int nr, const volatile unsigned long *addr)
+static __always_inline int constant_test_bit(int nr, const volatile unsigned long *addr)
 {
 	return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
 }
diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h
index d973289..3cbbecd 100644
--- a/include/asm-i386/current.h
+++ b/include/asm-i386/current.h
@@ -5,7 +5,7 @@
 
 struct task_struct;
 
-static inline struct task_struct * get_current(void)
+static __always_inline struct task_struct * get_current(void)
 {
 	return current_thread_info()->task;
 }
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index 02c8f5d..bb5f88a 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -201,7 +201,7 @@
 return __res;
 }
 
-static inline void * __memcpy(void * to, const void * from, size_t n)
+static __always_inline void * __memcpy(void * to, const void * from, size_t n)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -223,7 +223,7 @@
  * This looks ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
-static inline void * __constant_memcpy(void * to, const void * from, size_t n)
+static __always_inline void * __constant_memcpy(void * to, const void * from, size_t n)
 {
 	long esi, edi;
 	if (!n) return to;
@@ -367,7 +367,7 @@
  * things 32 bits at a time even when we don't know the size of the
  * area at compile-time..
  */
-static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+static __always_inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -416,7 +416,7 @@
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
  */
-static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+static __always_inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
 {
 	switch (count) {
 		case 0:
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 89ab7e2..3f1337c 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -411,7 +411,7 @@
  * Returns number of bytes that could not be copied.
  * On success, this will be zero.
  */
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
@@ -432,7 +432,7 @@
 	return __copy_to_user_ll(to, from, n);
 }
 
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        might_sleep();
@@ -456,7 +456,7 @@
  * If some data could not be copied, this function will pad the copied
  * data to the requested size using zero bytes.
  */
-static inline unsigned long
+static __always_inline unsigned long
 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
 	if (__builtin_constant_p(n)) {
@@ -477,7 +477,7 @@
 	return __copy_from_user_ll(to, from, n);
 }
 
-static inline unsigned long
+static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        might_sleep();
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index a74b681..8c0fc22 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -68,10 +68,14 @@
 	unsigned long status;
 };
 
+#define	MAX_PARAM_RSE_SIZE	(0x60+0x60/0x3f)
 /* per-cpu kprobe control block */
 struct kprobe_ctlblk {
 	unsigned long kprobe_status;
 	struct pt_regs jprobe_saved_regs;
+	unsigned long jprobes_saved_stacked_regs[MAX_PARAM_RSE_SIZE];
+	unsigned long *bsp;
+	unsigned long cfm;
 	struct prev_kprobe prev_kprobe;
 };
 
@@ -118,5 +122,7 @@
 static inline void jprobe_return(void)
 {
 }
+extern void invalidate_stacked_regs(void);
+extern void flush_register_stack(void);
 
 #endif				/* _ASM_KPROBES_H */
diff --git a/include/asm-ia64/sn/ioc3.h b/include/asm-ia64/sn/ioc3.h
new file mode 100644
index 0000000..95ed6cc
--- /dev/null
+++ b/include/asm-ia64/sn/ioc3.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2005 Silicon Graphics, Inc.
+ */
+#ifndef IA64_SN_IOC3_H
+#define IA64_SN_IOC3_H
+
+/* serial port register map */
+struct ioc3_serialregs {
+	uint32_t sscr;
+	uint32_t stpir;
+	uint32_t stcir;
+	uint32_t srpir;
+	uint32_t srcir;
+	uint32_t srtr;
+	uint32_t shadow;
+};
+
+/* SUPERIO uart register map */
+struct ioc3_uartregs {
+	char iu_lcr;
+	union {
+		char iir;	/* read only */
+		char fcr;	/* write only */
+	} u3;
+	union {
+		char ier;	/* DLAB == 0 */
+		char dlm;	/* DLAB == 1 */
+	} u2;
+	union {
+		char rbr;	/* read only, DLAB == 0 */
+		char thr;	/* write only, DLAB == 0 */
+		char dll;	/* DLAB == 1 */
+	} u1;
+	char iu_scr;
+	char iu_msr;
+	char iu_lsr;
+	char iu_mcr;
+};
+
+#define iu_rbr u1.rbr
+#define iu_thr u1.thr
+#define iu_dll u1.dll
+#define iu_ier u2.ier
+#define iu_dlm u2.dlm
+#define iu_iir u3.iir
+#define iu_fcr u3.fcr
+
+struct ioc3_sioregs {
+	char fill[0x170];
+	struct ioc3_uartregs uartb;
+	struct ioc3_uartregs uarta;
+};
+
+/* PCI IO/mem space register map */
+struct ioc3 {
+	uint32_t pci_id;
+	uint32_t pci_scr;
+	uint32_t pci_rev;
+	uint32_t pci_lat;
+	uint32_t pci_addr;
+	uint32_t pci_err_addr_l;
+	uint32_t pci_err_addr_h;
+
+	uint32_t sio_ir;
+	/* these registers are read-only for general kernel code. To
+	 * modify them use the functions in ioc3.c
+	 */
+	uint32_t sio_ies;
+	uint32_t sio_iec;
+	uint32_t sio_cr;
+	uint32_t int_out;
+	uint32_t mcr;
+	uint32_t gpcr_s;
+	uint32_t gpcr_c;
+	uint32_t gpdr;
+	uint32_t gppr[9];
+	char fill[0x4c];
+
+	/* serial port registers */
+	uint32_t sbbr_h;
+	uint32_t sbbr_l;
+
+	struct ioc3_serialregs port_a;
+	struct ioc3_serialregs port_b;
+	char fill1[0x1ff10];
+	/* superio registers */
+	struct ioc3_sioregs sregs;
+};
+
+/* These don't exist on the ioc3 serial card... */
+#define eier	fill1[8]
+#define eisr	fill1[4]
+
+#define PCI_LAT			0xc	/* Latency Timer */
+#define PCI_SCR_DROP_MODE_EN	0x00008000 /* drop pios on parity err */
+#define UARTA_BASE		0x178
+#define UARTB_BASE		0x170
+
+
+/* bitmasks for serial RX status byte */
+#define RXSB_OVERRUN		0x01	/* char(s) lost */
+#define RXSB_PAR_ERR		0x02	/* parity error */
+#define RXSB_FRAME_ERR		0x04	/* framing error */
+#define RXSB_BREAK		0x08	/* break character */
+#define RXSB_CTS		0x10	/* state of CTS */
+#define RXSB_DCD		0x20	/* state of DCD */
+#define RXSB_MODEM_VALID	0x40	/* DCD, CTS and OVERRUN are valid */
+#define RXSB_DATA_VALID		0x80	/* FRAME_ERR PAR_ERR & BREAK valid */
+
+/* bitmasks for serial TX control byte */
+#define TXCB_INT_WHEN_DONE	0x20	/* interrupt after this byte is sent */
+#define TXCB_INVALID		0x00	/* byte is invalid */
+#define TXCB_VALID		0x40	/* byte is valid */
+#define TXCB_MCR		0x80	/* data<7:0> to modem cntrl register */
+#define TXCB_DELAY		0xc0	/* delay data<7:0> mSec */
+
+/* bitmasks for SBBR_L */
+#define SBBR_L_SIZE		0x00000001	/* 0 1KB rings, 1 4KB rings */
+
+/* bitmasks for SSCR_<A:B> */
+#define SSCR_RX_THRESHOLD	0x000001ff	/* hiwater mark */
+#define SSCR_TX_TIMER_BUSY	0x00010000	/* TX timer in progress */
+#define SSCR_HFC_EN		0x00020000	/* h/w flow cntrl enabled */
+#define SSCR_RX_RING_DCD	0x00040000	/* postRX record on delta-DCD */
+#define SSCR_RX_RING_CTS	0x00080000	/* postRX record on delta-CTS */
+#define SSCR_HIGH_SPD		0x00100000	/* 4X speed */
+#define SSCR_DIAG		0x00200000	/* bypass clock divider */
+#define SSCR_RX_DRAIN		0x08000000	/* drain RX buffer to memory */
+#define SSCR_DMA_EN		0x10000000	/* enable ring buffer DMA */
+#define SSCR_DMA_PAUSE		0x20000000	/* pause DMA */
+#define SSCR_PAUSE_STATE	0x40000000	/* set when PAUSE takes effect*/
+#define SSCR_RESET		0x80000000	/* reset DMA channels */
+
+/* all producer/comsumer pointers are the same bitfield */
+#define PROD_CONS_PTR_4K	0x00000ff8	/* for 4K buffers */
+#define PROD_CONS_PTR_1K	0x000003f8	/* for 1K buffers */
+#define PROD_CONS_PTR_OFF	3
+
+/* bitmasks for SRCIR_<A:B> */
+#define SRCIR_ARM		0x80000000	/* arm RX timer */
+
+/* bitmasks for SHADOW_<A:B> */
+#define SHADOW_DR		0x00000001	/* data ready */
+#define SHADOW_OE		0x00000002	/* overrun error */
+#define SHADOW_PE		0x00000004	/* parity error */
+#define SHADOW_FE		0x00000008	/* framing error */
+#define SHADOW_BI		0x00000010	/* break interrupt */
+#define SHADOW_THRE		0x00000020	/* transmit holding reg empty */
+#define SHADOW_TEMT		0x00000040	/* transmit shift reg empty */
+#define SHADOW_RFCE		0x00000080	/* char in RX fifo has error */
+#define SHADOW_DCTS		0x00010000	/* delta clear to send */
+#define SHADOW_DDCD		0x00080000	/* delta data carrier detect */
+#define SHADOW_CTS		0x00100000	/* clear to send */
+#define SHADOW_DCD		0x00800000	/* data carrier detect */
+#define SHADOW_DTR		0x01000000	/* data terminal ready */
+#define SHADOW_RTS		0x02000000	/* request to send */
+#define SHADOW_OUT1		0x04000000	/* 16550 OUT1 bit */
+#define SHADOW_OUT2		0x08000000	/* 16550 OUT2 bit */
+#define SHADOW_LOOP		0x10000000	/* loopback enabled */
+
+/* bitmasks for SRTR_<A:B> */
+#define SRTR_CNT		0x00000fff	/* reload value for RX timer */
+#define SRTR_CNT_VAL		0x0fff0000	/* current value of RX timer */
+#define SRTR_CNT_VAL_SHIFT	16
+#define SRTR_HZ			16000		/* SRTR clock frequency */
+
+/* bitmasks for SIO_IR, SIO_IEC and SIO_IES  */
+#define SIO_IR_SA_TX_MT		0x00000001	/* Serial port A TX empty */
+#define SIO_IR_SA_RX_FULL	0x00000002	/* port A RX buf full */
+#define SIO_IR_SA_RX_HIGH	0x00000004	/* port A RX hiwat */
+#define SIO_IR_SA_RX_TIMER	0x00000008	/* port A RX timeout */
+#define SIO_IR_SA_DELTA_DCD	0x00000010	/* port A delta DCD */
+#define SIO_IR_SA_DELTA_CTS	0x00000020	/* port A delta CTS */
+#define SIO_IR_SA_INT		0x00000040	/* port A pass-thru intr */
+#define SIO_IR_SA_TX_EXPLICIT	0x00000080	/* port A explicit TX thru */
+#define SIO_IR_SA_MEMERR	0x00000100	/* port A PCI error */
+#define SIO_IR_SB_TX_MT		0x00000200
+#define SIO_IR_SB_RX_FULL	0x00000400
+#define SIO_IR_SB_RX_HIGH	0x00000800
+#define SIO_IR_SB_RX_TIMER	0x00001000
+#define SIO_IR_SB_DELTA_DCD	0x00002000
+#define SIO_IR_SB_DELTA_CTS	0x00004000
+#define SIO_IR_SB_INT		0x00008000
+#define SIO_IR_SB_TX_EXPLICIT	0x00010000
+#define SIO_IR_SB_MEMERR	0x00020000
+#define SIO_IR_PP_INT		0x00040000	/* P port pass-thru intr */
+#define SIO_IR_PP_INTA		0x00080000	/* PP context A thru */
+#define SIO_IR_PP_INTB		0x00100000	/* PP context B thru */
+#define SIO_IR_PP_MEMERR	0x00200000	/* PP PCI error */
+#define SIO_IR_KBD_INT		0x00400000	/* kbd/mouse intr */
+#define SIO_IR_RT_INT		0x08000000	/* RT output pulse */
+#define SIO_IR_GEN_INT1		0x10000000	/* RT input pulse */
+#define SIO_IR_GEN_INT_SHIFT	28
+
+/* per device interrupt masks */
+#define SIO_IR_SA		(SIO_IR_SA_TX_MT | \
+				 SIO_IR_SA_RX_FULL | \
+				 SIO_IR_SA_RX_HIGH | \
+				 SIO_IR_SA_RX_TIMER | \
+				 SIO_IR_SA_DELTA_DCD | \
+				 SIO_IR_SA_DELTA_CTS | \
+				 SIO_IR_SA_INT | \
+				 SIO_IR_SA_TX_EXPLICIT | \
+				 SIO_IR_SA_MEMERR)
+
+#define SIO_IR_SB		(SIO_IR_SB_TX_MT | \
+				 SIO_IR_SB_RX_FULL | \
+				 SIO_IR_SB_RX_HIGH | \
+				 SIO_IR_SB_RX_TIMER | \
+				 SIO_IR_SB_DELTA_DCD | \
+				 SIO_IR_SB_DELTA_CTS | \
+				 SIO_IR_SB_INT | \
+				 SIO_IR_SB_TX_EXPLICIT | \
+				 SIO_IR_SB_MEMERR)
+
+#define SIO_IR_PP		(SIO_IR_PP_INT | SIO_IR_PP_INTA | \
+				 SIO_IR_PP_INTB | SIO_IR_PP_MEMERR)
+#define SIO_IR_RT		(SIO_IR_RT_INT | SIO_IR_GEN_INT1)
+
+/* bitmasks for SIO_CR */
+#define SIO_CR_CMD_PULSE_SHIFT 15
+#define SIO_CR_SER_A_BASE_SHIFT 1
+#define SIO_CR_SER_B_BASE_SHIFT 8
+#define SIO_CR_ARB_DIAG		0x00380000	/* cur !enet PCI requet (ro) */
+#define SIO_CR_ARB_DIAG_TXA	0x00000000
+#define SIO_CR_ARB_DIAG_RXA	0x00080000
+#define SIO_CR_ARB_DIAG_TXB	0x00100000
+#define SIO_CR_ARB_DIAG_RXB	0x00180000
+#define SIO_CR_ARB_DIAG_PP	0x00200000
+#define SIO_CR_ARB_DIAG_IDLE	0x00400000	/* 0 -> active request (ro) */
+
+/* defs for some of the generic I/O pins */
+#define GPCR_PHY_RESET		0x20	/* pin is output to PHY reset */
+#define GPCR_UARTB_MODESEL	0x40	/* pin is output to port B mode sel */
+#define GPCR_UARTA_MODESEL	0x80	/* pin is output to port A mode sel */
+
+#define GPPR_PHY_RESET_PIN	5	/* GIO pin controlling phy reset */
+#define GPPR_UARTB_MODESEL_PIN	6	/* GIO pin cntrling uartb modeselect */
+#define GPPR_UARTA_MODESEL_PIN	7	/* GIO pin cntrling uarta modeselect */
+
+#endif /* IA64_SN_IOC3_H */
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 2a8b0d9..8b9e10e 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -75,7 +75,8 @@
 #define  SN_SAL_IOIF_GET_HUBDEV_INFO		   0x02000055
 #define  SN_SAL_IOIF_GET_PCIBUS_INFO		   0x02000056
 #define  SN_SAL_IOIF_GET_PCIDEV_INFO		   0x02000057
-#define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST	   0x02000058
+#define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST	   0x02000058	// deprecated
+#define  SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST	   0x0200005a
 
 #define SN_SAL_HUB_ERROR_INTERRUPT		   0x02000060
 #define SN_SAL_BTE_RECOVER			   0x02000061
@@ -1100,7 +1101,7 @@
 	struct ia64_sal_retval rv;
 
 	rv.status = 0;
-	SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, 0, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, (u64)nasid, 0, 0, 0, 0, 0, 0);
 	if (rv.status == SALRET_NOT_IMPLEMENTED)
 		return 0;
 	return (int) rv.status;
diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h
index 49faf8f..203945a 100644
--- a/include/asm-ia64/sn/xp.h
+++ b/include/asm-ia64/sn/xp.h
@@ -227,7 +227,9 @@
 
 	xpcOpenCloseError,	/* 50: channel open/close protocol error */
 
-	xpcUnknownReason	/* 51: unknown reason -- must be last in list */
+	xpcDisconnected,	/* 51: channel disconnected (closed) */
+
+	xpcUnknownReason	/* 52: unknown reason -- must be last in list */
 };
 
 
diff --git a/arch/ia64/sn/kernel/xpc.h b/include/asm-ia64/sn/xpc.h
similarity index 98%
rename from arch/ia64/sn/kernel/xpc.h
rename to include/asm-ia64/sn/xpc.h
index 5483a9f..87e9cd58 100644
--- a/arch/ia64/sn/kernel/xpc.h
+++ b/include/asm-ia64/sn/xpc.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -11,8 +11,8 @@
  * Cross Partition Communication (XPC) structures and macros.
  */
 
-#ifndef _IA64_SN_KERNEL_XPC_H
-#define _IA64_SN_KERNEL_XPC_H
+#ifndef _ASM_IA64_SN_XPC_H
+#define _ASM_IA64_SN_XPC_H
 
 
 #include <linux/config.h>
@@ -663,6 +663,7 @@
 extern struct device *xpc_part;
 extern struct device *xpc_chan;
 extern int xpc_disengage_request_timelimit;
+extern int xpc_disengage_request_timedout;
 extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
 extern void xpc_dropped_IPI_check(struct xpc_partition *);
 extern void xpc_activate_partition(struct xpc_partition *);
@@ -707,7 +708,7 @@
 extern void xpc_deliver_msg(struct xpc_channel *);
 extern void xpc_disconnect_channel(const int, struct xpc_channel *,
 					enum xpc_retval, unsigned long *);
-extern void xpc_disconnecting_callout(struct xpc_channel *);
+extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval);
 extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval);
 extern void xpc_teardown_infrastructure(struct xpc_partition *);
 
@@ -1269,5 +1270,5 @@
 }
 
 
-#endif /* _IA64_SN_KERNEL_XPC_H */
+#endif /* _ASM_IA64_SN_XPC_H */
 
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 653bb7f..1d6518f 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -93,6 +93,7 @@
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
+#define TIF_DB_DISABLED		19	/* debug trap disabled for fsyscall */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
@@ -100,9 +101,10 @@
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
-#define _TIF_SIGDELAYED	(1 << TIF_SIGDELAYED)
+#define _TIF_SIGDELAYED		(1 << TIF_SIGDELAYED)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT		(1 << TIF_MCA_INIT)
+#define _TIF_DB_DISABLED	(1 << TIF_DB_DISABLED)
 
 /* "work to do on user-return" bits */
 #define TIF_ALLWORK_MASK	(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SIGDELAYED)
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 248f9ae..147a38d 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -36,7 +36,7 @@
 	int t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%2		# atomic_add_return\n\
 	add	%0,%1,%0\n"
 	PPC405_ERR77(0,%2)
@@ -72,7 +72,7 @@
 	int t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%2		# atomic_sub_return\n\
 	subf	%0,%1,%0\n"
 	PPC405_ERR77(0,%2)
@@ -106,7 +106,7 @@
 	int t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_inc_return\n\
 	addic	%0,%0,1\n"
 	PPC405_ERR77(0,%1)
@@ -150,7 +150,7 @@
 	int t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_dec_return\n\
 	addic	%0,%0,-1\n"
 	PPC405_ERR77(0,%1)
@@ -176,19 +176,19 @@
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)							 \
-({															 \
-	   int c, old;											 \
-	   c = atomic_read(v);									 \
-	   for (;;) {											  \
-			   if (unlikely(c == (u)))						 \
-					   break;								  \
-			   old = atomic_cmpxchg((v), c, c + (a));		  \
-			   if (likely(old == c))						   \
-					   break;								  \
-			   c = old;										\
-	   }													   \
-	   c != (u);											   \
+#define atomic_add_unless(v, a, u)			\
+({							\
+	int c, old;					\
+	c = atomic_read(v);				\
+	for (;;) {					\
+		if (unlikely(c == (u)))			\
+			break;				\
+		old = atomic_cmpxchg((v), c, c + (a));	\
+		if (likely(old == c))			\
+			break;				\
+		c = old;				\
+	}						\
+	c != (u);					\
 })
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
@@ -204,7 +204,7 @@
 	int t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
 	addic.	%0,%0,-1\n\
 	blt-	2f\n"
@@ -253,7 +253,7 @@
 	long t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%2		# atomic64_add_return\n\
 	add	%0,%1,%0\n\
 	stdcx.	%0,0,%2 \n\
@@ -287,7 +287,7 @@
 	long t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%2		# atomic64_sub_return\n\
 	subf	%0,%1,%0\n\
 	stdcx.	%0,0,%2 \n\
@@ -319,7 +319,7 @@
 	long t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%1		# atomic64_inc_return\n\
 	addic	%0,%0,1\n\
 	stdcx.	%0,0,%1 \n\
@@ -361,7 +361,7 @@
 	long t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%1		# atomic64_dec_return\n\
 	addic	%0,%0,-1\n\
 	stdcx.	%0,0,%1\n\
@@ -386,7 +386,7 @@
 	long t;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%1		# atomic64_dec_if_positive\n\
 	addic.	%0,%0,-1\n\
 	blt-	2f\n\
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index 1996eaa..bf6941a 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -112,7 +112,7 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:"	PPC_LLARX "%0,0,%3		# test_and_set_bit\n"
 	"or	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
@@ -134,7 +134,7 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:"	PPC_LLARX "%0,0,%3		# test_and_clear_bit\n"
 	"andc	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
@@ -156,7 +156,7 @@
 	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:"	PPC_LLARX "%0,0,%3		# test_and_change_bit\n"
 	"xor	%1,%0,%2 \n"
 	PPC405_ERR77(0,%3)
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index ef6ead3..6421054 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -19,6 +19,7 @@
 #define PPC_FEATURE_POWER5		0x00040000
 #define PPC_FEATURE_POWER5_PLUS		0x00020000
 #define PPC_FEATURE_CELL		0x00010000
+#define PPC_FEATURE_BOOKE		0x00008000
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
@@ -31,11 +32,11 @@
 typedef	void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
 
 enum powerpc_oprofile_type {
-	INVALID = 0,
-	RS64 = 1,
-	POWER4 = 2,
-	G4 = 3,
-	BOOKE = 4,
+	PPC_OPROFILE_INVALID = 0,
+	PPC_OPROFILE_RS64 = 1,
+	PPC_OPROFILE_POWER4 = 2,
+	PPC_OPROFILE_G4 = 3,
+	PPC_OPROFILE_BOOKE = 4,
 };
 
 struct cpu_spec {
@@ -64,6 +65,9 @@
 
 	/* Processor specific oprofile operations */
 	enum powerpc_oprofile_type oprofile_type;
+
+	/* Name of processor class, for the ELF AT_PLATFORM entry */
+	char		*platform;
 };
 
 extern struct cpu_spec		*cur_cpu_spec;
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h
index 45f2af6..94d228f 100644
--- a/include/asm-powerpc/elf.h
+++ b/include/asm-powerpc/elf.h
@@ -221,21 +221,19 @@
    instruction set this cpu supports.  This could be done in userspace,
    but it's not easy, and we've already done it here.  */
 # define ELF_HWCAP	(cur_cpu_spec->cpu_user_features)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.  */
+
+#define ELF_PLATFORM	(cur_cpu_spec->platform)
+
 #ifdef __powerpc64__
 # define ELF_PLAT_INIT(_r, load_addr)	do {	\
 	_r->gpr[2] = load_addr; 		\
 } while (0)
 #endif /* __powerpc64__ */
 
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.
-
-   For the moment, we have only optimizations for the Intel generations,
-   but that could change... */
-
-#define ELF_PLATFORM	(NULL)
-
 #ifdef __KERNEL__
 
 #ifdef __powerpc64__
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h
index f0319d5..39e85f3 100644
--- a/include/asm-powerpc/futex.h
+++ b/include/asm-powerpc/futex.h
@@ -11,7 +11,7 @@
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
   __asm__ __volatile ( \
-	SYNC_ON_SMP \
+	LWSYNC_ON_SMP \
 "1:	lwarx	%0,0,%2\n" \
 	insn \
 	PPC405_ERR77(0, %2) \
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index da7af5a..38ca9ad 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -6,7 +6,10 @@
 
 #define H_Success	0
 #define H_Busy		1	/* Hardware busy -- retry later */
+#define H_Closed	2	/* Resource closed */
 #define H_Constrained	4	/* Resource request constrained to max allowed */
+#define H_InProgress   14	/* Kind of like busy */
+#define H_Continue     18	/* Returned from H_Join on success */
 #define H_LongBusyStartRange   9900  /* Start of long busy range */
 #define H_LongBusyOrder1msec   9900  /* Long busy, hint that 1msec is a good time to retry */
 #define H_LongBusyOrder10msec  9901  /* Long busy, hint that 10msec is a good time to retry */
@@ -114,6 +117,8 @@
 #define H_REGISTER_VTERM	0x154
 #define H_FREE_VTERM		0x158
 #define H_POLL_PENDING	        0x1D8
+#define H_JOIN			0x298
+#define H_ENABLE_CRQ		0x2B0
 
 #ifndef __ASSEMBLY__
 
diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h
index ff82ea7..cd9f11f 100644
--- a/include/asm-powerpc/lppaca.h
+++ b/include/asm-powerpc/lppaca.h
@@ -29,7 +29,9 @@
 //----------------------------------------------------------------------------
 #include <asm/types.h>
 
-struct lppaca {
+/* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
+ * alignment is sufficient to prevent this */
+struct __attribute__((__aligned__(0x400))) lppaca {
 //=============================================================================
 // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
 // NOTE: The xDynXyz fields are fields that will be dynamically changed by
@@ -129,5 +131,7 @@
 	u8	pmc_save_area[256];	// PMC interrupt Area           x00-xFF
 };
 
+extern struct lppaca lppaca[];
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index a64b4d4..c9add8f 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -23,6 +23,7 @@
 
 register struct paca_struct *local_paca asm("r13");
 #define get_paca()	local_paca
+#define get_lppaca()	(get_paca()->lppaca_ptr)
 
 struct task_struct;
 
@@ -95,19 +96,6 @@
 	u64 saved_r1;			/* r1 save for RTAS calls */
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
 	u8 proc_enabled;		/* irq soft-enable flag */
-
-	/*
-	 * iSeries structure which the hypervisor knows about -
-	 * this structure should not cross a page boundary.
-	 * The vpa_init/register_vpa call is now known to fail if the
-	 * lppaca structure crosses a page boundary.
-	 * The lppaca is also used on POWER5 pSeries boxes.
-	 * The lppaca is 640 bytes long, and cannot readily change
-	 * since the hypervisor knows its layout, so a 1kB
-	 * alignment will suffice to ensure that it doesn't
-	 * cross a page boundary.
-	 */
-	struct lppaca lppaca __attribute__((__aligned__(0x400)));
 };
 
 extern struct paca_struct paca[];
diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h
index 0dc798d..ab8688d 100644
--- a/include/asm-powerpc/ppc_asm.h
+++ b/include/asm-powerpc/ppc_asm.h
@@ -156,52 +156,56 @@
 #endif
 
 /* 
- * LOADADDR( rn, name )
- *   loads the address of 'name' into 'rn'
+ * LOAD_REG_IMMEDIATE(rn, expr)
+ *   Loads the value of the constant expression 'expr' into register 'rn'
+ *   using immediate instructions only.  Use this when it's important not
+ *   to reference other data (i.e. on ppc64 when the TOC pointer is not
+ *   valid).
  *
- * LOADBASE( rn, name )
- *   loads the address (possibly without the low 16 bits) of 'name' into 'rn'
- *   suitable for base+disp addressing
+ * LOAD_REG_ADDR(rn, name)
+ *   Loads the address of label 'name' into register 'rn'.  Use this when
+ *   you don't particularly need immediate instructions only, but you need
+ *   the whole address in one register (e.g. it's a structure address and
+ *   you want to access various offsets within it).  On ppc32 this is
+ *   identical to LOAD_REG_IMMEDIATE.
+ *
+ * LOAD_REG_ADDRBASE(rn, name)
+ * ADDROFF(name)
+ *   LOAD_REG_ADDRBASE loads part of the address of label 'name' into
+ *   register 'rn'.  ADDROFF(name) returns the remainder of the address as
+ *   a constant expression.  ADDROFF(name) is a signed expression < 16 bits
+ *   in size, so is suitable for use directly as an offset in load and store
+ *   instructions.  Use this when loading/storing a single word or less as:
+ *      LOAD_REG_ADDRBASE(rX, name)
+ *      ld	rY,ADDROFF(name)(rX)
  */
 #ifdef __powerpc64__
-#define LOADADDR(rn,name) \
-	lis	rn,name##@highest;	\
-	ori	rn,rn,name##@higher;	\
-	rldicr	rn,rn,32,31;		\
-	oris	rn,rn,name##@h;		\
-	ori	rn,rn,name##@l
+#define LOAD_REG_IMMEDIATE(reg,expr)		\
+	lis     (reg),(expr)@highest;		\
+	ori     (reg),(reg),(expr)@higher;	\
+	rldicr  (reg),(reg),32,31;		\
+	oris    (reg),(reg),(expr)@h;		\
+	ori     (reg),(reg),(expr)@l;
 
-#define LOADBASE(rn,name)		\
-	ld	rn,name@got(r2)
+#define LOAD_REG_ADDR(reg,name)			\
+	ld	(reg),name@got(r2)
 
-#define OFF(name)	0
-
-#define SET_REG_TO_CONST(reg, value)	         	\
-	lis     reg,(((value)>>48)&0xFFFF);             \
-	ori     reg,reg,(((value)>>32)&0xFFFF);         \
-	rldicr  reg,reg,32,31;                          \
-	oris    reg,reg,(((value)>>16)&0xFFFF);         \
-	ori     reg,reg,((value)&0xFFFF);
-
-#define SET_REG_TO_LABEL(reg, label)	         	\
-	lis     reg,(label)@highest;                    \
-	ori     reg,reg,(label)@higher;                 \
-	rldicr  reg,reg,32,31;                          \
-	oris    reg,reg,(label)@h;                      \
-	ori     reg,reg,(label)@l;
+#define LOAD_REG_ADDRBASE(reg,name)	LOAD_REG_ADDR(reg,name)
+#define ADDROFF(name)			0
 
 /* offsets for stack frame layout */
 #define LRSAVE	16
 
 #else /* 32-bit */
-#define LOADADDR(rn,name) \
-	lis	rn,name@ha;	\
-	addi	rn,rn,name@l
 
-#define LOADBASE(rn,name)	\
-	lis	rn,name@ha
+#define LOAD_REG_IMMEDIATE(reg,expr)		\
+	lis	(reg),(expr)@ha;		\
+	addi	(reg),(reg),(expr)@l;
 
-#define OFF(name)	name@l
+#define LOAD_REG_ADDR(reg,name)		LOAD_REG_IMMEDIATE(reg, name)
+
+#define LOAD_REG_ADDRBASE(reg, name)	lis	(reg),name@ha
+#define ADDROFF(name)			name@l
 
 /* offsets for stack frame layout */
 #define LRSAVE	4
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 329e9bf..5b2bd4e 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -87,6 +87,7 @@
 	char	*full_name;
 
 	struct	property *properties;
+	struct  property *deadprops; /* removed properties */
 	struct	device_node *parent;
 	struct	device_node *child;
 	struct	device_node *sibling;
@@ -135,6 +136,9 @@
 extern struct device_node *of_get_parent(const struct device_node *node);
 extern struct device_node *of_get_next_child(const struct device_node *node,
 					     struct device_node *prev);
+extern struct property *of_find_property(struct device_node *np,
+					 const char *name,
+					 int *lenp);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 
@@ -164,6 +168,10 @@
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_remove_property(struct device_node *np, struct property *prop);
+extern int prom_update_property(struct device_node *np,
+				struct property *newprop,
+				struct property *oldprop);
 
 #ifdef CONFIG_PPC32
 /*
diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h
index 7549009..895cb6d 100644
--- a/include/asm-powerpc/spinlock.h
+++ b/include/asm-powerpc/spinlock.h
@@ -46,7 +46,7 @@
 
 	token = LOCK_TOKEN;
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%2		# __spin_trylock\n\
+"1:	lwarx		%0,0,%2\n\
 	cmpwi		0,%0,0\n\
 	bne-		2f\n\
 	stwcx.		%1,0,%2\n\
@@ -80,7 +80,7 @@
 
 #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
 /* We only yield to the hypervisor if we are in shared processor mode */
-#define SHARED_PROCESSOR (get_paca()->lppaca.shared_proc)
+#define SHARED_PROCESSOR (get_lppaca()->shared_proc)
 extern void __spin_yield(raw_spinlock_t *lock);
 extern void __rw_yield(raw_rwlock_t *lock);
 #else /* SPLPAR || ISERIES */
@@ -124,8 +124,8 @@
 
 static __inline__ void __raw_spin_unlock(raw_spinlock_t *lock)
 {
-	__asm__ __volatile__(SYNC_ON_SMP"	# __raw_spin_unlock"
-			     : : :"memory");
+	__asm__ __volatile__("# __raw_spin_unlock\n\t"
+				LWSYNC_ON_SMP: : :"memory");
 	lock->slock = 0;
 }
 
@@ -167,7 +167,7 @@
 	long tmp;
 
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%1		# read_trylock\n"
+"1:	lwarx		%0,0,%1\n"
 	__DO_SIGN_EXTEND
 "	addic.		%0,%0,1\n\
 	ble-		2f\n"
@@ -192,7 +192,7 @@
 
 	token = WRLOCK_TOKEN;
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%2	# write_trylock\n\
+"1:	lwarx		%0,0,%2\n\
 	cmpwi		0,%0,0\n\
 	bne-		2f\n"
 	PPC405_ERR77(0,%1)
@@ -249,8 +249,9 @@
 	long tmp;
 
 	__asm__ __volatile__(
-	"eieio				# read_unlock\n\
-1:	lwarx		%0,0,%1\n\
+	"# read_unlock\n\t"
+	LWSYNC_ON_SMP
+"1:	lwarx		%0,0,%1\n\
 	addic		%0,%0,-1\n"
 	PPC405_ERR77(0,%1)
 "	stwcx.		%0,0,%1\n\
@@ -262,8 +263,8 @@
 
 static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
 {
-	__asm__ __volatile__(SYNC_ON_SMP"	# write_unlock"
-			     : : :"memory");
+	__asm__ __volatile__("# write_unlock\n\t"
+				LWSYNC_ON_SMP: : :"memory");
 	rw->lock = 0;
 }
 
diff --git a/include/asm-powerpc/synch.h b/include/asm-powerpc/synch.h
index 794870a..c90d9d9 100644
--- a/include/asm-powerpc/synch.h
+++ b/include/asm-powerpc/synch.h
@@ -2,6 +2,8 @@
 #define _ASM_POWERPC_SYNCH_H 
 #ifdef __KERNEL__
 
+#include <linux/stringify.h>
+
 #ifdef __powerpc64__
 #define __SUBARCH_HAS_LWSYNC
 #endif
@@ -12,20 +14,12 @@
 #    define LWSYNC	sync
 #endif
 
-
-/*
- * Arguably the bitops and *xchg operations don't imply any memory barrier
- * or SMP ordering, but in fact a lot of drivers expect them to imply
- * both, since they do on x86 cpus.
- */
 #ifdef CONFIG_SMP
-#define EIEIO_ON_SMP	"eieio\n"
 #define ISYNC_ON_SMP	"\n\tisync"
-#define SYNC_ON_SMP	__stringify(LWSYNC) "\n"
+#define LWSYNC_ON_SMP	__stringify(LWSYNC) "\n"
 #else
-#define EIEIO_ON_SMP
 #define ISYNC_ON_SMP
-#define SYNC_ON_SMP
+#define LWSYNC_ON_SMP
 #endif
 
 static inline void eieio(void)
@@ -38,14 +32,5 @@
 	__asm__ __volatile__ ("isync" : : : "memory");
 }
 
-#ifdef CONFIG_SMP
-#define eieio_on_smp()	eieio()
-#define isync_on_smp()	isync()
-#else
-#define eieio_on_smp()	__asm__ __volatile__("": : :"memory")
-#define isync_on_smp()	__asm__ __volatile__("": : :"memory")
-#endif
-
 #endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_SYNCH_H */
-
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 9b822af..d9bf536 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -212,7 +212,7 @@
 	unsigned long prev;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%2 \n"
 	PPC405_ERR77(0,%2)
 "	stwcx.	%3,0,%2 \n\
@@ -232,7 +232,7 @@
 	unsigned long prev;
 
 	__asm__ __volatile__(
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%2 \n"
 	PPC405_ERR77(0,%2)
 "	stdcx.	%3,0,%2 \n\
@@ -287,7 +287,7 @@
 	unsigned int prev;
 
 	__asm__ __volatile__ (
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
 	cmpw	0,%0,%3\n\
 	bne-	2f\n"
@@ -311,7 +311,7 @@
 	unsigned long prev;
 
 	__asm__ __volatile__ (
-	EIEIO_ON_SMP
+	LWSYNC_ON_SMP
 "1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
 	cmpd	0,%0,%3\n\
 	bne-	2f\n\
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index d9b86a1..baddc9a 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -175,11 +175,10 @@
 	set_dec_cpu6(val);
 #else
 #ifdef CONFIG_PPC_ISERIES
-	struct paca_struct *lpaca = get_paca();
 	int cur_dec;
 
-	if (lpaca->lppaca.shared_proc) {
-		lpaca->lppaca.virtual_decr = val;
+	if (get_lppaca()->shared_proc) {
+		get_lppaca()->virtual_decr = val;
 		cur_dec = get_dec();
 		if (cur_dec > val)
 			HvCall_setVirtualDecr();
diff --git a/include/asm-s390/s390_rdev.h b/include/asm-s390/s390_rdev.h
index 3ad78f2..6fa2044 100644
--- a/include/asm-s390/s390_rdev.h
+++ b/include/asm-s390/s390_rdev.h
@@ -2,7 +2,7 @@
  *  include/asm-s390/ccwdev.h
  *
  *    Copyright (C) 2002,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Cornelia Huck <cohuck@de.ibm.com>
+ *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *               Carsten Otte  <cotte@de.ibm.com>
  *
  *  Interface for s390 root device
diff --git a/include/asm-s390/sigcontext.h b/include/asm-s390/sigcontext.h
index 8035453..aeb6e0b 100644
--- a/include/asm-s390/sigcontext.h
+++ b/include/asm-s390/sigcontext.h
@@ -8,6 +8,8 @@
 #ifndef _ASM_S390_SIGCONTEXT_H
 #define _ASM_S390_SIGCONTEXT_H
 
+#include <linux/compiler.h>
+
 #define __NUM_GPRS 16
 #define __NUM_FPRS 16
 #define __NUM_ACRS 16
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index c7c3a9a..b2e65e8 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -115,13 +115,14 @@
 }
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_user_vtime(struct task_struct *);
+extern void account_vtime(struct task_struct *);
+extern void account_tick_vtime(struct task_struct *);
 extern void account_system_vtime(struct task_struct *);
 #endif
 
 #define finish_arch_switch(prev) do {					     \
 	set_fs(current->thread.mm_segment);				     \
-	account_system_vtime(prev);					     \
+	account_vtime(prev);						     \
 } while (0)
 
 #define nop() __asm__ __volatile__ ("nop")
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index a582cfc..7b286bd 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -76,7 +76,7 @@
  * directly without translation, we catch the bug with a NULL-deference
  * kernel oops. Illegal ranges of incoming indices are caught too.
  */
-static inline unsigned long fix_to_virt(const unsigned int idx)
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
 {
 	/*
 	 * this branch gets completely eliminated after inlining,
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index 2892c4b..bddffcb 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -244,7 +244,7 @@
 extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len); 
 extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len); 
 
-static inline int __copy_from_user(void *dst, const void __user *src, unsigned size) 
+static __always_inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
 { 
        int ret = 0;
 	if (!__builtin_constant_p(size))
@@ -273,7 +273,7 @@
 	}
 }	
 
-static inline int __copy_to_user(void __user *dst, const void *src, unsigned size) 
+static __always_inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
 { 
        int ret = 0;
 	if (!__builtin_constant_p(size))
@@ -305,7 +305,7 @@
 }	
 
 
-static inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size) 
+static __always_inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 { 
        int ret = 0;
 	if (!__builtin_constant_p(size))
diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h
index 9a7b374..d2bc0d6 100644
--- a/include/linux/auxvec.h
+++ b/include/linux/auxvec.h
@@ -26,6 +26,6 @@
 
 #define AT_SECURE 23   /* secure mode boolean */
 
-#define AT_VECTOR_SIZE  42 /* Size of auxiliary table.  */
+#define AT_VECTOR_SIZE  44 /* Size of auxiliary table.  */
 
 #endif /* _LINUX_AUXVEC_H */
diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
index 4209082..1698b84 100644
--- a/include/linux/compiler-gcc3.h
+++ b/include/linux/compiler-gcc3.h
@@ -13,3 +13,4 @@
 #define __must_check		__attribute__((warn_unused_result))
 #endif
 
+#define __always_inline		inline __attribute__((always_inline))
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index e913e9b..6f5cc6f 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -3,7 +3,16 @@
 /* These definitions are for GCC v4.x.  */
 #include <linux/compiler-gcc.h>
 
+#ifdef CONFIG_FORCED_INLINING
+# undef inline
+# undef __inline__
+# undef __inline
+# define inline			inline		__attribute__((always_inline))
+# define __inline__		__inline__	__attribute__((always_inline))
+# define __inline		__inline	__attribute__((always_inline))
+#endif
+
 #define __attribute_used__	__attribute__((__used__))
 #define __must_check 		__attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
-
+#define __always_inline		inline __attribute__((always_inline))
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index c472f97..3bc6069 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -48,6 +48,9 @@
 extern struct file_operations proc_cpuset_operations;
 extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
 
+extern void cpuset_lock(void);
+extern void cpuset_unlock(void);
+
 #else /* !CONFIG_CPUSETS */
 
 static inline int cpuset_init_early(void) { return 0; }
@@ -93,6 +96,9 @@
 	return buffer;
 }
 
+static inline void cpuset_lock(void) {}
+static inline void cpuset_unlock(void) {}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
diff --git a/include/linux/device.h b/include/linux/device.h
index 0cdee78e..58df18d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -49,6 +49,9 @@
 	int		(*match)(struct device * dev, struct device_driver * drv);
 	int		(*uevent)(struct device *dev, char **envp,
 				  int num_envp, char *buffer, int buffer_size);
+	int		(*probe)(struct device * dev);
+	int		(*remove)(struct device * dev);
+	void		(*shutdown)(struct device * dev);
 	int		(*suspend)(struct device * dev, pm_message_t state);
 	int		(*resume)(struct device * dev);
 };
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a973be2..2cb19e6 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -608,15 +608,15 @@
 	int (*fb_sync)(struct fb_info *info);
 
 	/* perform fb specific ioctl (optional) */
-	int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
-			unsigned long arg, struct fb_info *info);
+	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
+			unsigned long arg);
 
 	/* Handle 32bit compat ioctl (optional) */
-	long (*fb_compat_ioctl)(struct file *f, unsigned cmd, unsigned long arg,
-			       struct fb_info *info);
+	int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
+			unsigned long arg);
 
 	/* perform fb specific mmap */
-	int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
 
 	/* save current hardware state */
 	void (*fb_save_state)(struct fb_info *info);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d1e370d..552cedf 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1383,6 +1383,12 @@
 extern int unregister_chrdev(unsigned int, const char *);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern int chrdev_open(struct inode *, struct file *);
+extern int get_chrdev_list(char *);
+extern void *acquire_chrdev_list(void);
+extern int count_chrdev_list(void);
+extern void *get_next_chrdev(void *);
+extern int get_chrdev_info(void *, int *, char **);
+extern void release_chrdev_list(void *);
 
 /* fs/block_dev.c */
 #define BDEVNAME_SIZE	32	/* Largest string for a blockdev identifier */
@@ -1391,6 +1397,11 @@
 extern struct block_device *lookup_bdev(const char *);
 extern struct block_device *open_bdev_excl(const char *, int, void *);
 extern void close_bdev_excl(struct block_device *);
+extern void *acquire_blkdev_list(void);
+extern int count_blkdev_list(void);
+extern void *get_next_blkdev(void *);
+extern int get_blkdev_info(void *, int *, char **);
+extern void release_blkdev_list(void *);
 
 extern void init_special_inode(struct inode *, umode_t, dev_t);
 
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 71d2b8a..eab5370 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -93,10 +93,6 @@
 struct task_struct;
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
-static inline void account_user_vtime(struct task_struct *tsk)
-{
-}
-
 static inline void account_system_vtime(struct task_struct *tsk)
 {
 }
diff --git a/include/linux/ide.h b/include/linux/ide.h
index f2e1b5b..110b3cf 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -983,8 +983,13 @@
 	ide_startstop_t	(*abort)(ide_drive_t *, struct request *rq);
 	ide_proc_entry_t	*proc;
 	struct device_driver	gen_driver;
+	int		(*probe)(ide_drive_t *);
+	void		(*remove)(ide_drive_t *);
+	void		(*shutdown)(ide_drive_t *);
 } ide_driver_t;
 
+#define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
+
 int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
 
 /*
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
new file mode 100644
index 0000000..e7906a7
--- /dev/null
+++ b/include/linux/ioc3.h
@@ -0,0 +1,93 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
+ */
+
+#ifndef _LINUX_IOC3_H
+#define _LINUX_IOC3_H
+
+#include <asm/sn/ioc3.h>
+
+#define IOC3_MAX_SUBMODULES	32
+
+#define IOC3_CLASS_NONE		0
+#define IOC3_CLASS_BASE_IP27	1
+#define IOC3_CLASS_BASE_IP30	2
+#define IOC3_CLASS_MENET_123	3
+#define IOC3_CLASS_MENET_4	4
+#define IOC3_CLASS_CADDUO	5
+#define IOC3_CLASS_SERIAL	6
+
+/* One of these per IOC3 */
+struct ioc3_driver_data {
+	struct list_head list;
+	int id;				/* IOC3 sequence number */
+	/* PCI mapping */
+	unsigned long pma;		/* physical address */
+	struct __iomem ioc3 *vma;	/* pointer to registers */
+	struct pci_dev *pdev;		/* PCI device */
+	/* IRQ stuff */
+	int dual_irq;			/* set if separate IRQs are used */
+	int irq_io, irq_eth;		/* IRQ numbers */
+	/* GPIO magic */
+	spinlock_t gpio_lock;
+	unsigned int gpdr_shadow;
+	/* NIC identifiers */
+	char nic_part[32];
+	char nic_serial[16];
+	char nic_mac[6];
+	/* submodule set */
+	int class;
+	void *data[IOC3_MAX_SUBMODULES];	/* for submodule use */
+	int active[IOC3_MAX_SUBMODULES];	/* set if probe succeeds */
+	/* is_ir_lock must be held while
+	 * modifying sio_ie values, so
+	 * we can be sure that sio_ie is
+	 * not changing when we read it
+	 * along with sio_ir.
+	 */
+	spinlock_t ir_lock;	/* SIO_IE[SC] mod lock */
+};
+
+/* One per submodule */
+struct ioc3_submodule {
+	char *name;		/* descriptive submodule name */
+	struct module *owner;	/* owning kernel module */
+	int ethernet;		/* set for ethernet drivers */
+	int (*probe) (struct ioc3_submodule *, struct ioc3_driver_data *);
+	int (*remove) (struct ioc3_submodule *, struct ioc3_driver_data *);
+	int id;			/* assigned by IOC3, index for the "data" array */
+	/* IRQ stuff */
+	unsigned int irq_mask;	/* IOC3 IRQ mask, leave clear for Ethernet */
+	int reset_mask;		/* non-zero if you want the ioc3.c module to reset interrupts */
+	int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *);
+	/* private submodule data */
+	void *data;		/* assigned by submodule */
+};
+
+/**********************************
+ * Functions needed by submodules *
+ **********************************/
+
+#define IOC3_W_IES		0
+#define IOC3_W_IEC		1
+
+/* registers a submodule for all existing and future IOC3 chips */
+extern int ioc3_register_submodule(struct ioc3_submodule *);
+/* unregisters a submodule */
+extern void ioc3_unregister_submodule(struct ioc3_submodule *);
+/* enables IRQs indicated by irq_mask for a specified IOC3 chip */
+extern void ioc3_enable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* ackowledges specified IRQs */
+extern void ioc3_ack(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* disables IRQs indicated by irq_mask for a specified IOC3 chip */
+extern void ioc3_disable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* atomically sets GPCR bits */
+extern void ioc3_gpcr_set(struct ioc3_driver_data *, unsigned int);
+/* general ireg writer */
+extern void ioc3_write_ireg(struct ioc3_driver_data *idd, uint32_t value, int reg);
+
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index e6ee2d9..323924e 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -216,6 +216,7 @@
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
+#define NIPQUAD_FMT "%u.%u.%u.%u"
 
 #define NIP6(addr) \
 	ntohs((addr).s6_addr16[0]), \
@@ -226,6 +227,7 @@
 	ntohs((addr).s6_addr16[5]), \
 	ntohs((addr).s6_addr16[6]), \
 	ntohs((addr).s6_addr16[7])
+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
 
 #if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index c7ac77e..d6a53ed 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -132,12 +132,8 @@
 	spinlock_t lock;
 };
 
-static inline void mpol_shared_policy_init(struct shared_policy *info)
-{
-	info->root = RB_ROOT;
-	spin_lock_init(&info->lock);
-}
-
+void mpol_shared_policy_init(struct shared_policy *info, int policy,
+				nodemask_t *nodes);
 int mpol_set_shared_policy(struct shared_policy *info,
 				struct vm_area_struct *vma,
 				struct mempolicy *new);
@@ -211,7 +207,8 @@
 	return -EINVAL;
 }
 
-static inline void mpol_shared_policy_init(struct shared_policy *info)
+static inline void mpol_shared_policy_init(struct shared_policy *info,
+					int policy, nodemask_t *nodes)
 {
 }
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index c643016..85854b8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -512,7 +512,7 @@
 extern struct page *mem_map;
 #endif
 
-static inline void *lowmem_page_address(struct page *page)
+static __always_inline void *lowmem_page_address(struct page *page)
 {
 	return __va(page_to_pfn(page) << PAGE_SHIFT);
 }
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 7297e43..e013425 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -201,34 +201,6 @@
 	return container_of(inode, struct ncp_inode_info, vfs_inode);
 }
 
-#ifdef DEBUG_NCP_MALLOC
-
-#include <linux/slab.h>
-
-extern int ncp_malloced;
-extern int ncp_current_malloced;
-
-static inline void *
- ncp_kmalloc(unsigned int size, int priority)
-{
-	ncp_malloced += 1;
-	ncp_current_malloced += 1;
-	return kmalloc(size, priority);
-}
-
-static inline void ncp_kfree_s(void *obj, int size)
-{
-	ncp_current_malloced -= 1;
-	kfree(obj);
-}
-
-#else				/* DEBUG_NCP_MALLOC */
-
-#define ncp_kmalloc(s,p) kmalloc(s,p)
-#define ncp_kfree_s(o,s) kfree(o)
-
-#endif				/* DEBUG_NCP_MALLOC */
-
 /* linux/fs/ncpfs/inode.c */
 int ncp_notify_change(struct dentry *, struct iattr *);
 struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 6d39b51..3ff88c8 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -154,6 +154,9 @@
 	unsigned int expect_delete;
 };
 
+/* call to create an explicit dependency on nf_conntrack. */
+extern void need_conntrack(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
new file mode 100644
index 0000000..472f048
--- /dev/null
+++ b/include/linux/netfilter/x_tables.h
@@ -0,0 +1,224 @@
+#ifndef _X_TABLES_H
+#define _X_TABLES_H
+
+#define XT_FUNCTION_MAXNAMELEN 30
+#define XT_TABLE_MAXNAMELEN 32
+
+/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
+ * kernel supports, if >= revision. */
+struct xt_get_revision
+{
+	char name[XT_FUNCTION_MAXNAMELEN-1];
+
+	u_int8_t revision;
+};
+
+/* CONTINUE verdict for targets */
+#define XT_CONTINUE 0xFFFFFFFF
+
+/* For standard target */
+#define XT_RETURN (-NF_REPEAT - 1)
+
+#define XT_ALIGN(s) (((s) + (__alignof__(void *)-1)) & ~(__alignof__(void *)-1))
+
+/* Standard return verdict, or do jump. */
+#define XT_STANDARD_TARGET ""
+/* Error verdict. */
+#define XT_ERROR_TARGET "ERROR"
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls. */
+#define XT_BASE_CTL		64	/* base for firewall socket options */
+
+#define XT_SO_SET_REPLACE	(XT_BASE_CTL)
+#define XT_SO_SET_ADD_COUNTERS	(XT_BASE_CTL + 1)
+#define XT_SO_SET_MAX		XT_SO_SET_ADD_COUNTERS
+
+#define XT_SO_GET_INFO			(XT_BASE_CTL)
+#define XT_SO_GET_ENTRIES		(XT_BASE_CTL + 1)
+#define XT_SO_GET_REVISION_MATCH	(XT_BASE_CTL + 2)
+#define XT_SO_GET_REVISION_TARGET	(XT_BASE_CTL + 3)
+#define XT_SO_GET_MAX			XT_SO_GET_REVISION_TARGET
+
+#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
+#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
+
+struct xt_counters
+{
+	u_int64_t pcnt, bcnt;			/* Packet and byte counters */
+};
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+struct xt_counters_info
+{
+	/* Which table. */
+	char name[XT_TABLE_MAXNAMELEN];
+
+	unsigned int num_counters;
+
+	/* The counters (actually `number' of these). */
+	struct xt_counters counters[0];
+};
+
+#define XT_INV_PROTO		0x40	/* Invert the sense of PROTO. */
+
+#ifdef __KERNEL__
+
+#include <linux/netdevice.h>
+
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+#include <linux/netfilter_ipv4/listhelp.h>
+
+struct xt_match
+{
+	struct list_head list;
+
+	const char name[XT_FUNCTION_MAXNAMELEN-1];
+
+	u_int8_t revision;
+
+	/* Return true or false: return FALSE and set *hotdrop = 1 to
+           force immediate packet drop. */
+	/* Arguments changed since 2.6.9, as this must now handle
+	   non-linear skb, using skb_header_pointer and
+	   skb_ip_make_writable. */
+	int (*match)(const struct sk_buff *skb,
+		     const struct net_device *in,
+		     const struct net_device *out,
+		     const void *matchinfo,
+		     int offset,
+		     unsigned int protoff,
+		     int *hotdrop);
+
+	/* Called when user tries to insert an entry of this type. */
+	/* Should return true or false. */
+	int (*checkentry)(const char *tablename,
+			  const void *ip,
+			  void *matchinfo,
+			  unsigned int matchinfosize,
+			  unsigned int hook_mask);
+
+	/* Called when entry of this type deleted. */
+	void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
+};
+
+/* Registration hooks for targets. */
+struct xt_target
+{
+	struct list_head list;
+
+	const char name[XT_FUNCTION_MAXNAMELEN-1];
+
+	u_int8_t revision;
+
+	/* Returns verdict. Argument order changed since 2.6.9, as this
+	   must now handle non-linear skbs, using skb_copy_bits and
+	   skb_ip_make_writable. */
+	unsigned int (*target)(struct sk_buff **pskb,
+			       const struct net_device *in,
+			       const struct net_device *out,
+			       unsigned int hooknum,
+			       const void *targinfo,
+			       void *userdata);
+
+	/* Called when user tries to insert an entry of this type:
+           hook_mask is a bitmask of hooks from which it can be
+           called. */
+	/* Should return true or false. */
+	int (*checkentry)(const char *tablename,
+			  const void *entry,
+			  void *targinfo,
+			  unsigned int targinfosize,
+			  unsigned int hook_mask);
+
+	/* Called when entry of this type deleted. */
+	void (*destroy)(void *targinfo, unsigned int targinfosize);
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
+};
+
+/* Furniture shopping... */
+struct xt_table
+{
+	struct list_head list;
+
+	/* A unique name... */
+	char name[XT_TABLE_MAXNAMELEN];
+
+	/* What hooks you will enter on */
+	unsigned int valid_hooks;
+
+	/* Lock for the curtain */
+	rwlock_t lock;
+
+	/* Man behind the curtain... */
+	//struct ip6t_table_info *private;
+	void *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
+
+	int af;		/* address/protocol family */
+};
+
+#include <linux/netfilter_ipv4.h>
+
+/* The table itself */
+struct xt_table_info
+{
+	/* Size per table */
+	unsigned int size;
+	/* Number of entries: FIXME. --RR */
+	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
+
+	/* Entry points and underflows */
+	unsigned int hook_entry[NF_IP_NUMHOOKS];
+	unsigned int underflow[NF_IP_NUMHOOKS];
+
+	/* ipt_entry tables: one per CPU */
+	char *entries[NR_CPUS];
+};
+
+extern int xt_register_target(int af, struct xt_target *target);
+extern void xt_unregister_target(int af, struct xt_target *target);
+extern int xt_register_match(int af, struct xt_match *target);
+extern void xt_unregister_match(int af, struct xt_match *target);
+
+extern int xt_register_table(struct xt_table *table,
+			     struct xt_table_info *bootstrap,
+			     struct xt_table_info *newinfo);
+extern void *xt_unregister_table(struct xt_table *table);
+
+extern struct xt_table_info *xt_replace_table(struct xt_table *table,
+					      unsigned int num_counters,
+					      struct xt_table_info *newinfo,
+					      int *error);
+
+extern struct xt_match *xt_find_match(int af, const char *name, u8 revision);
+extern struct xt_target *xt_find_target(int af, const char *name, u8 revision);
+extern struct xt_target *xt_request_find_target(int af, const char *name, 
+						u8 revision);
+extern int xt_find_revision(int af, const char *name, u8 revision, int target,
+			    int *err);
+
+extern struct xt_table *xt_find_table_lock(int af, const char *name);
+extern void xt_table_unlock(struct xt_table *t);
+
+extern int xt_proto_init(int af);
+extern void xt_proto_fini(int af);
+
+extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
+extern void xt_free_table_info(struct xt_table_info *info);
+
+#endif /* __KERNEL__ */
+
+#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter/xt_CLASSIFY.h b/include/linux/netfilter/xt_CLASSIFY.h
new file mode 100644
index 0000000..5811135
--- /dev/null
+++ b/include/linux/netfilter/xt_CLASSIFY.h
@@ -0,0 +1,8 @@
+#ifndef _XT_CLASSIFY_H
+#define _XT_CLASSIFY_H
+
+struct xt_classify_target_info {
+	u_int32_t priority;
+};
+
+#endif /*_XT_CLASSIFY_H */
diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/linux/netfilter/xt_CONNMARK.h
new file mode 100644
index 0000000..9f74468
--- /dev/null
+++ b/include/linux/netfilter/xt_CONNMARK.h
@@ -0,0 +1,25 @@
+#ifndef _XT_CONNMARK_H_target
+#define _XT_CONNMARK_H_target
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+enum {
+	XT_CONNMARK_SET = 0,
+	XT_CONNMARK_SAVE,
+	XT_CONNMARK_RESTORE
+};
+
+struct xt_connmark_target_info {
+	unsigned long mark;
+	unsigned long mask;
+	u_int8_t mode;
+};
+
+#endif /*_XT_CONNMARK_H_target*/
diff --git a/include/linux/netfilter/xt_MARK.h b/include/linux/netfilter/xt_MARK.h
new file mode 100644
index 0000000..b021e93
--- /dev/null
+++ b/include/linux/netfilter/xt_MARK.h
@@ -0,0 +1,21 @@
+#ifndef _XT_MARK_H_target
+#define _XT_MARK_H_target
+
+/* Version 0 */
+struct xt_mark_target_info {
+	unsigned long mark;
+};
+
+/* Version 1 */
+enum {
+	XT_MARK_SET=0,
+	XT_MARK_AND,
+	XT_MARK_OR,
+};
+
+struct xt_mark_target_info_v1 {
+	unsigned long mark;
+	u_int8_t mode;
+};
+
+#endif /*_XT_MARK_H_target */
diff --git a/include/linux/netfilter/xt_NFQUEUE.h b/include/linux/netfilter/xt_NFQUEUE.h
new file mode 100644
index 0000000..9a9af79f
--- /dev/null
+++ b/include/linux/netfilter/xt_NFQUEUE.h
@@ -0,0 +1,16 @@
+/* iptables module for using NFQUEUE mechanism
+ *
+ * (C) 2005 Harald Welte <laforge@netfilter.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+*/
+#ifndef _XT_NFQ_TARGET_H
+#define _XT_NFQ_TARGET_H
+
+/* target info */
+struct xt_NFQ_info {
+	u_int16_t queuenum;
+};
+
+#endif /* _XT_NFQ_TARGET_H */
diff --git a/include/linux/netfilter/xt_comment.h b/include/linux/netfilter/xt_comment.h
new file mode 100644
index 0000000..eacfedc
--- /dev/null
+++ b/include/linux/netfilter/xt_comment.h
@@ -0,0 +1,10 @@
+#ifndef _XT_COMMENT_H
+#define _XT_COMMENT_H
+
+#define XT_MAX_COMMENT_LEN 256
+
+struct xt_comment_info {
+	unsigned char comment[XT_MAX_COMMENT_LEN];
+};
+
+#endif /* XT_COMMENT_H */
diff --git a/include/linux/netfilter/xt_connbytes.h b/include/linux/netfilter/xt_connbytes.h
new file mode 100644
index 0000000..c022c98
--- /dev/null
+++ b/include/linux/netfilter/xt_connbytes.h
@@ -0,0 +1,25 @@
+#ifndef _XT_CONNBYTES_H
+#define _XT_CONNBYTES_H
+
+enum xt_connbytes_what {
+	XT_CONNBYTES_PKTS,
+	XT_CONNBYTES_BYTES,
+	XT_CONNBYTES_AVGPKT,
+};
+
+enum xt_connbytes_direction {
+	XT_CONNBYTES_DIR_ORIGINAL,
+	XT_CONNBYTES_DIR_REPLY,
+	XT_CONNBYTES_DIR_BOTH,
+};
+
+struct xt_connbytes_info
+{
+	struct {
+		aligned_u64 from;	/* count to be matched */
+		aligned_u64 to;		/* count to be matched */
+	} count;
+	u_int8_t what;		/* ipt_connbytes_what */
+	u_int8_t direction;	/* ipt_connbytes_direction */
+};
+#endif
diff --git a/include/linux/netfilter/xt_connmark.h b/include/linux/netfilter/xt_connmark.h
new file mode 100644
index 0000000..c592f6a
--- /dev/null
+++ b/include/linux/netfilter/xt_connmark.h
@@ -0,0 +1,18 @@
+#ifndef _XT_CONNMARK_H
+#define _XT_CONNMARK_H
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+struct xt_connmark_info {
+	unsigned long mark, mask;
+	u_int8_t invert;
+};
+
+#endif /*_XT_CONNMARK_H*/
diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h
new file mode 100644
index 0000000..34f63cf
--- /dev/null
+++ b/include/linux/netfilter/xt_conntrack.h
@@ -0,0 +1,63 @@
+/* Header file for kernel module to match connection tracking information.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+
+#ifndef _XT_CONNTRACK_H
+#define _XT_CONNTRACK_H
+
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <linux/in.h>
+
+#define XT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define XT_CONNTRACK_STATE_INVALID (1 << 0)
+
+#define XT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+#define XT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
+#define XT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+
+/* flags, invflags: */
+#define XT_CONNTRACK_STATE	0x01
+#define XT_CONNTRACK_PROTO	0x02
+#define XT_CONNTRACK_ORIGSRC	0x04
+#define XT_CONNTRACK_ORIGDST	0x08
+#define XT_CONNTRACK_REPLSRC	0x10
+#define XT_CONNTRACK_REPLDST	0x20
+#define XT_CONNTRACK_STATUS	0x40
+#define XT_CONNTRACK_EXPIRES	0x80
+
+/* This is exposed to userspace, so remains frozen in time. */
+struct ip_conntrack_old_tuple
+{
+	struct {
+		__u32 ip;
+		union {
+			__u16 all;
+		} u;
+	} src;
+
+	struct {
+		__u32 ip;
+		union {
+			__u16 all;
+		} u;
+
+		/* The protocol. */
+		u16 protonum;
+	} dst;
+};
+
+struct xt_conntrack_info
+{
+	unsigned int statemask, statusmask;
+
+	struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
+	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
+
+	unsigned long expires_min, expires_max;
+
+	/* Flags word */
+	u_int8_t flags;
+	/* Inverse flags */
+	u_int8_t invflags;
+};
+#endif /*_XT_CONNTRACK_H*/
diff --git a/include/linux/netfilter/xt_dccp.h b/include/linux/netfilter/xt_dccp.h
new file mode 100644
index 0000000..e0221b9
--- /dev/null
+++ b/include/linux/netfilter/xt_dccp.h
@@ -0,0 +1,23 @@
+#ifndef _XT_DCCP_H_
+#define _XT_DCCP_H_
+
+#define XT_DCCP_SRC_PORTS	        0x01
+#define XT_DCCP_DEST_PORTS	        0x02
+#define XT_DCCP_TYPE			0x04
+#define XT_DCCP_OPTION			0x08
+
+#define XT_DCCP_VALID_FLAGS		0x0f
+
+struct xt_dccp_info {
+	u_int16_t dpts[2];  /* Min, Max */
+	u_int16_t spts[2];  /* Min, Max */
+
+	u_int16_t flags;
+	u_int16_t invflags;
+
+	u_int16_t typemask;
+	u_int8_t option;
+};
+
+#endif /* _XT_DCCP_H_ */
+
diff --git a/include/linux/netfilter/xt_helper.h b/include/linux/netfilter/xt_helper.h
new file mode 100644
index 0000000..6b42763f
--- /dev/null
+++ b/include/linux/netfilter/xt_helper.h
@@ -0,0 +1,8 @@
+#ifndef _XT_HELPER_H
+#define _XT_HELPER_H
+
+struct xt_helper_info {
+	int invert;
+	char name[30];
+};
+#endif /* _XT_HELPER_H */
diff --git a/include/linux/netfilter/xt_length.h b/include/linux/netfilter/xt_length.h
new file mode 100644
index 0000000..7c2b439
--- /dev/null
+++ b/include/linux/netfilter/xt_length.h
@@ -0,0 +1,9 @@
+#ifndef _XT_LENGTH_H
+#define _XT_LENGTH_H
+
+struct xt_length_info {
+    u_int16_t	min, max;
+    u_int8_t	invert;
+};
+
+#endif /*_XT_LENGTH_H*/
diff --git a/include/linux/netfilter/xt_limit.h b/include/linux/netfilter/xt_limit.h
new file mode 100644
index 0000000..b3ce653
--- /dev/null
+++ b/include/linux/netfilter/xt_limit.h
@@ -0,0 +1,21 @@
+#ifndef _XT_RATE_H
+#define _XT_RATE_H
+
+/* timings are in milliseconds. */
+#define XT_LIMIT_SCALE 10000
+
+/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
+   seconds, or one every 59 hours. */
+struct xt_rateinfo {
+	u_int32_t avg;    /* Average secs between packets * scale */
+	u_int32_t burst;  /* Period multiplier for upper limit. */
+
+	/* Used internally by the kernel */
+	unsigned long prev;
+	u_int32_t credit;
+	u_int32_t credit_cap, cost;
+
+	/* Ugly, ugly fucker. */
+	struct xt_rateinfo *master;
+};
+#endif /*_XT_RATE_H*/
diff --git a/include/linux/netfilter/xt_mac.h b/include/linux/netfilter/xt_mac.h
new file mode 100644
index 0000000..b892cdc
--- /dev/null
+++ b/include/linux/netfilter/xt_mac.h
@@ -0,0 +1,8 @@
+#ifndef _XT_MAC_H
+#define _XT_MAC_H
+
+struct xt_mac_info {
+    unsigned char srcaddr[ETH_ALEN];
+    int invert;
+};
+#endif /*_XT_MAC_H*/
diff --git a/include/linux/netfilter/xt_mark.h b/include/linux/netfilter/xt_mark.h
new file mode 100644
index 0000000..802dd48
--- /dev/null
+++ b/include/linux/netfilter/xt_mark.h
@@ -0,0 +1,9 @@
+#ifndef _XT_MARK_H
+#define _XT_MARK_H
+
+struct xt_mark_info {
+    unsigned long mark, mask;
+    u_int8_t invert;
+};
+
+#endif /*_XT_MARK_H*/
diff --git a/include/linux/netfilter/xt_physdev.h b/include/linux/netfilter/xt_physdev.h
new file mode 100644
index 0000000..25a7a18
--- /dev/null
+++ b/include/linux/netfilter/xt_physdev.h
@@ -0,0 +1,24 @@
+#ifndef _XT_PHYSDEV_H
+#define _XT_PHYSDEV_H
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+#define XT_PHYSDEV_OP_IN		0x01
+#define XT_PHYSDEV_OP_OUT		0x02
+#define XT_PHYSDEV_OP_BRIDGED		0x04
+#define XT_PHYSDEV_OP_ISIN		0x08
+#define XT_PHYSDEV_OP_ISOUT		0x10
+#define XT_PHYSDEV_OP_MASK		(0x20 - 1)
+
+struct xt_physdev_info {
+	char physindev[IFNAMSIZ];
+	char in_mask[IFNAMSIZ];
+	char physoutdev[IFNAMSIZ];
+	char out_mask[IFNAMSIZ];
+	u_int8_t invert;
+	u_int8_t bitmask;
+};
+
+#endif /*_XT_PHYSDEV_H*/
diff --git a/include/linux/netfilter/xt_pkttype.h b/include/linux/netfilter/xt_pkttype.h
new file mode 100644
index 0000000..f265cf5
--- /dev/null
+++ b/include/linux/netfilter/xt_pkttype.h
@@ -0,0 +1,8 @@
+#ifndef _XT_PKTTYPE_H
+#define _XT_PKTTYPE_H
+
+struct xt_pkttype_info {
+	int	pkttype;
+	int	invert;
+};
+#endif /*_XT_PKTTYPE_H*/
diff --git a/include/linux/netfilter/xt_realm.h b/include/linux/netfilter/xt_realm.h
new file mode 100644
index 0000000..220e872
--- /dev/null
+++ b/include/linux/netfilter/xt_realm.h
@@ -0,0 +1,10 @@
+#ifndef _XT_REALM_H
+#define _XT_REALM_H
+
+struct xt_realm_info {
+	u_int32_t id;
+	u_int32_t mask;
+	u_int8_t invert;
+};
+
+#endif /* _XT_REALM_H */
diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h
new file mode 100644
index 0000000..b157897
--- /dev/null
+++ b/include/linux/netfilter/xt_sctp.h
@@ -0,0 +1,107 @@
+#ifndef _XT_SCTP_H_
+#define _XT_SCTP_H_
+
+#define XT_SCTP_SRC_PORTS	        0x01
+#define XT_SCTP_DEST_PORTS	        0x02
+#define XT_SCTP_CHUNK_TYPES		0x04
+
+#define XT_SCTP_VALID_FLAGS		0x07
+
+#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
+
+
+struct xt_sctp_flag_info {
+	u_int8_t chunktype;
+	u_int8_t flag;
+	u_int8_t flag_mask;
+};
+
+#define XT_NUM_SCTP_FLAGS	4
+
+struct xt_sctp_info {
+	u_int16_t dpts[2];  /* Min, Max */
+	u_int16_t spts[2];  /* Min, Max */
+
+	u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
+
+#define SCTP_CHUNK_MATCH_ANY   0x01  /* Match if any of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ALL   0x02  /* Match if all of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ONLY  0x04  /* Match if these are the only chunk types present */
+
+	u_int32_t chunk_match_type;
+	struct xt_sctp_flag_info flag_info[XT_NUM_SCTP_FLAGS];
+	int flag_count;
+
+	u_int32_t flags;
+	u_int32_t invflags;
+};
+
+#define bytes(type) (sizeof(type) * 8)
+
+#define SCTP_CHUNKMAP_SET(chunkmap, type) 		\
+	do { 						\
+		chunkmap[type / bytes(u_int32_t)] |= 	\
+			1 << (type % bytes(u_int32_t));	\
+	} while (0)
+
+#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)		 	\
+	do {							\
+		chunkmap[type / bytes(u_int32_t)] &= 		\
+			~(1 << (type % bytes(u_int32_t)));	\
+	} while (0)
+
+#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) 			\
+({								\
+	(chunkmap[type / bytes (u_int32_t)] & 			\
+		(1 << (type % bytes (u_int32_t)))) ? 1: 0;	\
+})
+
+#define SCTP_CHUNKMAP_RESET(chunkmap) 				\
+	do {							\
+		int i; 						\
+		for (i = 0; i < ELEMCOUNT(chunkmap); i++)	\
+			chunkmap[i] = 0;			\
+	} while (0)
+
+#define SCTP_CHUNKMAP_SET_ALL(chunkmap) 			\
+	do {							\
+		int i; 						\
+		for (i = 0; i < ELEMCOUNT(chunkmap); i++) 	\
+			chunkmap[i] = ~0;			\
+	} while (0)
+
+#define SCTP_CHUNKMAP_COPY(destmap, srcmap) 			\
+	do {							\
+		int i; 						\
+		for (i = 0; i < ELEMCOUNT(chunkmap); i++) 	\
+			destmap[i] = srcmap[i];			\
+	} while (0)
+
+#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) 		\
+({							\
+	int i; 						\
+	int flag = 1;					\
+	for (i = 0; i < ELEMCOUNT(chunkmap); i++) {	\
+		if (chunkmap[i]) {			\
+			flag = 0;			\
+			break;				\
+		}					\
+	}						\
+        flag;						\
+})
+
+#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) 		\
+({							\
+	int i; 						\
+	int flag = 1;					\
+	for (i = 0; i < ELEMCOUNT(chunkmap); i++) {	\
+		if (chunkmap[i] != ~0) {		\
+			flag = 0;			\
+				break;			\
+		}					\
+	}						\
+        flag;						\
+})
+
+#endif /* _XT_SCTP_H_ */
+
diff --git a/include/linux/netfilter/xt_state.h b/include/linux/netfilter/xt_state.h
new file mode 100644
index 0000000..c06f32e
--- /dev/null
+++ b/include/linux/netfilter/xt_state.h
@@ -0,0 +1,13 @@
+#ifndef _XT_STATE_H
+#define _XT_STATE_H
+
+#define XT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define XT_STATE_INVALID (1 << 0)
+
+#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+
+struct xt_state_info
+{
+	unsigned int statemask;
+};
+#endif /*_XT_STATE_H*/
diff --git a/include/linux/netfilter/xt_string.h b/include/linux/netfilter/xt_string.h
new file mode 100644
index 0000000..3b3419f
--- /dev/null
+++ b/include/linux/netfilter/xt_string.h
@@ -0,0 +1,18 @@
+#ifndef _XT_STRING_H
+#define _XT_STRING_H
+
+#define XT_STRING_MAX_PATTERN_SIZE 128
+#define XT_STRING_MAX_ALGO_NAME_SIZE 16
+
+struct xt_string_info
+{
+	u_int16_t from_offset;
+	u_int16_t to_offset;
+	char	  algo[XT_STRING_MAX_ALGO_NAME_SIZE];
+	char 	  pattern[XT_STRING_MAX_PATTERN_SIZE];
+	u_int8_t  patlen;
+	u_int8_t  invert;
+	struct ts_config __attribute__((aligned(8))) *config;
+};
+
+#endif /*_XT_STRING_H*/
diff --git a/include/linux/netfilter/xt_tcpmss.h b/include/linux/netfilter/xt_tcpmss.h
new file mode 100644
index 0000000..e03274c
--- /dev/null
+++ b/include/linux/netfilter/xt_tcpmss.h
@@ -0,0 +1,9 @@
+#ifndef _XT_TCPMSS_MATCH_H
+#define _XT_TCPMSS_MATCH_H
+
+struct xt_tcpmss_match_info {
+    u_int16_t mss_min, mss_max;
+    u_int8_t invert;
+};
+
+#endif /*_XT_TCPMSS_MATCH_H*/
diff --git a/include/linux/netfilter/xt_tcpudp.h b/include/linux/netfilter/xt_tcpudp.h
new file mode 100644
index 0000000..78bc65f
--- /dev/null
+++ b/include/linux/netfilter/xt_tcpudp.h
@@ -0,0 +1,36 @@
+#ifndef _XT_TCPUDP_H
+#define _XT_TCPUDP_H
+
+/* TCP matching stuff */
+struct xt_tcp
+{
+	u_int16_t spts[2];			/* Source port range. */
+	u_int16_t dpts[2];			/* Destination port range. */
+	u_int8_t option;			/* TCP Option iff non-zero*/
+	u_int8_t flg_mask;			/* TCP flags mask byte */
+	u_int8_t flg_cmp;			/* TCP flags compare byte */
+	u_int8_t invflags;			/* Inverse flags */
+};
+
+/* Values for "inv" field in struct ipt_tcp. */
+#define XT_TCP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
+#define XT_TCP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
+#define XT_TCP_INV_FLAGS	0x04	/* Invert the sense of TCP flags. */
+#define XT_TCP_INV_OPTION	0x08	/* Invert the sense of option test. */
+#define XT_TCP_INV_MASK		0x0F	/* All possible flags. */
+
+/* UDP matching stuff */
+struct xt_udp
+{
+	u_int16_t spts[2];			/* Source port range. */
+	u_int16_t dpts[2];			/* Destination port range. */
+	u_int8_t invflags;			/* Inverse flags */
+};
+
+/* Values for "invflags" field in struct ipt_udp. */
+#define XT_UDP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
+#define XT_UDP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
+#define XT_UDP_INV_MASK	0x03	/* All possible flags. */
+
+
+#endif
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index e98a870..fd21796 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -19,8 +19,12 @@
 #include <linux/compiler.h>
 #include <linux/netfilter_arp.h>
 
-#define ARPT_FUNCTION_MAXNAMELEN 30
-#define ARPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define arpt_target xt_target
+#define arpt_table xt_table
 
 #define ARPT_DEV_ADDR_LEN_MAX 16
 
@@ -91,11 +95,6 @@
 	int verdict;
 };
 
-struct arpt_counters
-{
-	u_int64_t pcnt, bcnt;			/* Packet and byte counters */
-};
-
 /* Values for "flag" field in struct arpt_ip (general arp structure).
  * No flags defined yet.
  */
@@ -130,7 +129,7 @@
 	unsigned int comefrom;
 
 	/* Packet and byte counters. */
-	struct arpt_counters counters;
+	struct xt_counters counters;
 
 	/* The matches (if any), then the target. */
 	unsigned char elems[0];
@@ -141,23 +140,24 @@
  * Unlike BSD Linux inherits IP options so you don't have to use a raw
  * socket for this. Instead we check rights in the calls.
  */
-#define ARPT_BASE_CTL		96	/* base for firewall socket options */
+#define ARPT_CTL_OFFSET		32
+#define ARPT_BASE_CTL		(XT_BASE_CTL+ARPT_CTL_OFFSET)
 
-#define ARPT_SO_SET_REPLACE		(ARPT_BASE_CTL)
-#define ARPT_SO_SET_ADD_COUNTERS	(ARPT_BASE_CTL + 1)
-#define ARPT_SO_SET_MAX			ARPT_SO_SET_ADD_COUNTERS
+#define ARPT_SO_SET_REPLACE		(XT_SO_SET_REPLACE+ARPT_CTL_OFFSET)
+#define ARPT_SO_SET_ADD_COUNTERS	(XT_SO_SET_ADD_COUNTERS+ARPT_CTL_OFFSET)
+#define ARPT_SO_SET_MAX			(XT_SO_SET_MAX+ARPT_CTL_OFFSET)
 
-#define ARPT_SO_GET_INFO		(ARPT_BASE_CTL)
-#define ARPT_SO_GET_ENTRIES		(ARPT_BASE_CTL + 1)
-/* #define ARPT_SO_GET_REVISION_MATCH	(ARPT_BASE_CTL + 2)*/
-#define ARPT_SO_GET_REVISION_TARGET	(ARPT_BASE_CTL + 3)
-#define ARPT_SO_GET_MAX			ARPT_SO_GET_REVISION_TARGET
+#define ARPT_SO_GET_INFO		(XT_SO_GET_INFO+ARPT_CTL_OFFSET)
+#define ARPT_SO_GET_ENTRIES		(XT_SO_GET_ENTRIES+ARPT_CTL_OFFSET)
+/* #define ARPT_SO_GET_REVISION_MATCH	XT_SO_GET_REVISION_MATCH  */
+#define ARPT_SO_GET_REVISION_TARGET	(XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET)
+#define ARPT_SO_GET_MAX			(XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET)
 
 /* CONTINUE verdict for targets */
-#define ARPT_CONTINUE 0xFFFFFFFF
+#define ARPT_CONTINUE XT_CONTINUE
 
 /* For standard target */
-#define ARPT_RETURN (-NF_REPEAT - 1)
+#define ARPT_RETURN XT_RETURN
 
 /* The argument to ARPT_SO_GET_INFO */
 struct arpt_getinfo
@@ -208,23 +208,14 @@
 	/* Number of counters (must be equal to current number of entries). */
 	unsigned int num_counters;
 	/* The old entries' counters. */
-	struct arpt_counters __user *counters;
+	struct xt_counters __user *counters;
 
 	/* The entries (hang off end: not really an array). */
 	struct arpt_entry entries[0];
 };
 
 /* The argument to ARPT_SO_ADD_COUNTERS. */
-struct arpt_counters_info
-{
-	/* Which table. */
-	char name[ARPT_TABLE_MAXNAMELEN];
-
-	unsigned int num_counters;
-
-	/* The counters (actually `number' of these). */
-	struct arpt_counters counters[0];
-};
+#define arpt_counters_info xt_counters_info
 
 /* The argument to ARPT_SO_GET_ENTRIES. */
 struct arpt_get_entries
@@ -239,19 +230,10 @@
 	struct arpt_entry entrytable[0];
 };
 
-/* The argument to ARPT_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct arpt_get_revision
-{
-	char name[ARPT_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define ARPT_STANDARD_TARGET ""
+#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define ARPT_ERROR_TARGET "ERROR"
+#define ARPT_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e)
@@ -281,63 +263,8 @@
  */
 #ifdef __KERNEL__
 
-/* Registration hooks for targets. */
-struct arpt_target
-{
-	struct list_head list;
-
-	const char name[ARPT_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-
-	/* Returns verdict. */
-	unsigned int (*target)(struct sk_buff **pskb,
-			       unsigned int hooknum,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       const void *targinfo,
-			       void *userdata);
-
-	/* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-	/* Should return true or false. */
-	int (*checkentry)(const char *tablename,
-			  const struct arpt_entry *e,
-			  void *targinfo,
-			  unsigned int targinfosize,
-			  unsigned int hook_mask);
-
-	/* Called when entry of this type deleted. */
-	void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
-	struct module *me;
-};
-
-extern int arpt_register_target(struct arpt_target *target);
-extern void arpt_unregister_target(struct arpt_target *target);
-
-/* Furniture shopping... */
-struct arpt_table
-{
-	struct list_head list;
-
-	/* A unique name... */
-	char name[ARPT_TABLE_MAXNAMELEN];
-
-	/* What hooks you will enter on */
-	unsigned int valid_hooks;
-
-	/* Lock for the curtain */
-	rwlock_t lock;
-
-	/* Man behind the curtain... */
-	struct arpt_table_info *private;
-
-	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
-	struct module *me;
-};
+#define arpt_register_target(tgt) xt_register_target(NF_ARP, tgt)
+#define arpt_unregister_target(tgt) xt_unregister_target(NF_ARP, tgt)
 
 extern int arpt_register_table(struct arpt_table *table,
 			       const struct arpt_replace *repl);
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index b3432ab..215765f 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -199,9 +199,6 @@
 	nf_conntrack_put(&ct->ct_general);
 }
 
-/* call to create an explicit dependency on ip_conntrack. */
-extern void need_ip_conntrack(void);
-
 extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
 			  const struct ip_conntrack_tuple *orig);
 
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index d19d65c..76ba24b 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -25,8 +25,14 @@
 #include <linux/compiler.h>
 #include <linux/netfilter_ipv4.h>
 
-#define IPT_FUNCTION_MAXNAMELEN 30
-#define IPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
 
 /* Yes, Virginia, you have to zero the padding. */
 struct ipt_ip {
@@ -102,10 +108,7 @@
 	int verdict;
 };
 
-struct ipt_counters
-{
-	u_int64_t pcnt, bcnt;			/* Packet and byte counters */
-};
+#define ipt_counters xt_counters
 
 /* Values for "flag" field in struct ipt_ip (general ip structure). */
 #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
@@ -119,7 +122,7 @@
 #define IPT_INV_SRCIP		0x08	/* Invert the sense of SRC IP. */
 #define IPT_INV_DSTIP		0x10	/* Invert the sense of DST OP. */
 #define IPT_INV_FRAG		0x20	/* Invert the sense of FRAG. */
-#define IPT_INV_PROTO		0x40	/* Invert the sense of PROTO. */
+#define IPT_INV_PROTO		XT_INV_PROTO
 #define IPT_INV_MASK		0x7F	/* All possible flag bits mask. */
 
 /* This structure defines each of the firewall rules.  Consists of 3
@@ -141,7 +144,7 @@
 	unsigned int comefrom;
 
 	/* Packet and byte counters. */
-	struct ipt_counters counters;
+	struct xt_counters counters;
 
 	/* The matches (if any), then the target. */
 	unsigned char elems[0];
@@ -151,54 +154,34 @@
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use a raw
  * socket for this. Instead we check rights in the calls. */
-#define IPT_BASE_CTL		64	/* base for firewall socket options */
+#define IPT_BASE_CTL		XT_BASE_CTL
 
-#define IPT_SO_SET_REPLACE	(IPT_BASE_CTL)
-#define IPT_SO_SET_ADD_COUNTERS	(IPT_BASE_CTL + 1)
-#define IPT_SO_SET_MAX		IPT_SO_SET_ADD_COUNTERS
+#define IPT_SO_SET_REPLACE	XT_SO_SET_REPLACE
+#define IPT_SO_SET_ADD_COUNTERS	XT_SO_SET_ADD_COUNTERS
+#define IPT_SO_SET_MAX		XT_SO_SET_MAX
 
-#define IPT_SO_GET_INFO			(IPT_BASE_CTL)
-#define IPT_SO_GET_ENTRIES		(IPT_BASE_CTL + 1)
-#define IPT_SO_GET_REVISION_MATCH	(IPT_BASE_CTL + 2)
-#define IPT_SO_GET_REVISION_TARGET	(IPT_BASE_CTL + 3)
-#define IPT_SO_GET_MAX			IPT_SO_GET_REVISION_TARGET
+#define IPT_SO_GET_INFO			XT_SO_GET_INFO
+#define IPT_SO_GET_ENTRIES		XT_SO_GET_ENTRIES
+#define IPT_SO_GET_REVISION_MATCH	XT_SO_GET_REVISION_MATCH
+#define IPT_SO_GET_REVISION_TARGET	XT_SO_GET_REVISION_TARGET
+#define IPT_SO_GET_MAX			XT_SO_GET_REVISION_TARGET
 
-/* CONTINUE verdict for targets */
-#define IPT_CONTINUE 0xFFFFFFFF
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
 
-/* For standard target */
-#define IPT_RETURN (-NF_REPEAT - 1)
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
 
-/* TCP matching stuff */
-struct ipt_tcp
-{
-	u_int16_t spts[2];			/* Source port range. */
-	u_int16_t dpts[2];			/* Destination port range. */
-	u_int8_t option;			/* TCP Option iff non-zero*/
-	u_int8_t flg_mask;			/* TCP flags mask byte */
-	u_int8_t flg_cmp;			/* TCP flags compare byte */
-	u_int8_t invflags;			/* Inverse flags */
-};
+#define IPT_TCP_INV_SRCPT	XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT	XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS	XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION	XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK	XT_TCP_INV_MASK
 
-/* Values for "inv" field in struct ipt_tcp. */
-#define IPT_TCP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
-#define IPT_TCP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
-#define IPT_TCP_INV_FLAGS	0x04	/* Invert the sense of TCP flags. */
-#define IPT_TCP_INV_OPTION	0x08	/* Invert the sense of option test. */
-#define IPT_TCP_INV_MASK	0x0F	/* All possible flags. */
-
-/* UDP matching stuff */
-struct ipt_udp
-{
-	u_int16_t spts[2];			/* Source port range. */
-	u_int16_t dpts[2];			/* Destination port range. */
-	u_int8_t invflags;			/* Inverse flags */
-};
-
-/* Values for "invflags" field in struct ipt_udp. */
-#define IPT_UDP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
-#define IPT_UDP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
-#define IPT_UDP_INV_MASK	0x03	/* All possible flags. */
+#define IPT_UDP_INV_SRCPT	XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT	XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK	XT_UDP_INV_MASK
 
 /* ICMP matching stuff */
 struct ipt_icmp
@@ -260,23 +243,14 @@
 	/* Number of counters (must be equal to current number of entries). */
 	unsigned int num_counters;
 	/* The old entries' counters. */
-	struct ipt_counters __user *counters;
+	struct xt_counters __user *counters;
 
 	/* The entries (hang off end: not really an array). */
 	struct ipt_entry entries[0];
 };
 
 /* The argument to IPT_SO_ADD_COUNTERS. */
-struct ipt_counters_info
-{
-	/* Which table. */
-	char name[IPT_TABLE_MAXNAMELEN];
-
-	unsigned int num_counters;
-
-	/* The counters (actually `number' of these). */
-	struct ipt_counters counters[0];
-};
+#define ipt_counters_info xt_counters_info
 
 /* The argument to IPT_SO_GET_ENTRIES. */
 struct ipt_get_entries
@@ -291,19 +265,10 @@
 	struct ipt_entry entrytable[0];
 };
 
-/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct ipt_get_revision
-{
-	char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define IPT_STANDARD_TARGET ""
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define IPT_ERROR_TARGET "ERROR"
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct ipt_entry_target *
@@ -356,103 +321,18 @@
 #include <linux/init.h>
 extern void ipt_init(void) __init;
 
-struct ipt_match
-{
-	struct list_head list;
+#define ipt_register_target(tgt) xt_register_target(AF_INET, tgt)
+#define ipt_unregister_target(tgt) xt_unregister_target(AF_INET, tgt)
 
-	const char name[IPT_FUNCTION_MAXNAMELEN-1];
+#define ipt_register_match(mtch) xt_register_match(AF_INET, mtch)
+#define ipt_unregister_match(mtch) xt_unregister_match(AF_INET, mtch)
 
-	u_int8_t revision;
+//#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl)
+//#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl)
 
-	/* Return true or false: return FALSE and set *hotdrop = 1 to
-           force immediate packet drop. */
-	/* Arguments changed since 2.4, as this must now handle
-           non-linear skbs, using skb_copy_bits and
-           skb_ip_make_writable. */
-	int (*match)(const struct sk_buff *skb,
-		     const struct net_device *in,
-		     const struct net_device *out,
-		     const void *matchinfo,
-		     int offset,
-		     int *hotdrop);
-
-	/* Called when user tries to insert an entry of this type. */
-	/* Should return true or false. */
-	int (*checkentry)(const char *tablename,
-			  const struct ipt_ip *ip,
-			  void *matchinfo,
-			  unsigned int matchinfosize,
-			  unsigned int hook_mask);
-
-	/* Called when entry of this type deleted. */
-	void (*destroy)(void *matchinfo, unsigned int matchinfosize);
-
-	/* Set this to THIS_MODULE. */
-	struct module *me;
-};
-
-/* Registration hooks for targets. */
-struct ipt_target
-{
-	struct list_head list;
-
-	const char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-
-	/* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-	/* Should return true or false. */
-	int (*checkentry)(const char *tablename,
-			  const struct ipt_entry *e,
-			  void *targinfo,
-			  unsigned int targinfosize,
-			  unsigned int hook_mask);
-
-	/* Called when entry of this type deleted. */
-	void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-	/* Returns verdict.  Argument order changed since 2.4, as this
-           must now handle non-linear skbs, using skb_copy_bits and
-           skb_ip_make_writable. */
-	unsigned int (*target)(struct sk_buff **pskb,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       unsigned int hooknum,
-			       const void *targinfo,
-			       void *userdata);
-
-	/* Set this to THIS_MODULE. */
-	struct module *me;
-};
-
-extern int ipt_register_target(struct ipt_target *target);
-extern void ipt_unregister_target(struct ipt_target *target);
-
-extern int ipt_register_match(struct ipt_match *match);
-extern void ipt_unregister_match(struct ipt_match *match);
-
-/* Furniture shopping... */
-struct ipt_table
-{
-	struct list_head list;
-
-	/* A unique name... */
-	char name[IPT_TABLE_MAXNAMELEN];
-
-	/* What hooks you will enter on */
-	unsigned int valid_hooks;
-
-	/* Lock for the curtain */
-	rwlock_t lock;
-
-	/* Man behind the curtain... */
-	struct ipt_table_info *private;
-
-	/* Set to THIS_MODULE. */
-	struct module *me;
-};
+extern int ipt_register_table(struct ipt_table *table,
+			      const struct ipt_replace *repl);
+extern void ipt_unregister_table(struct ipt_table *table);
 
 /* net/sched/ipt.c: Gimme access to your targets!  Gets target->me. */
 extern struct ipt_target *ipt_find_target(const char *name, u8 revision);
@@ -476,9 +356,6 @@
 	struct ipt_error_target target;
 };
 
-extern int ipt_register_table(struct ipt_table *table,
-			      const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct ipt_table *table);
 extern unsigned int ipt_do_table(struct sk_buff **pskb,
 				 unsigned int hook,
 				 const struct net_device *in,
@@ -486,6 +363,6 @@
 				 struct ipt_table *table,
 				 void *userdata);
 
-#define IPT_ALIGN(s) (((s) + (__alignof__(struct ipt_entry)-1)) & ~(__alignof__(struct ipt_entry)-1))
+#define IPT_ALIGN(s) XT_ALIGN(s)
 #endif /*__KERNEL__*/
 #endif /* _IPTABLES_H */
diff --git a/include/linux/netfilter_ipv4/ipt_CLASSIFY.h b/include/linux/netfilter_ipv4/ipt_CLASSIFY.h
index 7596e3d..a46d511 100644
--- a/include/linux/netfilter_ipv4/ipt_CLASSIFY.h
+++ b/include/linux/netfilter_ipv4/ipt_CLASSIFY.h
@@ -1,8 +1,7 @@
 #ifndef _IPT_CLASSIFY_H
 #define _IPT_CLASSIFY_H
 
-struct ipt_classify_target_info {
-	u_int32_t priority;
-};
+#include <linux/netfilter/xt_CLASSIFY.h>
+#define ipt_classify_target_info xt_classify_target_info
 
 #endif /*_IPT_CLASSIFY_H */
diff --git a/include/linux/netfilter_ipv4/ipt_CONNMARK.h b/include/linux/netfilter_ipv4/ipt_CONNMARK.h
index d3c0253..9ecfee0 100644
--- a/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+++ b/include/linux/netfilter_ipv4/ipt_CONNMARK.h
@@ -9,17 +9,11 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
+#include <linux/netfilter/xt_CONNMARK.h>
+#define IPT_CONNMARK_SET	XT_CONNMARK_SET
+#define IPT_CONNMARK_SAVE	XT_CONNMARK_SAVE
+#define	IPT_CONNMARK_RESTORE	XT_CONNMARK_RESTORE
 
-enum {
-	IPT_CONNMARK_SET = 0,
-	IPT_CONNMARK_SAVE,
-	IPT_CONNMARK_RESTORE
-};
-
-struct ipt_connmark_target_info {
-	unsigned long mark;
-	unsigned long mask;
-	u_int8_t mode;
-};
+#define ipt_connmark_target_info xt_connmark_target_info
 
 #endif /*_IPT_CONNMARK_H_target*/
diff --git a/include/linux/netfilter_ipv4/ipt_MARK.h b/include/linux/netfilter_ipv4/ipt_MARK.h
index f474857..697a486 100644
--- a/include/linux/netfilter_ipv4/ipt_MARK.h
+++ b/include/linux/netfilter_ipv4/ipt_MARK.h
@@ -1,20 +1,18 @@
 #ifndef _IPT_MARK_H_target
 #define _IPT_MARK_H_target
 
+/* Backwards compatibility for old userspace */
+
+#include <linux/netfilter/xt_MARK.h>
+
 /* Version 0 */
-struct ipt_mark_target_info {
-	unsigned long mark;
-};
+#define ipt_mark_target_info xt_mark_target_info
 
 /* Version 1 */
-enum {
-	IPT_MARK_SET=0,
-	IPT_MARK_AND,
-	IPT_MARK_OR
-};
+#define IPT_MARK_SET	XT_MARK_SET
+#define IPT_MARK_AND	XT_MARK_AND
+#define	IPT_MARK_OR	XT_MARK_OR
 
-struct ipt_mark_target_info_v1 {
-	unsigned long mark;
-	u_int8_t mode;
-};
+#define ipt_mark_target_info_v1 xt_mark_target_info_v1
+
 #endif /*_IPT_MARK_H_target*/
diff --git a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h
index b5b2943..97a2a75 100644
--- a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h
+++ b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h
@@ -8,9 +8,9 @@
 #ifndef _IPT_NFQ_TARGET_H
 #define _IPT_NFQ_TARGET_H
 
-/* target info */
-struct ipt_NFQ_info {
-	u_int16_t queuenum;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_NFQUEUE.h>
+
+#define ipt_NFQ_info xt_NFQ_info
 
 #endif /* _IPT_DSCP_TARGET_H */
diff --git a/include/linux/netfilter_ipv4/ipt_comment.h b/include/linux/netfilter_ipv4/ipt_comment.h
index 85c1123..ae2afc2 100644
--- a/include/linux/netfilter_ipv4/ipt_comment.h
+++ b/include/linux/netfilter_ipv4/ipt_comment.h
@@ -1,10 +1,10 @@
 #ifndef _IPT_COMMENT_H
 #define _IPT_COMMENT_H
 
-#define IPT_MAX_COMMENT_LEN 256
+#include <linux/netfilter/xt_comment.h>
 
-struct ipt_comment_info {
-	unsigned char comment[IPT_MAX_COMMENT_LEN];
-};
+#define IPT_MAX_COMMENT_LEN XT_MAX_COMMENT_LEN
+
+#define ipt_comment_info xt_comment_info
 
 #endif /* _IPT_COMMENT_H */
diff --git a/include/linux/netfilter_ipv4/ipt_connbytes.h b/include/linux/netfilter_ipv4/ipt_connbytes.h
index 9e5532f..b04dfa3 100644
--- a/include/linux/netfilter_ipv4/ipt_connbytes.h
+++ b/include/linux/netfilter_ipv4/ipt_connbytes.h
@@ -1,25 +1,18 @@
 #ifndef _IPT_CONNBYTES_H
 #define _IPT_CONNBYTES_H
 
-enum ipt_connbytes_what {
-	IPT_CONNBYTES_PKTS,
-	IPT_CONNBYTES_BYTES,
-	IPT_CONNBYTES_AVGPKT,
-};
+#include <net/netfilter/xt_connbytes.h>
+#define ipt_connbytes_what xt_connbytes_what
 
-enum ipt_connbytes_direction {
-	IPT_CONNBYTES_DIR_ORIGINAL,
-	IPT_CONNBYTES_DIR_REPLY,
-	IPT_CONNBYTES_DIR_BOTH,
-};
+#define IPT_CONNBYTES_PKTS	XT_CONNBYTES_PACKETS
+#define IPT_CONNBYTES_BYTES	XT_CONNBYTES_BYTES
+#define IPT_CONNBYTES_AVGPKT	XT_CONNBYTES_AVGPKT
 
-struct ipt_connbytes_info
-{
-	struct {
-		aligned_u64 from;	/* count to be matched */
-		aligned_u64 to;		/* count to be matched */
-	} count;
-	u_int8_t what;		/* ipt_connbytes_what */
-	u_int8_t direction;	/* ipt_connbytes_direction */
-};
+#define ipt_connbytes_direction 	xt_connbytes_direction
+#define IPT_CONNBYTES_DIR_ORIGINAL 	XT_CONNBYTES_DIR_ORIGINAL
+#define IPT_CONNBYTES_DIR_REPLY 	XT_CONNBYTES_DIR_REPLY
+#define IPT_CONNBYTES_DIR_BOTH		XT_CONNBYTES_DIR_BOTH
+
+#define ipt_connbytes_info xt_connbytes_info
+
 #endif
diff --git a/include/linux/netfilter_ipv4/ipt_connmark.h b/include/linux/netfilter_ipv4/ipt_connmark.h
index 4657327..c7ba656 100644
--- a/include/linux/netfilter_ipv4/ipt_connmark.h
+++ b/include/linux/netfilter_ipv4/ipt_connmark.h
@@ -1,18 +1,7 @@
 #ifndef _IPT_CONNMARK_H
 #define _IPT_CONNMARK_H
 
-/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- * by Henrik Nordstrom <hno@marasystems.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-struct ipt_connmark_info {
-	unsigned long mark, mask;
-	u_int8_t invert;
-};
+#include <linux/netfilter/xt_connmark.h>
+#define ipt_connmark_info xt_connmark_info
 
 #endif /*_IPT_CONNMARK_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_conntrack.h b/include/linux/netfilter_ipv4/ipt_conntrack.h
index 413c565..cde6762 100644
--- a/include/linux/netfilter_ipv4/ipt_conntrack.h
+++ b/include/linux/netfilter_ipv4/ipt_conntrack.h
@@ -5,56 +5,24 @@
 #ifndef _IPT_CONNTRACK_H
 #define _IPT_CONNTRACK_H
 
-#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
-#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
+#include <linux/netfilter/xt_conntrack.h>
 
-#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
-#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
-#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+#define IPT_CONNTRACK_STATE_BIT(ctinfo) XT_CONNTRACK_STATE_BIT(ctinfo)
+#define IPT_CONNTRACK_STATE_INVALID 	XT_CONNTRACK_STATE_INVALID
+
+#define IPT_CONNTRACK_STATE_SNAT 	XT_CONNTRACK_STATE_SNAT
+#define IPT_CONNTRACK_STATE_DNAT	XT_CONNTRACK_STATE_DNAT
+#define IPT_CONNTRACK_STATE_UNTRACKED	XT_CONNTRACK_STATE_UNTRACKED
 
 /* flags, invflags: */
-#define IPT_CONNTRACK_STATE	0x01
-#define IPT_CONNTRACK_PROTO	0x02
-#define IPT_CONNTRACK_ORIGSRC	0x04
-#define IPT_CONNTRACK_ORIGDST	0x08
-#define IPT_CONNTRACK_REPLSRC	0x10
-#define IPT_CONNTRACK_REPLDST	0x20
-#define IPT_CONNTRACK_STATUS	0x40
-#define IPT_CONNTRACK_EXPIRES	0x80
+#define IPT_CONNTRACK_STATE		XT_CONNTRACK_STATE
+#define IPT_CONNTRACK_PROTO		XT_CONNTRACK_PROTO
+#define IPT_CONNTRACK_ORIGSRC		XT_CONNTRACK_ORIGSRC
+#define IPT_CONNTRACK_ORIGDST		XT_CONNTRACK_ORIGDST
+#define IPT_CONNTRACK_REPLSRC		XT_CONNTRACK_REPLSRC
+#define IPT_CONNTRACK_REPLDST		XT_CONNTRACK_REPLDST
+#define IPT_CONNTRACK_STATUS		XT_CONNTRACK_STATUS
+#define IPT_CONNTRACK_EXPIRES		XT_CONNTRACK_EXPIRES
 
-/* This is exposed to userspace, so remains frozen in time. */
-struct ip_conntrack_old_tuple
-{
-	struct {
-		__u32 ip;
-		union {
-			__u16 all;
-		} u;
-	} src;
-
-	struct {
-		__u32 ip;
-		union {
-			__u16 all;
-		} u;
-
-		/* The protocol. */
-		u16 protonum;
-	} dst;
-};
-
-struct ipt_conntrack_info
-{
-	unsigned int statemask, statusmask;
-
-	struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
-	struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
-
-	unsigned long expires_min, expires_max;
-
-	/* Flags word */
-	u_int8_t flags;
-	/* Inverse flags */
-	u_int8_t invflags;
-};
+#define ipt_conntrack_info		xt_conntrack_info
 #endif /*_IPT_CONNTRACK_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_dccp.h b/include/linux/netfilter_ipv4/ipt_dccp.h
index 3cb3a52..e70d11e 100644
--- a/include/linux/netfilter_ipv4/ipt_dccp.h
+++ b/include/linux/netfilter_ipv4/ipt_dccp.h
@@ -1,23 +1,15 @@
 #ifndef _IPT_DCCP_H_
 #define _IPT_DCCP_H_
 
-#define IPT_DCCP_SRC_PORTS	        0x01
-#define IPT_DCCP_DEST_PORTS	        0x02
-#define IPT_DCCP_TYPE			0x04
-#define IPT_DCCP_OPTION			0x08
+#include <linux/netfilter/xt_dccp.h>
+#define IPT_DCCP_SRC_PORTS	XT_DCCP_SRC_PORTS
+#define IPT_DCCP_DEST_PORTS	XT_DCCP_DEST_PORTS
+#define IPT_DCCP_TYPE		XT_DCCP_TYPE
+#define IPT_DCCP_OPTION		XT_DCCP_OPTION
 
-#define IPT_DCCP_VALID_FLAGS		0x0f
+#define IPT_DCCP_VALID_FLAGS 	XT_DCCP_VALID_FLAGS
 
-struct ipt_dccp_info {
-	u_int16_t dpts[2];  /* Min, Max */
-	u_int16_t spts[2];  /* Min, Max */
-
-	u_int16_t flags;
-	u_int16_t invflags;
-
-	u_int16_t typemask;
-	u_int8_t option;
-};
+#define ipt_dccp_info xt_dccp_info
 
 #endif /* _IPT_DCCP_H_ */
 
diff --git a/include/linux/netfilter_ipv4/ipt_helper.h b/include/linux/netfilter_ipv4/ipt_helper.h
index 6f12ecb..80452c2 100644
--- a/include/linux/netfilter_ipv4/ipt_helper.h
+++ b/include/linux/netfilter_ipv4/ipt_helper.h
@@ -1,8 +1,7 @@
 #ifndef _IPT_HELPER_H
 #define _IPT_HELPER_H
 
-struct ipt_helper_info {
-	int invert;
-	char name[30];
-};
+#include <linux/netfilter/xt_helper.h>
+#define ipt_helper_info xt_helper_info
+
 #endif /* _IPT_HELPER_H */
diff --git a/include/linux/netfilter_ipv4/ipt_length.h b/include/linux/netfilter_ipv4/ipt_length.h
index 6e08852..9b45206 100644
--- a/include/linux/netfilter_ipv4/ipt_length.h
+++ b/include/linux/netfilter_ipv4/ipt_length.h
@@ -1,9 +1,7 @@
 #ifndef _IPT_LENGTH_H
 #define _IPT_LENGTH_H
 
-struct ipt_length_info {
-    u_int16_t	min, max;
-    u_int8_t	invert;
-};
+#include <linux/netfilter/xt_length.h>
+#define ipt_length_info xt_length_info
 
 #endif /*_IPT_LENGTH_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_limit.h b/include/linux/netfilter_ipv4/ipt_limit.h
index 2564534..92f5cd0 100644
--- a/include/linux/netfilter_ipv4/ipt_limit.h
+++ b/include/linux/netfilter_ipv4/ipt_limit.h
@@ -1,21 +1,8 @@
 #ifndef _IPT_RATE_H
 #define _IPT_RATE_H
 
-/* timings are in milliseconds. */
-#define IPT_LIMIT_SCALE 10000
+#include <linux/netfilter/xt_limit.h>
+#define IPT_LIMIT_SCALE XT_LIMIT_SCALE
+#define ipt_rateinfo xt_rateinfo
 
-/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
-   seconds, or one every 59 hours. */
-struct ipt_rateinfo {
-	u_int32_t avg;    /* Average secs between packets * scale */
-	u_int32_t burst;  /* Period multiplier for upper limit. */
-
-	/* Used internally by the kernel */
-	unsigned long prev;
-	u_int32_t credit;
-	u_int32_t credit_cap, cost;
-
-	/* Ugly, ugly fucker. */
-	struct ipt_rateinfo *master;
-};
 #endif /*_IPT_RATE_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_mac.h b/include/linux/netfilter_ipv4/ipt_mac.h
index f8d5b8e..b186008 100644
--- a/include/linux/netfilter_ipv4/ipt_mac.h
+++ b/include/linux/netfilter_ipv4/ipt_mac.h
@@ -1,8 +1,7 @@
 #ifndef _IPT_MAC_H
 #define _IPT_MAC_H
 
-struct ipt_mac_info {
-    unsigned char srcaddr[ETH_ALEN];
-    int invert;
-};
+#include <linux/netfilter/xt_mac.h>
+#define ipt_mac_info xt_mac_info
+
 #endif /*_IPT_MAC_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_mark.h b/include/linux/netfilter_ipv4/ipt_mark.h
index f3952b5..bfde67c 100644
--- a/include/linux/netfilter_ipv4/ipt_mark.h
+++ b/include/linux/netfilter_ipv4/ipt_mark.h
@@ -1,9 +1,9 @@
 #ifndef _IPT_MARK_H
 #define _IPT_MARK_H
 
-struct ipt_mark_info {
-    unsigned long mark, mask;
-    u_int8_t invert;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_mark.h>
+
+#define ipt_mark_info xt_mark_info
 
 #endif /*_IPT_MARK_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_physdev.h b/include/linux/netfilter_ipv4/ipt_physdev.h
index 7538c86..2400e71 100644
--- a/include/linux/netfilter_ipv4/ipt_physdev.h
+++ b/include/linux/netfilter_ipv4/ipt_physdev.h
@@ -1,24 +1,17 @@
 #ifndef _IPT_PHYSDEV_H
 #define _IPT_PHYSDEV_H
 
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
+/* Backwards compatibility for old userspace */
 
-#define IPT_PHYSDEV_OP_IN		0x01
-#define IPT_PHYSDEV_OP_OUT		0x02
-#define IPT_PHYSDEV_OP_BRIDGED		0x04
-#define IPT_PHYSDEV_OP_ISIN		0x08
-#define IPT_PHYSDEV_OP_ISOUT		0x10
-#define IPT_PHYSDEV_OP_MASK		(0x20 - 1)
+#include <linux/netfilter/xt_physdev.h>
 
-struct ipt_physdev_info {
-	char physindev[IFNAMSIZ];
-	char in_mask[IFNAMSIZ];
-	char physoutdev[IFNAMSIZ];
-	char out_mask[IFNAMSIZ];
-	u_int8_t invert;
-	u_int8_t bitmask;
-};
+#define IPT_PHYSDEV_OP_IN		XT_PHYSDEV_OP_IN
+#define IPT_PHYSDEV_OP_OUT		XT_PHYSDEV_OP_OUT
+#define IPT_PHYSDEV_OP_BRIDGED		XT_PHYSDEV_OP_BRIDGED
+#define IPT_PHYSDEV_OP_ISIN		XT_PHYSDEV_OP_ISIN
+#define IPT_PHYSDEV_OP_ISOUT		XT_PHYSDEV_OP_ISOUT
+#define IPT_PHYSDEV_OP_MASK		XT_PHYSDEV_OP_MASK
+
+#define ipt_physdev_info xt_physdev_info
 
 #endif /*_IPT_PHYSDEV_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_pkttype.h b/include/linux/netfilter_ipv4/ipt_pkttype.h
index d53a658..ff1fbc9 100644
--- a/include/linux/netfilter_ipv4/ipt_pkttype.h
+++ b/include/linux/netfilter_ipv4/ipt_pkttype.h
@@ -1,8 +1,7 @@
 #ifndef _IPT_PKTTYPE_H
 #define _IPT_PKTTYPE_H
 
-struct ipt_pkttype_info {
-	int	pkttype;
-	int	invert;
-};
+#include <linux/netfilter/xt_pkttype.h>
+#define ipt_pkttype_info xt_pkttype_info
+
 #endif /*_IPT_PKTTYPE_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_realm.h b/include/linux/netfilter_ipv4/ipt_realm.h
index a4d6698..b3996ea 100644
--- a/include/linux/netfilter_ipv4/ipt_realm.h
+++ b/include/linux/netfilter_ipv4/ipt_realm.h
@@ -1,10 +1,7 @@
 #ifndef _IPT_REALM_H
 #define _IPT_REALM_H
 
-struct ipt_realm_info {
-	u_int32_t id;
-	u_int32_t mask;
-	u_int8_t invert;
-};
+#include <linux/netfilter/xt_realm.h>
+#define ipt_realm_info xt_realm_info
 
 #endif /* _IPT_REALM_H */
diff --git a/include/linux/netfilter_ipv4/ipt_state.h b/include/linux/netfilter_ipv4/ipt_state.h
index 5df3786..a44a99c 100644
--- a/include/linux/netfilter_ipv4/ipt_state.h
+++ b/include/linux/netfilter_ipv4/ipt_state.h
@@ -1,13 +1,15 @@
 #ifndef _IPT_STATE_H
 #define _IPT_STATE_H
 
-#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
-#define IPT_STATE_INVALID (1 << 0)
+/* Backwards compatibility for old userspace */
 
-#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+#include <linux/netfilter/xt_state.h>
 
-struct ipt_state_info
-{
-	unsigned int statemask;
-};
+#define IPT_STATE_BIT		XT_STATE_BIT
+#define IPT_STATE_INVALID	XT_STATE_INVALID
+
+#define IPT_STATE_UNTRACKED	XT_STATE_UNTRACKED
+
+#define ipt_state_info		xt_state_info
+
 #endif /*_IPT_STATE_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_string.h b/include/linux/netfilter_ipv4/ipt_string.h
index a265f6e..c26de30 100644
--- a/include/linux/netfilter_ipv4/ipt_string.h
+++ b/include/linux/netfilter_ipv4/ipt_string.h
@@ -1,18 +1,10 @@
 #ifndef _IPT_STRING_H
 #define _IPT_STRING_H
 
-#define IPT_STRING_MAX_PATTERN_SIZE 128
-#define IPT_STRING_MAX_ALGO_NAME_SIZE 16
+#include <linux/netfilter/xt_string.h>
 
-struct ipt_string_info
-{
-	u_int16_t from_offset;
-	u_int16_t to_offset;
-	char	  algo[IPT_STRING_MAX_ALGO_NAME_SIZE];
-	char 	  pattern[IPT_STRING_MAX_PATTERN_SIZE];
-	u_int8_t  patlen;
-	u_int8_t  invert;
-	struct ts_config __attribute__((aligned(8))) *config;
-};
+#define IPT_STRING_MAX_PATTERN_SIZE XT_STRING_MAX_PATTERN_SIZE
+#define IPT_STRING_MAX_ALGO_NAME_SIZE XT_STRING_MAX_ALGO_NAME_SIZE
+#define ipt_string_info xt_string_info
 
 #endif /*_IPT_STRING_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_tcpmss.h b/include/linux/netfilter_ipv4/ipt_tcpmss.h
index e2b1439..18bbc8e 100644
--- a/include/linux/netfilter_ipv4/ipt_tcpmss.h
+++ b/include/linux/netfilter_ipv4/ipt_tcpmss.h
@@ -1,9 +1,7 @@
 #ifndef _IPT_TCPMSS_MATCH_H
 #define _IPT_TCPMSS_MATCH_H
 
-struct ipt_tcpmss_match_info {
-    u_int16_t mss_min, mss_max;
-    u_int8_t invert;
-};
+#include <linux/netfilter/xt_tcpmss.h>
+#define ipt_tcpmss_match_info xt_tcpmss_match_info
 
 #endif /*_IPT_TCPMSS_MATCH_H*/
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index c163ba3..f249b57 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -25,8 +25,15 @@
 #include <linux/compiler.h>
 #include <linux/netfilter_ipv6.h>
 
-#define IP6T_FUNCTION_MAXNAMELEN 30
-#define IP6T_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+
+#define ip6t_match xt_match
+#define ip6t_target xt_target
+#define ip6t_table xt_table
+#define ip6t_get_revision xt_get_revision
 
 /* Yes, Virginia, you have to zero the padding. */
 struct ip6t_ip6 {
@@ -104,10 +111,7 @@
 	int verdict;
 };
 
-struct ip6t_counters
-{
-	u_int64_t pcnt, bcnt;			/* Packet and byte counters */
-};
+#define ip6t_counters	xt_counters
 
 /* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
 #define IP6T_F_PROTO		0x01	/* Set if rule cares about upper 
@@ -123,7 +127,7 @@
 #define IP6T_INV_SRCIP		0x08	/* Invert the sense of SRC IP. */
 #define IP6T_INV_DSTIP		0x10	/* Invert the sense of DST OP. */
 #define IP6T_INV_FRAG		0x20	/* Invert the sense of FRAG. */
-#define IP6T_INV_PROTO		0x40	/* Invert the sense of PROTO. */
+#define IP6T_INV_PROTO		XT_INV_PROTO
 #define IP6T_INV_MASK		0x7F	/* All possible flag bits mask. */
 
 /* This structure defines each of the firewall rules.  Consists of 3
@@ -145,7 +149,7 @@
 	unsigned int comefrom;
 
 	/* Packet and byte counters. */
-	struct ip6t_counters counters;
+	struct xt_counters counters;
 
 	/* The matches (if any), then the target. */
 	unsigned char elems[0];
@@ -155,54 +159,41 @@
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use
  * a raw socket for this. Instead we check rights in the calls. */
-#define IP6T_BASE_CTL			64	/* base for firewall socket options */
+#define IP6T_BASE_CTL			XT_BASE_CTL
 
-#define IP6T_SO_SET_REPLACE		(IP6T_BASE_CTL)
-#define IP6T_SO_SET_ADD_COUNTERS	(IP6T_BASE_CTL + 1)
-#define IP6T_SO_SET_MAX			IP6T_SO_SET_ADD_COUNTERS
+#define IP6T_SO_SET_REPLACE		XT_SO_SET_REPLACE
+#define IP6T_SO_SET_ADD_COUNTERS	XT_SO_SET_ADD_COUNTERS
+#define IP6T_SO_SET_MAX			XT_SO_SET_MAX
 
-#define IP6T_SO_GET_INFO		(IP6T_BASE_CTL)
-#define IP6T_SO_GET_ENTRIES		(IP6T_BASE_CTL + 1)
-#define	IP6T_SO_GET_REVISION_MATCH	(IP6T_BASE_CTL + 2)
-#define	IP6T_SO_GET_REVISION_TARGET	(IP6T_BASE_CTL + 3)
-#define IP6T_SO_GET_MAX			IP6T_SO_GET_REVISION_TARGET
+#define IP6T_SO_GET_INFO		XT_SO_GET_INFO
+#define IP6T_SO_GET_ENTRIES		XT_SO_GET_ENTRIES
+#define	IP6T_SO_GET_REVISION_MATCH	XT_SO_GET_REVISION_MATCH
+#define	IP6T_SO_GET_REVISION_TARGET	XT_SO_GET_REVISION_TARGET
+#define IP6T_SO_GET_MAX			XT_SO_GET_REVISION_TARGET
 
 /* CONTINUE verdict for targets */
-#define IP6T_CONTINUE 0xFFFFFFFF
+#define IP6T_CONTINUE XT_CONTINUE
 
 /* For standard target */
-#define IP6T_RETURN (-NF_REPEAT - 1)
+#define IP6T_RETURN XT_RETURN
 
-/* TCP matching stuff */
-struct ip6t_tcp
-{
-	u_int16_t spts[2];			/* Source port range. */
-	u_int16_t dpts[2];			/* Destination port range. */
-	u_int8_t option;			/* TCP Option iff non-zero*/
-	u_int8_t flg_mask;			/* TCP flags mask byte */
-	u_int8_t flg_cmp;			/* TCP flags compare byte */
-	u_int8_t invflags;			/* Inverse flags */
-};
+/* TCP/UDP matching stuff */
+#include <linux/netfilter/xt_tcpudp.h>
+
+#define ip6t_tcp xt_tcp
+#define ip6t_udp xt_udp
 
 /* Values for "inv" field in struct ipt_tcp. */
-#define IP6T_TCP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
-#define IP6T_TCP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
-#define IP6T_TCP_INV_FLAGS	0x04	/* Invert the sense of TCP flags. */
-#define IP6T_TCP_INV_OPTION	0x08	/* Invert the sense of option test. */
-#define IP6T_TCP_INV_MASK	0x0F	/* All possible flags. */
-
-/* UDP matching stuff */
-struct ip6t_udp
-{
-	u_int16_t spts[2];			/* Source port range. */
-	u_int16_t dpts[2];			/* Destination port range. */
-	u_int8_t invflags;			/* Inverse flags */
-};
+#define IP6T_TCP_INV_SRCPT	XT_TCP_INV_SRCPT
+#define IP6T_TCP_INV_DSTPT	XT_TCP_INV_DSTPT
+#define IP6T_TCP_INV_FLAGS	XT_TCP_INV_FLAGS
+#define IP6T_TCP_INV_OPTION	XT_TCP_INV_OPTION
+#define IP6T_TCP_INV_MASK	XT_TCP_INV_MASK
 
 /* Values for "invflags" field in struct ipt_udp. */
-#define IP6T_UDP_INV_SRCPT	0x01	/* Invert the sense of source ports. */
-#define IP6T_UDP_INV_DSTPT	0x02	/* Invert the sense of dest ports. */
-#define IP6T_UDP_INV_MASK	0x03	/* All possible flags. */
+#define IP6T_UDP_INV_SRCPT	XT_UDP_INV_SRCPT
+#define IP6T_UDP_INV_DSTPT	XT_UDP_INV_DSTPT
+#define IP6T_UDP_INV_MASK	XT_UDP_INV_MASK
 
 /* ICMP matching stuff */
 struct ip6t_icmp
@@ -264,23 +255,14 @@
 	/* Number of counters (must be equal to current number of entries). */
 	unsigned int num_counters;
 	/* The old entries' counters. */
-	struct ip6t_counters __user *counters;
+	struct xt_counters __user *counters;
 
 	/* The entries (hang off end: not really an array). */
 	struct ip6t_entry entries[0];
 };
 
 /* The argument to IP6T_SO_ADD_COUNTERS. */
-struct ip6t_counters_info
-{
-	/* Which table. */
-	char name[IP6T_TABLE_MAXNAMELEN];
-
-	unsigned int num_counters;
-
-	/* The counters (actually `number' of these). */
-	struct ip6t_counters counters[0];
-};
+#define ip6t_counters_info xt_counters_info
 
 /* The argument to IP6T_SO_GET_ENTRIES. */
 struct ip6t_get_entries
@@ -295,19 +277,10 @@
 	struct ip6t_entry entrytable[0];
 };
 
-/* The argument to IP6T_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct ip6t_get_revision
-{
-	char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define IP6T_STANDARD_TARGET ""
+#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define IP6T_ERROR_TARGET "ERROR"
+#define IP6T_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct ip6t_entry_target *
@@ -361,104 +334,11 @@
 #include <linux/init.h>
 extern void ip6t_init(void) __init;
 
-struct ip6t_match
-{
-	struct list_head list;
+#define ip6t_register_target(tgt) xt_register_target(AF_INET6, tgt)
+#define ip6t_unregister_target(tgt) xt_unregister_target(AF_INET6, tgt)
 
-	const char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-
-	/* Return true or false: return FALSE and set *hotdrop = 1 to
-           force immediate packet drop. */
-	/* Arguments changed since 2.6.9, as this must now handle
-	   non-linear skb, using skb_header_pointer and
-	   skb_ip_make_writable. */
-	int (*match)(const struct sk_buff *skb,
-		     const struct net_device *in,
-		     const struct net_device *out,
-		     const void *matchinfo,
-		     int offset,
-		     unsigned int protoff,
-		     int *hotdrop);
-
-	/* Called when user tries to insert an entry of this type. */
-	/* Should return true or false. */
-	int (*checkentry)(const char *tablename,
-			  const struct ip6t_ip6 *ip,
-			  void *matchinfo,
-			  unsigned int matchinfosize,
-			  unsigned int hook_mask);
-
-	/* Called when entry of this type deleted. */
-	void (*destroy)(void *matchinfo, unsigned int matchinfosize);
-
-	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
-	struct module *me;
-};
-
-/* Registration hooks for targets. */
-struct ip6t_target
-{
-	struct list_head list;
-
-	const char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-	u_int8_t revision;
-
-	/* Returns verdict. Argument order changed since 2.6.9, as this
-	   must now handle non-linear skbs, using skb_copy_bits and
-	   skb_ip_make_writable. */
-	unsigned int (*target)(struct sk_buff **pskb,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       unsigned int hooknum,
-			       const void *targinfo,
-			       void *userdata);
-
-	/* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-	/* Should return true or false. */
-	int (*checkentry)(const char *tablename,
-			  const struct ip6t_entry *e,
-			  void *targinfo,
-			  unsigned int targinfosize,
-			  unsigned int hook_mask);
-
-	/* Called when entry of this type deleted. */
-	void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
-	struct module *me;
-};
-
-extern int ip6t_register_target(struct ip6t_target *target);
-extern void ip6t_unregister_target(struct ip6t_target *target);
-
-extern int ip6t_register_match(struct ip6t_match *match);
-extern void ip6t_unregister_match(struct ip6t_match *match);
-
-/* Furniture shopping... */
-struct ip6t_table
-{
-	struct list_head list;
-
-	/* A unique name... */
-	char name[IP6T_TABLE_MAXNAMELEN];
-
-	/* What hooks you will enter on */
-	unsigned int valid_hooks;
-
-	/* Lock for the curtain */
-	rwlock_t lock;
-
-	/* Man behind the curtain... */
-	struct ip6t_table_info *private;
-
-	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
-	struct module *me;
-};
+#define ip6t_register_match(match) xt_register_match(AF_INET6, match)
+#define ip6t_unregister_match(match) xt_unregister_match(AF_INET6, match)
 
 extern int ip6t_register_table(struct ip6t_table *table,
 			       const struct ip6t_replace *repl);
diff --git a/include/linux/netfilter_ipv6/ip6t_MARK.h b/include/linux/netfilter_ipv6/ip6t_MARK.h
index 7ade8d8..7cf629a 100644
--- a/include/linux/netfilter_ipv6/ip6t_MARK.h
+++ b/include/linux/netfilter_ipv6/ip6t_MARK.h
@@ -1,8 +1,9 @@
 #ifndef _IP6T_MARK_H_target
 #define _IP6T_MARK_H_target
 
-struct ip6t_mark_target_info {
-	unsigned long mark;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_MARK.h>
 
-#endif /*_IPT_MARK_H_target*/
+#define ip6t_mark_target_info xt_mark_target_info
+
+#endif /*_IP6T_MARK_H_target*/
diff --git a/include/linux/netfilter_ipv6/ip6t_length.h b/include/linux/netfilter_ipv6/ip6t_length.h
index 7fc09f9..9e9689d 100644
--- a/include/linux/netfilter_ipv6/ip6t_length.h
+++ b/include/linux/netfilter_ipv6/ip6t_length.h
@@ -1,10 +1,8 @@
 #ifndef _IP6T_LENGTH_H
 #define _IP6T_LENGTH_H
 
-struct ip6t_length_info {
-	u_int16_t  min, max;
-	u_int8_t   invert;
-};
+#include <linux/netfilter/xt_length.h>
+#define ip6t_length_info xt_length_info
 
 #endif /*_IP6T_LENGTH_H*/
 	
diff --git a/include/linux/netfilter_ipv6/ip6t_limit.h b/include/linux/netfilter_ipv6/ip6t_limit.h
index f2866e5..487e5ea 100644
--- a/include/linux/netfilter_ipv6/ip6t_limit.h
+++ b/include/linux/netfilter_ipv6/ip6t_limit.h
@@ -1,21 +1,8 @@
 #ifndef _IP6T_RATE_H
 #define _IP6T_RATE_H
 
-/* timings are in milliseconds. */
-#define IP6T_LIMIT_SCALE 10000
+#include <linux/netfilter/xt_limit.h>
+#define IP6T_LIMIT_SCALE XT_LIMIT_SCALE
+#define ip6t_rateinfo xt_rateinfo
 
-/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
-   seconds, or one every 59 hours. */
-struct ip6t_rateinfo {
-	u_int32_t avg;    /* Average secs between packets * scale */
-	u_int32_t burst;  /* Period multiplier for upper limit. */
-
-	/* Used internally by the kernel */
-	unsigned long prev;
-	u_int32_t credit;
-	u_int32_t credit_cap, cost;
-
-	/* Ugly, ugly fucker. */
-	struct ip6t_rateinfo *master;
-};
-#endif /*_IPT_RATE_H*/
+#endif /*_IP6T_RATE_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_mac.h b/include/linux/netfilter_ipv6/ip6t_mac.h
index 87c088c..ac58e83 100644
--- a/include/linux/netfilter_ipv6/ip6t_mac.h
+++ b/include/linux/netfilter_ipv6/ip6t_mac.h
@@ -1,8 +1,7 @@
 #ifndef _IP6T_MAC_H
 #define _IP6T_MAC_H
 
-struct ip6t_mac_info {
-    unsigned char srcaddr[ETH_ALEN];
-    int invert;
-};
-#endif /*_IPT_MAC_H*/
+#include <linux/netfilter/xt_mac.h>
+#define ip6t_mac_info xt_mac_info
+
+#endif /*_IP6T_MAC_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_mark.h b/include/linux/netfilter_ipv6/ip6t_mark.h
index a734441..ff20495 100644
--- a/include/linux/netfilter_ipv6/ip6t_mark.h
+++ b/include/linux/netfilter_ipv6/ip6t_mark.h
@@ -1,9 +1,9 @@
 #ifndef _IP6T_MARK_H
 #define _IP6T_MARK_H
 
-struct ip6t_mark_info {
-    unsigned long mark, mask;
-    u_int8_t invert;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_mark.h>
+
+#define ip6t_mark_info xt_mark_info
 
 #endif /*_IPT_MARK_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_physdev.h b/include/linux/netfilter_ipv6/ip6t_physdev.h
index c234731..c161c0a 100644
--- a/include/linux/netfilter_ipv6/ip6t_physdev.h
+++ b/include/linux/netfilter_ipv6/ip6t_physdev.h
@@ -1,24 +1,17 @@
 #ifndef _IP6T_PHYSDEV_H
 #define _IP6T_PHYSDEV_H
 
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
+/* Backwards compatibility for old userspace */
 
-#define IP6T_PHYSDEV_OP_IN		0x01
-#define IP6T_PHYSDEV_OP_OUT		0x02
-#define IP6T_PHYSDEV_OP_BRIDGED		0x04
-#define IP6T_PHYSDEV_OP_ISIN		0x08
-#define IP6T_PHYSDEV_OP_ISOUT		0x10
-#define IP6T_PHYSDEV_OP_MASK		(0x20 - 1)
+#include <linux/netfilter/xt_physdev.h>
 
-struct ip6t_physdev_info {
-	char physindev[IFNAMSIZ];
-	char in_mask[IFNAMSIZ];
-	char physoutdev[IFNAMSIZ];
-	char out_mask[IFNAMSIZ];
-	u_int8_t invert;
-	u_int8_t bitmask;
-};
+#define IP6T_PHYSDEV_OP_IN		XT_PHYSDEV_OP_IN
+#define IP6T_PHYSDEV_OP_OUT		XT_PHYSDEV_OP_OUT
+#define IP6T_PHYSDEV_OP_BRIDGED		XT_PHYSDEV_OP_BRIDGED
+#define IP6T_PHYSDEV_OP_ISIN		XT_PHYSDEV_OP_ISIN
+#define IP6T_PHYSDEV_OP_ISOUT		XT_PHYSDEV_OP_ISOUT
+#define IP6T_PHYSDEV_OP_MASK		XT_PHYSDEV_OP_MASK
+
+#define ip6t_physdev_info xt_physdev_info
 
 #endif /*_IP6T_PHYSDEV_H*/
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 7fb397e..5403257 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -181,6 +181,7 @@
 #define PCI_DEVICE_ID_LSI_FC929X	0x0626
 #define PCI_DEVICE_ID_LSI_FC939X	0x0642
 #define PCI_DEVICE_ID_LSI_FC949X	0x0640
+#define PCI_DEVICE_ID_LSI_FC949ES	0x0646
 #define PCI_DEVICE_ID_LSI_FC919X	0x0628
 #define PCI_DEVICE_ID_NCR_YELLOWFIN	0x0701
 #define PCI_DEVICE_ID_LSI_61C102	0x0901
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 74488e4..aa6322d 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -146,6 +146,11 @@
 extern void proc_device_tree_init(void);
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
 extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
+extern void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
+					 struct property *prop);
+extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
+					 struct property *newprop,
+					 struct property *oldprop);
 #endif /* CONFIG_PROC_DEVICETREE */
 
 extern struct proc_dir_entry *proc_symlink(const char *,
diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
index 48831ea..d0dd38b 100644
--- a/include/linux/raid_class.h
+++ b/include/linux/raid_class.h
@@ -31,9 +31,11 @@
 	RAID_LEVEL_LINEAR,
 	RAID_LEVEL_0,
 	RAID_LEVEL_1,
+	RAID_LEVEL_10,
 	RAID_LEVEL_3,
 	RAID_LEVEL_4,
 	RAID_LEVEL_5,
+	RAID_LEVEL_50,
 	RAID_LEVEL_6,
 };
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a72e171..2df1a1a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -160,6 +160,7 @@
 #define SCHED_NORMAL		0
 #define SCHED_FIFO		1
 #define SCHED_RR		2
+#define SCHED_BATCH		3
 
 struct sched_param {
 	int sched_priority;
@@ -470,9 +471,9 @@
 
 /*
  * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL tasks are
- * in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values
- * are inverted: lower p->prio value means higher priority.
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
  *
  * The MAX_USER_RT_PRIO value allows the actual maximum
  * RT priority to be separate from the value exported to
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index c3e5982..c057f0b 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -26,6 +26,8 @@
 	unsigned long free_blocks;  /* How many are left for allocation */
 	unsigned long max_inodes;   /* How many inodes are allowed */
 	unsigned long free_inodes;  /* How many are left for allocation */
+	int policy;		    /* Default NUMA memory alloc policy */
+	nodemask_t policy_nodes;    /* nodemask for preferred and bind */
 	spinlock_t    stat_lock;
 };
 
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index c415312..621a3d3 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -58,53 +58,6 @@
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
 
-#ifdef DEBUG_SMB_MALLOC
-
-#include <linux/slab.h>
-
-extern int smb_malloced;
-extern int smb_current_vmalloced;
-extern int smb_current_kmalloced;
-
-static inline void *
-smb_vmalloc(unsigned int size)
-{
-        smb_malloced += 1;
-        smb_current_vmalloced += 1;
-        return vmalloc(size);
-}
-
-static inline void
-smb_vfree(void *obj)
-{
-        smb_current_vmalloced -= 1;
-        vfree(obj);
-}
-
-static inline void *
-smb_kmalloc(size_t size, int flags)
-{
-	smb_malloced += 1;
-	smb_current_kmalloced += 1;
-	return kmalloc(size, flags);
-}
-
-static inline void
-smb_kfree(void *obj)
-{
-	smb_current_kmalloced -= 1;
-	kfree(obj);
-}
-
-#else /* DEBUG_SMB_MALLOC */
-
-#define smb_kmalloc(s,p)	kmalloc(s,p)
-#define smb_kfree(o)		kfree(o)
-#define smb_vmalloc(s)		vmalloc(s)
-#define smb_vfree(o)		vfree(o)
-
-#endif /* DEBUG_SMB_MALLOC */
-
 /*
  * Flags for the in-memory inode
  */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 9f40191..b02dda4 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -186,6 +186,7 @@
 #define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
 #define AF_LLC		26	/* Linux LLC			*/
+#define AF_TIPC		30	/* TIPC sockets			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_MAX		32	/* For now.. */
 
@@ -218,6 +219,7 @@
 #define PF_PPPOX	AF_PPPOX
 #define PF_WANPIPE	AF_WANPIPE
 #define PF_LLC		AF_LLC
+#define PF_TIPC		AF_TIPC
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_MAX		AF_MAX
 
@@ -279,6 +281,7 @@
 #define SOL_LLC		268
 #define SOL_DCCP	269
 #define SOL_NETLINK	270
+#define SOL_TIPC	271
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
new file mode 100644
index 0000000..72261e0
--- /dev/null
+++ b/include/linux/spi/ads7846.h
@@ -0,0 +1,18 @@
+/* linux/spi/ads7846.h */
+
+/* Touchscreen characteristics vary between boards and models.  The
+ * platform_data for the device's "struct device" holds this information.
+ *
+ * It's OK if the min/max values are zero.
+ */
+struct ads7846_platform_data {
+	u16	model;			/* 7843, 7845, 7846. */
+	u16	vref_delay_usecs;	/* 0 for external vref; etc */
+	u16	x_plate_ohms;
+	u16	y_plate_ohms;
+
+	u16	x_min, x_max;
+	u16	y_min, y_max;
+	u16	pressure_min, pressure_max;
+};
+
diff --git a/include/linux/spi/flash.h b/include/linux/spi/flash.h
new file mode 100644
index 0000000..3f22932
--- /dev/null
+++ b/include/linux/spi/flash.h
@@ -0,0 +1,31 @@
+#ifndef LINUX_SPI_FLASH_H
+#define LINUX_SPI_FLASH_H
+
+struct mtd_partition;
+
+/**
+ * struct flash_platform_data: board-specific flash data
+ * @name: optional flash device name (eg, as used with mtdparts=)
+ * @parts: optional array of mtd_partitions for static partitioning
+ * @nr_parts: number of mtd_partitions for static partitoning
+ * @type: optional flash device type (e.g. m25p80 vs m25p64), for use
+ *	with chips that can't be queried for JEDEC or other IDs
+ *
+ * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
+ * provide information about SPI flash parts (such as DataFlash) to
+ * help set up the device and its appropriate default partitioning.
+ *
+ * Note that for DataFlash, sizes for pages, blocks, and sectors are
+ * rarely powers of two; and partitions should be sector-aligned.
+ */
+struct flash_platform_data {
+	char		*name;
+	struct mtd_partition *parts;
+	unsigned int	nr_parts;
+
+	char		*type;
+
+	/* we'll likely add more ... use JEDEC IDs, etc */
+};
+
+#endif
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
new file mode 100644
index 0000000..b05f146
--- /dev/null
+++ b/include/linux/spi/spi.h
@@ -0,0 +1,668 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_SPI_H
+#define __LINUX_SPI_H
+
+/*
+ * INTERFACES between SPI master-side drivers and SPI infrastructure.
+ * (There's no SPI slave support for Linux yet...)
+ */
+extern struct bus_type spi_bus_type;
+
+/**
+ * struct spi_device - Master side proxy for an SPI slave device
+ * @dev: Driver model representation of the device.
+ * @master: SPI controller used with the device.
+ * @max_speed_hz: Maximum clock rate to be used with this chip
+ *	(on this board); may be changed by the device's driver.
+ * @chip-select: Chipselect, distinguishing chips handled by "master".
+ * @mode: The spi mode defines how data is clocked out and in.
+ *	This may be changed by the device's driver.
+ * @bits_per_word: Data transfers involve one or more words; word sizes
+ * 	like eight or 12 bits are common.  In-memory wordsizes are
+ *	powers of two bytes (e.g. 20 bit samples use 32 bits).
+ *	This may be changed by the device's driver.
+ * @irq: Negative, or the number passed to request_irq() to receive
+ * 	interrupts from this device.
+ * @controller_state: Controller's runtime state
+ * @controller_data: Board-specific definitions for controller, such as
+ * 	FIFO initialization parameters; from board_info.controller_data
+ *
+ * An spi_device is used to interchange data between an SPI slave
+ * (usually a discrete chip) and CPU memory.
+ *
+ * In "dev", the platform_data is used to hold information about this
+ * device that's meaningful to the device's protocol driver, but not
+ * to its controller.  One example might be an identifier for a chip
+ * variant with slightly different functionality.
+ */
+struct spi_device {
+	struct device		dev;
+	struct spi_master	*master;
+	u32			max_speed_hz;
+	u8			chip_select;
+	u8			mode;
+#define	SPI_CPHA	0x01			/* clock phase */
+#define	SPI_CPOL	0x02			/* clock polarity */
+#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
+#define	SPI_MODE_1	(0|SPI_CPHA)
+#define	SPI_MODE_2	(SPI_CPOL|0)
+#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
+#define	SPI_CS_HIGH	0x04			/* chipselect active high? */
+	u8			bits_per_word;
+	int			irq;
+	void			*controller_state;
+	void			*controller_data;
+	const char		*modalias;
+
+	// likely need more hooks for more protocol options affecting how
+	// the controller talks to each chip, like:
+	//  - bit order (default is wordwise msb-first)
+	//  - memory packing (12 bit samples into low bits, others zeroed)
+	//  - priority
+	//  - drop chipselect after each word
+	//  - chipselect delays
+	//  - ...
+};
+
+static inline struct spi_device *to_spi_device(struct device *dev)
+{
+	return dev ? container_of(dev, struct spi_device, dev) : NULL;
+}
+
+/* most drivers won't need to care about device refcounting */
+static inline struct spi_device *spi_dev_get(struct spi_device *spi)
+{
+	return (spi && get_device(&spi->dev)) ? spi : NULL;
+}
+
+static inline void spi_dev_put(struct spi_device *spi)
+{
+	if (spi)
+		put_device(&spi->dev);
+}
+
+/* ctldata is for the bus_master driver's runtime state */
+static inline void *spi_get_ctldata(struct spi_device *spi)
+{
+	return spi->controller_state;
+}
+
+static inline void spi_set_ctldata(struct spi_device *spi, void *state)
+{
+	spi->controller_state = state;
+}
+
+
+struct spi_message;
+
+
+
+struct spi_driver {
+	int			(*probe)(struct spi_device *spi);
+	int			(*remove)(struct spi_device *spi);
+	void			(*shutdown)(struct spi_device *spi);
+	int			(*suspend)(struct spi_device *spi, pm_message_t mesg);
+	int			(*resume)(struct spi_device *spi);
+	struct device_driver	driver;
+};
+
+static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
+{
+	return drv ? container_of(drv, struct spi_driver, driver) : NULL;
+}
+
+extern int spi_register_driver(struct spi_driver *sdrv);
+
+static inline void spi_unregister_driver(struct spi_driver *sdrv)
+{
+	if (!sdrv)
+		return;
+	driver_unregister(&sdrv->driver);
+}
+
+
+
+/**
+ * struct spi_master - interface to SPI master controller
+ * @cdev: class interface to this driver
+ * @bus_num: board-specific (and often SOC-specific) identifier for a
+ * 	given SPI controller.
+ * @num_chipselect: chipselects are used to distinguish individual
+ * 	SPI slaves, and are numbered from zero to num_chipselects.
+ * 	each slave has a chipselect signal, but it's common that not
+ * 	every chipselect is connected to a slave.
+ * @setup: updates the device mode and clocking records used by a
+ * 	device's SPI controller; protocol code may call this.
+ * @transfer: adds a message to the controller's transfer queue.
+ * @cleanup: frees controller-specific state
+ *
+ * Each SPI master controller can communicate with one or more spi_device
+ * children.  These make a small bus, sharing MOSI, MISO and SCK signals
+ * but not chip select signals.  Each device may be configured to use a
+ * different clock rate, since those shared signals are ignored unless
+ * the chip is selected.
+ *
+ * The driver for an SPI controller manages access to those devices through
+ * a queue of spi_message transactions, copyin data between CPU memory and
+ * an SPI slave device).  For each such message it queues, it calls the
+ * message's completion function when the transaction completes.
+ */
+struct spi_master {
+	struct class_device	cdev;
+
+	/* other than zero (== assign one dynamically), bus_num is fully
+	 * board-specific.  usually that simplifies to being SOC-specific.
+	 * example:  one SOC has three SPI controllers, numbered 1..3,
+	 * and one board's schematics might show it using SPI-2.  software
+	 * would normally use bus_num=2 for that controller.
+	 */
+	u16			bus_num;
+
+	/* chipselects will be integral to many controllers; some others
+	 * might use board-specific GPIOs.
+	 */
+	u16			num_chipselect;
+
+	/* setup mode and clock, etc (spi driver may call many times) */
+	int			(*setup)(struct spi_device *spi);
+
+	/* bidirectional bulk transfers
+	 *
+	 * + The transfer() method may not sleep; its main role is
+	 *   just to add the message to the queue.
+	 * + For now there's no remove-from-queue operation, or
+	 *   any other request management
+	 * + To a given spi_device, message queueing is pure fifo
+	 *
+	 * + The master's main job is to process its message queue,
+	 *   selecting a chip then transferring data
+	 * + If there are multiple spi_device children, the i/o queue
+	 *   arbitration algorithm is unspecified (round robin, fifo,
+	 *   priority, reservations, preemption, etc)
+	 *
+	 * + Chipselect stays active during the entire message
+	 *   (unless modified by spi_transfer.cs_change != 0).
+	 * + The message transfers use clock and SPI mode parameters
+	 *   previously established by setup() for this device
+	 */
+	int			(*transfer)(struct spi_device *spi,
+						struct spi_message *mesg);
+
+	/* called on release() to free memory provided by spi_master */
+	void			(*cleanup)(const struct spi_device *spi);
+};
+
+static inline void *spi_master_get_devdata(struct spi_master *master)
+{
+	return class_get_devdata(&master->cdev);
+}
+
+static inline void spi_master_set_devdata(struct spi_master *master, void *data)
+{
+	class_set_devdata(&master->cdev, data);
+}
+
+static inline struct spi_master *spi_master_get(struct spi_master *master)
+{
+	if (!master || !class_device_get(&master->cdev))
+		return NULL;
+	return master;
+}
+
+static inline void spi_master_put(struct spi_master *master)
+{
+	if (master)
+		class_device_put(&master->cdev);
+}
+
+
+/* the spi driver core manages memory for the spi_master classdev */
+extern struct spi_master *
+spi_alloc_master(struct device *host, unsigned size);
+
+extern int spi_register_master(struct spi_master *master);
+extern void spi_unregister_master(struct spi_master *master);
+
+extern struct spi_master *spi_busnum_to_master(u16 busnum);
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * I/O INTERFACE between SPI controller and protocol drivers
+ *
+ * Protocol drivers use a queue of spi_messages, each transferring data
+ * between the controller and memory buffers.
+ *
+ * The spi_messages themselves consist of a series of read+write transfer
+ * segments.  Those segments always read the same number of bits as they
+ * write; but one or the other is easily ignored by passing a null buffer
+ * pointer.  (This is unlike most types of I/O API, because SPI hardware
+ * is full duplex.)
+ *
+ * NOTE:  Allocation of spi_transfer and spi_message memory is entirely
+ * up to the protocol driver, which guarantees the integrity of both (as
+ * well as the data buffers) for as long as the message is queued.
+ */
+
+/**
+ * struct spi_transfer - a read/write buffer pair
+ * @tx_buf: data to be written (dma-safe memory), or NULL
+ * @rx_buf: data to be read (dma-safe memory), or NULL
+ * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped
+ * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
+ * @len: size of rx and tx buffers (in bytes)
+ * @cs_change: affects chipselect after this transfer completes
+ * @delay_usecs: microseconds to delay after this transfer before
+ * 	(optionally) changing the chipselect status, then starting
+ * 	the next transfer or completing this spi_message.
+ * @transfer_list: transfers are sequenced through spi_message.transfers
+ *
+ * SPI transfers always write the same number of bytes as they read.
+ * Protocol drivers should always provide rx_buf and/or tx_buf.
+ * In some cases, they may also want to provide DMA addresses for
+ * the data being transferred; that may reduce overhead, when the
+ * underlying driver uses dma.
+ *
+ * If the transmit buffer is null, undefined data will be shifted out
+ * while filling rx_buf.  If the receive buffer is null, the data
+ * shifted in will be discarded.  Only "len" bytes shift out (or in).
+ * It's an error to try to shift out a partial word.  (For example, by
+ * shifting out three bytes with word size of sixteen or twenty bits;
+ * the former uses two bytes per word, the latter uses four bytes.)
+ *
+ * All SPI transfers start with the relevant chipselect active.  Normally
+ * it stays selected until after the last transfer in a message.  Drivers
+ * can affect the chipselect signal using cs_change:
+ *
+ * (i) If the transfer isn't the last one in the message, this flag is
+ * used to make the chipselect briefly go inactive in the middle of the
+ * message.  Toggling chipselect in this way may be needed to terminate
+ * a chip command, letting a single spi_message perform all of group of
+ * chip transactions together.
+ *
+ * (ii) When the transfer is the last one in the message, the chip may
+ * stay selected until the next transfer.  This is purely a performance
+ * hint; the controller driver may need to select a different device
+ * for the next message.
+ *
+ * The code that submits an spi_message (and its spi_transfers)
+ * to the lower layers is responsible for managing its memory.
+ * Zero-initialize every field you don't set up explicitly, to
+ * insulate against future API updates.  After you submit a message
+ * and its transfers, ignore them until its completion callback.
+ */
+struct spi_transfer {
+	/* it's ok if tx_buf == rx_buf (right?)
+	 * for MicroWire, one buffer must be null
+	 * buffers must work with dma_*map_single() calls, unless
+	 *   spi_message.is_dma_mapped reports a pre-existing mapping
+	 */
+	const void	*tx_buf;
+	void		*rx_buf;
+	unsigned	len;
+
+	dma_addr_t	tx_dma;
+	dma_addr_t	rx_dma;
+
+	unsigned	cs_change:1;
+	u16		delay_usecs;
+
+	struct list_head transfer_list;
+};
+
+/**
+ * struct spi_message - one multi-segment SPI transaction
+ * @transfers: list of transfer segments in this transaction
+ * @spi: SPI device to which the transaction is queued
+ * @is_dma_mapped: if true, the caller provided both dma and cpu virtual
+ *	addresses for each transfer buffer
+ * @complete: called to report transaction completions
+ * @context: the argument to complete() when it's called
+ * @actual_length: the total number of bytes that were transferred in all
+ *	successful segments
+ * @status: zero for success, else negative errno
+ * @queue: for use by whichever driver currently owns the message
+ * @state: for use by whichever driver currently owns the message
+ *
+ * An spi_message is used to execute an atomic sequence of data transfers,
+ * each represented by a struct spi_transfer.  The sequence is "atomic"
+ * in the sense that no other spi_message may use that SPI bus until that
+ * sequence completes.  On some systems, many such sequences can execute as
+ * as single programmed DMA transfer.  On all systems, these messages are
+ * queued, and might complete after transactions to other devices.  Messages
+ * sent to a given spi_device are alway executed in FIFO order.
+ *
+ * The code that submits an spi_message (and its spi_transfers)
+ * to the lower layers is responsible for managing its memory.
+ * Zero-initialize every field you don't set up explicitly, to
+ * insulate against future API updates.  After you submit a message
+ * and its transfers, ignore them until its completion callback.
+ */
+struct spi_message {
+	struct list_head 	transfers;
+
+	struct spi_device	*spi;
+
+	unsigned		is_dma_mapped:1;
+
+	/* REVISIT:  we might want a flag affecting the behavior of the
+	 * last transfer ... allowing things like "read 16 bit length L"
+	 * immediately followed by "read L bytes".  Basically imposing
+	 * a specific message scheduling algorithm.
+	 *
+	 * Some controller drivers (message-at-a-time queue processing)
+	 * could provide that as their default scheduling algorithm.  But
+	 * others (with multi-message pipelines) could need a flag to
+	 * tell them about such special cases.
+	 */
+
+	/* completion is reported through a callback */
+	void 			(*complete)(void *context);
+	void			*context;
+	unsigned		actual_length;
+	int			status;
+
+	/* for optional use by whatever driver currently owns the
+	 * spi_message ...  between calls to spi_async and then later
+	 * complete(), that's the spi_master controller driver.
+	 */
+	struct list_head	queue;
+	void			*state;
+};
+
+static inline void spi_message_init(struct spi_message *m)
+{
+	memset(m, 0, sizeof *m);
+	INIT_LIST_HEAD(&m->transfers);
+}
+
+static inline void
+spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
+{
+	list_add_tail(&t->transfer_list, &m->transfers);
+}
+
+static inline void
+spi_transfer_del(struct spi_transfer *t)
+{
+	list_del(&t->transfer_list);
+}
+
+/* It's fine to embed message and transaction structures in other data
+ * structures so long as you don't free them while they're in use.
+ */
+
+static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags)
+{
+	struct spi_message *m;
+
+	m = kzalloc(sizeof(struct spi_message)
+			+ ntrans * sizeof(struct spi_transfer),
+			flags);
+	if (m) {
+		int i;
+		struct spi_transfer *t = (struct spi_transfer *)(m + 1);
+
+		INIT_LIST_HEAD(&m->transfers);
+		for (i = 0; i < ntrans; i++, t++)
+			spi_message_add_tail(t, m);
+	}
+	return m;
+}
+
+static inline void spi_message_free(struct spi_message *m)
+{
+	kfree(m);
+}
+
+/**
+ * spi_setup -- setup SPI mode and clock rate
+ * @spi: the device whose settings are being modified
+ *
+ * SPI protocol drivers may need to update the transfer mode if the
+ * device doesn't work with the mode 0 default.  They may likewise need
+ * to update clock rates or word sizes from initial values.  This function
+ * changes those settings, and must be called from a context that can sleep.
+ * The changes take effect the next time the device is selected and data
+ * is transferred to or from it.
+ */
+static inline int
+spi_setup(struct spi_device *spi)
+{
+	return spi->master->setup(spi);
+}
+
+
+/**
+ * spi_async -- asynchronous SPI transfer
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers, including completion callback
+ *
+ * This call may be used in_irq and other contexts which can't sleep,
+ * as well as from task contexts which can sleep.
+ *
+ * The completion callback is invoked in a context which can't sleep.
+ * Before that invocation, the value of message->status is undefined.
+ * When the callback is issued, message->status holds either zero (to
+ * indicate complete success) or a negative error code.  After that
+ * callback returns, the driver which issued the transfer request may
+ * deallocate the associated memory; it's no longer in use by any SPI
+ * core or controller driver code.
+ *
+ * Note that although all messages to a spi_device are handled in
+ * FIFO order, messages may go to different devices in other orders.
+ * Some device might be higher priority, or have various "hard" access
+ * time requirements, for example.
+ *
+ * On detection of any fault during the transfer, processing of
+ * the entire message is aborted, and the device is deselected.
+ * Until returning from the associated message completion callback,
+ * no other spi_message queued to that device will be processed.
+ * (This rule applies equally to all the synchronous transfer calls,
+ * which are wrappers around this core asynchronous primitive.)
+ */
+static inline int
+spi_async(struct spi_device *spi, struct spi_message *message)
+{
+	message->spi = spi;
+	return spi->master->transfer(spi, message);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* All these synchronous SPI transfer routines are utilities layered
+ * over the core async transfer primitive.  Here, "synchronous" means
+ * they will sleep uninterruptibly until the async transfer completes.
+ */
+
+extern int spi_sync(struct spi_device *spi, struct spi_message *message);
+
+/**
+ * spi_write - SPI synchronous write
+ * @spi: device to which data will be written
+ * @buf: data buffer
+ * @len: data buffer size
+ *
+ * This writes the buffer and returns zero or a negative error code.
+ * Callable only from contexts that can sleep.
+ */
+static inline int
+spi_write(struct spi_device *spi, const u8 *buf, size_t len)
+{
+	struct spi_transfer	t = {
+			.tx_buf		= buf,
+			.len		= len,
+		};
+	struct spi_message	m;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+	return spi_sync(spi, &m);
+}
+
+/**
+ * spi_read - SPI synchronous read
+ * @spi: device from which data will be read
+ * @buf: data buffer
+ * @len: data buffer size
+ *
+ * This writes the buffer and returns zero or a negative error code.
+ * Callable only from contexts that can sleep.
+ */
+static inline int
+spi_read(struct spi_device *spi, u8 *buf, size_t len)
+{
+	struct spi_transfer	t = {
+			.rx_buf		= buf,
+			.len		= len,
+		};
+	struct spi_message	m;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+	return spi_sync(spi, &m);
+}
+
+/* this copies txbuf and rxbuf data; for small transfers only! */
+extern int spi_write_then_read(struct spi_device *spi,
+		const u8 *txbuf, unsigned n_tx,
+		u8 *rxbuf, unsigned n_rx);
+
+/**
+ * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
+ * @spi: device with which data will be exchanged
+ * @cmd: command to be written before data is read back
+ *
+ * This returns the (unsigned) eight bit number returned by the
+ * device, or else a negative error code.  Callable only from
+ * contexts that can sleep.
+ */
+static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
+{
+	ssize_t			status;
+	u8			result;
+
+	status = spi_write_then_read(spi, &cmd, 1, &result, 1);
+
+	/* return negative errno or unsigned value */
+	return (status < 0) ? status : result;
+}
+
+/**
+ * spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read
+ * @spi: device with which data will be exchanged
+ * @cmd: command to be written before data is read back
+ *
+ * This returns the (unsigned) sixteen bit number returned by the
+ * device, or else a negative error code.  Callable only from
+ * contexts that can sleep.
+ *
+ * The number is returned in wire-order, which is at least sometimes
+ * big-endian.
+ */
+static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
+{
+	ssize_t			status;
+	u16			result;
+
+	status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);
+
+	/* return negative errno or unsigned value */
+	return (status < 0) ? status : result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * INTERFACE between board init code and SPI infrastructure.
+ *
+ * No SPI driver ever sees these SPI device table segments, but
+ * it's how the SPI core (or adapters that get hotplugged) grows
+ * the driver model tree.
+ *
+ * As a rule, SPI devices can't be probed.  Instead, board init code
+ * provides a table listing the devices which are present, with enough
+ * information to bind and set up the device's driver.  There's basic
+ * support for nonstatic configurations too; enough to handle adding
+ * parport adapters, or microcontrollers acting as USB-to-SPI bridges.
+ */
+
+/* board-specific information about each SPI device */
+struct spi_board_info {
+	/* the device name and module name are coupled, like platform_bus;
+	 * "modalias" is normally the driver name.
+	 *
+	 * platform_data goes to spi_device.dev.platform_data,
+	 * controller_data goes to spi_device.controller_data,
+	 * irq is copied too
+	 */
+	char		modalias[KOBJ_NAME_LEN];
+	const void	*platform_data;
+	void		*controller_data;
+	int		irq;
+
+	/* slower signaling on noisy or low voltage boards */
+	u32		max_speed_hz;
+
+
+	/* bus_num is board specific and matches the bus_num of some
+	 * spi_master that will probably be registered later.
+	 *
+	 * chip_select reflects how this chip is wired to that master;
+	 * it's less than num_chipselect.
+	 */
+	u16		bus_num;
+	u16		chip_select;
+
+	/* ... may need additional spi_device chip config data here.
+	 * avoid stuff protocol drivers can set; but include stuff
+	 * needed to behave without being bound to a driver:
+	 *  - chipselect polarity
+	 *  - quirks like clock rate mattering when not selected
+	 */
+};
+
+#ifdef	CONFIG_SPI
+extern int
+spi_register_board_info(struct spi_board_info const *info, unsigned n);
+#else
+/* board init code may ignore whether SPI is configured or not */
+static inline int
+spi_register_board_info(struct spi_board_info const *info, unsigned n)
+	{ return 0; }
+#endif
+
+
+/* If you're hotplugging an adapter with devices (parport, usb, etc)
+ * use spi_new_device() to describe each device.  You can also call
+ * spi_unregister_device() to start making that device vanish, but
+ * normally that would be handled by spi_unregister_master().
+ */
+extern struct spi_device *
+spi_new_device(struct spi_master *, struct spi_board_info *);
+
+static inline void
+spi_unregister_device(struct spi_device *spi)
+{
+	if (spi)
+		device_unregister(&spi->dev);
+}
+
+#endif /* __LINUX_SPI_H */
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
new file mode 100644
index 0000000..c961fe9
--- /dev/null
+++ b/include/linux/spi/spi_bitbang.h
@@ -0,0 +1,135 @@
+#ifndef	__SPI_BITBANG_H
+#define	__SPI_BITBANG_H
+
+/*
+ * Mix this utility code with some glue code to get one of several types of
+ * simple SPI master driver.  Two do polled word-at-a-time I/O:
+ *
+ *   -	GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](),
+ *	expanding the per-word routines from the inline templates below.
+ *
+ *   -	Drivers for controllers resembling bare shift registers.  Provide
+ *	chipselect() and txrx_word[](), with custom setup()/cleanup() methods
+ *	that use your controller's clock and chipselect registers.
+ *
+ * Some hardware works well with requests at spi_transfer scope:
+ *
+ *   -	Drivers leveraging smarter hardware, with fifos or DMA; or for half
+ *	duplex (MicroWire) controllers.  Provide chipslect() and txrx_bufs(),
+ *	and custom setup()/cleanup() methods.
+ */
+struct spi_bitbang {
+	struct workqueue_struct	*workqueue;
+	struct work_struct	work;
+
+	spinlock_t		lock;
+	struct list_head	queue;
+	u8			busy;
+	u8			shutdown;
+	u8			use_dma;
+
+	struct spi_master	*master;
+
+	void	(*chipselect)(struct spi_device *spi, int is_on);
+#define	BITBANG_CS_ACTIVE	1	/* normally nCS, active low */
+#define	BITBANG_CS_INACTIVE	0
+
+	/* txrx_bufs() may handle dma mapping for transfers that don't
+	 * already have one (transfer.{tx,rx}_dma is zero), or use PIO
+	 */
+	int	(*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
+
+	/* txrx_word[SPI_MODE_*]() just looks like a shift register */
+	u32	(*txrx_word[4])(struct spi_device *spi,
+			unsigned nsecs,
+			u32 word, u8 bits);
+};
+
+/* you can call these default bitbang->master methods from your custom
+ * methods, if you like.
+ */
+extern int spi_bitbang_setup(struct spi_device *spi);
+extern void spi_bitbang_cleanup(const struct spi_device *spi);
+extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
+
+/* start or stop queue processing */
+extern int spi_bitbang_start(struct spi_bitbang *spi);
+extern int spi_bitbang_stop(struct spi_bitbang *spi);
+
+#endif	/* __SPI_BITBANG_H */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	EXPAND_BITBANG_TXRX
+
+/*
+ * The code that knows what GPIO pins do what should have declared four
+ * functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX
+ * and including this header:
+ *
+ *  void setsck(struct spi_device *, int is_on);
+ *  void setmosi(struct spi_device *, int is_on);
+ *  int getmiso(struct spi_device *);
+ *  void spidelay(unsigned);
+ *
+ * A non-inlined routine would call bitbang_txrx_*() routines.  The
+ * main loop could easily compile down to a handful of instructions,
+ * especially if the delay is a NOP (to run at peak speed).
+ *
+ * Since this is software, the timings may not be exactly what your board's
+ * chips need ... there may be several reasons you'd need to tweak timings
+ * in these routines, not just make to make it faster or slower to match a
+ * particular CPU clock rate.
+ */
+
+static inline u32
+bitbang_txrx_be_cpha0(struct spi_device *spi,
+		unsigned nsecs, unsigned cpol,
+		u32 word, u8 bits)
+{
+	/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
+
+	/* clock starts at inactive polarity */
+	for (word <<= (32 - bits); likely(bits); bits--) {
+
+		/* setup MSB (to slave) on trailing edge */
+		setmosi(spi, word & (1 << 31));
+		spidelay(nsecs);	/* T(setup) */
+
+		setsck(spi, !cpol);
+		spidelay(nsecs);
+
+		/* sample MSB (from slave) on leading edge */
+		word <<= 1;
+		word |= getmiso(spi);
+		setsck(spi, cpol);
+	}
+	return word;
+}
+
+static inline u32
+bitbang_txrx_be_cpha1(struct spi_device *spi,
+		unsigned nsecs, unsigned cpol,
+		u32 word, u8 bits)
+{
+	/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
+
+	/* clock starts at inactive polarity */
+	for (word <<= (32 - bits); likely(bits); bits--) {
+
+		/* setup MSB (to slave) on leading edge */
+		setsck(spi, !cpol);
+		setmosi(spi, word & (1 << 31));
+		spidelay(nsecs); /* T(setup) */
+
+		setsck(spi, cpol);
+		spidelay(nsecs);
+
+		/* sample MSB (from slave) on trailing edge */
+		word <<= 1;
+		word |= getmiso(spi);
+	}
+	return word;
+}
+
+#endif	/* EXPAND_BITBANG_TXRX */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 389d1c3..e92054d 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -180,6 +180,11 @@
 extern int putback_lru_pages(struct list_head *l);
 extern int migrate_pages(struct list_head *l, struct list_head *t,
 		struct list_head *moved, struct list_head *failed);
+#else
+static inline int isolate_lru_page(struct page *p) { return -ENOSYS; }
+static inline int putback_lru_pages(struct list_head *l) { return 0; }
+static inline int migrate_pages(struct list_head *l, struct list_head *t,
+	struct list_head *moved, struct list_head *failed) { return -ENOSYS; }
 #endif
 
 #ifdef CONFIG_MMU
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
new file mode 100644
index 0000000..243a15f
--- /dev/null
+++ b/include/linux/tipc.h
@@ -0,0 +1,212 @@
+/*
+ * include/linux/tipc.h: Include file for TIPC socket interface
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_TIPC_H_
+#define _LINUX_TIPC_H_
+
+#include <linux/types.h>
+
+/*
+ * TIPC addressing primitives
+ */
+ 
+struct tipc_portid {
+	__u32 ref;
+	__u32 node;
+};
+
+struct tipc_name {
+	__u32 type;
+	__u32 instance;
+};
+
+struct tipc_name_seq {
+	__u32 type;
+	__u32 lower;
+	__u32 upper;
+};
+
+static inline __u32 tipc_addr(unsigned int zone,
+			      unsigned int cluster,
+			      unsigned int node)
+{
+	return (zone << 24) | (cluster << 12) | node;
+}
+
+static inline unsigned int tipc_zone(__u32 addr)
+{
+	return addr >> 24;
+}
+
+static inline unsigned int tipc_cluster(__u32 addr)
+{
+	return (addr >> 12) & 0xfff;
+}
+
+static inline unsigned int tipc_node(__u32 addr)
+{
+	return addr & 0xfff;
+}
+
+/*
+ * Application-accessible port name types
+ */
+
+#define TIPC_CFG_SRV		0	/* configuration service name type */
+#define TIPC_TOP_SRV		1	/* topology service name type */
+#define TIPC_RESERVED_TYPES	64	/* lowest user-publishable name type */
+
+/* 
+ * Publication scopes when binding port names and port name sequences
+ */
+
+#define TIPC_ZONE_SCOPE		1
+#define TIPC_CLUSTER_SCOPE	2
+#define TIPC_NODE_SCOPE		3
+
+/*
+ * Limiting values for messages
+ */
+
+#define TIPC_MAX_USER_MSG_SIZE	66000
+
+/*
+ * Message importance levels
+ */
+
+#define TIPC_LOW_IMPORTANCE		0  /* default */
+#define TIPC_MEDIUM_IMPORTANCE		1
+#define TIPC_HIGH_IMPORTANCE		2
+#define TIPC_CRITICAL_IMPORTANCE	3
+
+/* 
+ * Msg rejection/connection shutdown reasons
+ */
+
+#define TIPC_OK			0
+#define TIPC_ERR_NO_NAME	1
+#define TIPC_ERR_NO_PORT	2
+#define TIPC_ERR_NO_NODE	3
+#define TIPC_ERR_OVERLOAD	4
+#define TIPC_CONN_SHUTDOWN	5
+
+/*
+ * TIPC topology subscription service definitions
+ */
+
+#define TIPC_SUB_PORTS     	0x01  	/* filter for port availability */
+#define TIPC_SUB_SERVICE     	0x02  	/* filter for service availability */
+#if 0
+/* The following filter options are not currently implemented */
+#define TIPC_SUB_NO_BIND_EVTS	0x04	/* filter out "publish" events */
+#define TIPC_SUB_NO_UNBIND_EVTS	0x08	/* filter out "withdraw" events */
+#define TIPC_SUB_SINGLE_EVT	0x10	/* expire after first event */
+#endif
+
+#define TIPC_WAIT_FOREVER	~0	/* timeout for permanent subscription */
+
+struct tipc_subscr {
+	struct tipc_name_seq seq;	/* name sequence of interest */
+	__u32 timeout;			/* subscription duration (in ms) */
+        __u32 filter;   		/* bitmask of filter options */
+	char usr_handle[8];		/* available for subscriber use */
+};
+
+#define TIPC_PUBLISHED		1	/* publication event */
+#define TIPC_WITHDRAWN		2	/* withdraw event */
+#define TIPC_SUBSCR_TIMEOUT	3	/* subscription timeout event */
+
+struct tipc_event {
+	__u32 event;			/* event type */
+	__u32 found_lower;		/* matching name seq instances */
+	__u32 found_upper;		/*    "      "    "     "      */
+	struct tipc_portid port;	/* associated port */
+	struct tipc_subscr s;		/* associated subscription */
+};
+
+/*
+ * Socket API
+ */
+
+#ifndef AF_TIPC
+#define AF_TIPC		30
+#endif
+
+#ifndef PF_TIPC
+#define PF_TIPC		AF_TIPC
+#endif
+
+#ifndef SOL_TIPC
+#define SOL_TIPC	271
+#endif
+
+#define TIPC_ADDR_NAMESEQ	1
+#define TIPC_ADDR_MCAST		1
+#define TIPC_ADDR_NAME		2
+#define TIPC_ADDR_ID		3
+
+struct sockaddr_tipc {
+	unsigned short family;
+	unsigned char  addrtype;
+	signed   char  scope;
+	union {
+		struct tipc_portid id;
+		struct tipc_name_seq nameseq;
+		struct {
+			struct tipc_name name;
+			__u32 domain; /* 0: own zone */
+		} name;
+	} addr;
+};
+
+/*
+ * Ancillary data objects supported by recvmsg()
+ */
+
+#define TIPC_ERRINFO	1	/* error info */
+#define TIPC_RETDATA	2	/* returned data */
+#define TIPC_DESTNAME	3	/* destination name */
+
+/*
+ * TIPC-specific socket option values
+ */
+
+#define TIPC_IMPORTANCE		127	/* Default: TIPC_LOW_IMPORTANCE */
+#define TIPC_SRC_DROPPABLE	128	/* Default: 0 (resend congested msg) */
+#define TIPC_DEST_DROPPABLE	129	/* Default: based on socket type */
+#define TIPC_CONN_TIMEOUT	130	/* Default: 8000 (ms)  */
+
+#endif
diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h
new file mode 100644
index 0000000..a52c8c6
--- /dev/null
+++ b/include/linux/tipc_config.h
@@ -0,0 +1,407 @@
+/*
+ * include/linux/tipc_config.h: Include file for TIPC configuration interface
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_TIPC_CONFIG_H_
+#define _LINUX_TIPC_CONFIG_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+/*
+ * Configuration
+ *
+ * All configuration management messaging involves sending a request message
+ * to the TIPC configuration service on a node, which sends a reply message
+ * back.  (In the future multi-message replies may be supported.)
+ *
+ * Both request and reply messages consist of a transport header and payload.
+ * The transport header contains info about the desired operation;
+ * the payload consists of zero or more type/length/value (TLV) items
+ * which specify parameters or results for the operation.
+ *
+ * For many operations, the request and reply messages have a fixed number
+ * of TLVs (usually zero or one); however, some reply messages may return 
+ * a variable number of TLVs.  A failed request is denoted by the presence
+ * of an "error string" TLV in the reply message instead of the TLV(s) the
+ * reply should contain if the request succeeds.
+ */
+ 
+/* 
+ * Public commands:
+ * May be issued by any process.
+ * Accepted by own node, or by remote node only if remote management enabled.                       
+ */
+ 
+#define  TIPC_CMD_NOOP   	    0x0000    /* tx none, rx none */
+#define  TIPC_CMD_GET_NODES         0x0001    /* tx net_addr, rx node_info(s) */
+#define  TIPC_CMD_GET_MEDIA_NAMES   0x0002    /* tx none, rx media_name(s) */
+#define  TIPC_CMD_GET_BEARER_NAMES  0x0003    /* tx none, rx bearer_name(s) */
+#define  TIPC_CMD_GET_LINKS         0x0004    /* tx net_addr, rx link_info(s) */
+#define  TIPC_CMD_SHOW_NAME_TABLE   0x0005    /* tx name_tbl_query, rx ultra_string */
+#define  TIPC_CMD_SHOW_PORTS        0x0006    /* tx none, rx ultra_string */
+#define  TIPC_CMD_SHOW_LINK_STATS   0x000B    /* tx link_name, rx ultra_string */
+
+#if 0
+#define  TIPC_CMD_SHOW_PORT_STATS   0x0008    /* tx port_ref, rx ultra_string */
+#define  TIPC_CMD_RESET_PORT_STATS  0x0009    /* tx port_ref, rx none */
+#define  TIPC_CMD_GET_ROUTES        0x000A    /* tx ?, rx ? */
+#define  TIPC_CMD_GET_LINK_PEER     0x000D    /* tx link_name, rx ? */
+#endif
+
+/* 
+ * Protected commands:
+ * May only be issued by "network administration capable" process.
+ * Accepted by own node, or by remote node only if remote management enabled
+ * and this node is zone manager.                       
+ */
+
+#define  TIPC_CMD_GET_REMOTE_MNG    0x4003    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_PORTS     0x4004    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_PUBL      0x4005    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_SUBSCR    0x4006    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_ZONES     0x4007    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_CLUSTERS  0x4008    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_NODES     0x4009    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_SLAVES    0x400A    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_NETID         0x400B    /* tx none, rx unsigned */
+
+#define  TIPC_CMD_ENABLE_BEARER     0x4101    /* tx bearer_config, rx none */
+#define  TIPC_CMD_DISABLE_BEARER    0x4102    /* tx bearer_name, rx none */
+#define  TIPC_CMD_SET_LINK_TOL      0x4107    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LINK_PRI      0x4108    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LINK_WINDOW   0x4109    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LOG_SIZE      0x410A    /* tx unsigned, rx none */
+#define  TIPC_CMD_DUMP_LOG          0x410B    /* tx none, rx ultra_string */
+#define  TIPC_CMD_RESET_LINK_STATS  0x410C    /* tx link_name, rx none */
+
+#if 0
+#define  TIPC_CMD_CREATE_LINK       0x4103    /* tx link_create, rx none */
+#define  TIPC_CMD_REMOVE_LINK       0x4104    /* tx link_name, rx none */
+#define  TIPC_CMD_BLOCK_LINK        0x4105    /* tx link_name, rx none */
+#define  TIPC_CMD_UNBLOCK_LINK      0x4106    /* tx link_name, rx none */
+#endif
+
+/* 
+ * Private commands:
+ * May only be issued by "network administration capable" process.
+ * Accepted by own node only; cannot be used on a remote node.                       
+ */
+
+#define  TIPC_CMD_SET_NODE_ADDR     0x8001    /* tx net_addr, rx none */
+#if 0
+#define  TIPC_CMD_SET_ZONE_MASTER   0x8002    /* tx none, rx none */
+#endif
+#define  TIPC_CMD_SET_REMOTE_MNG    0x8003    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_PORTS     0x8004    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_PUBL      0x8005    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_SUBSCR    0x8006    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_ZONES     0x8007    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_CLUSTERS  0x8008    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_NODES     0x8009    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_SLAVES    0x800A    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_NETID         0x800B    /* tx unsigned, rx none */
+
+/*
+ * TLV types defined for TIPC
+ */
+
+#define TIPC_TLV_NONE		0	/* no TLV present */
+#define TIPC_TLV_VOID		1	/* empty TLV (0 data bytes)*/
+#define TIPC_TLV_UNSIGNED	2	/* 32-bit integer */
+#define TIPC_TLV_STRING		3	/* char[128] (max) */
+#define TIPC_TLV_LARGE_STRING	4	/* char[2048] (max) */
+#define TIPC_TLV_ULTRA_STRING	5	/* char[32768] (max) */
+
+#define TIPC_TLV_ERROR_STRING	16	/* char[128] containing "error code" */
+#define TIPC_TLV_NET_ADDR   	17	/* 32-bit integer denoting <Z.C.N> */
+#define TIPC_TLV_MEDIA_NAME	18	/* char[TIPC_MAX_MEDIA_NAME] */
+#define TIPC_TLV_BEARER_NAME	19	/* char[TIPC_MAX_BEARER_NAME] */
+#define TIPC_TLV_LINK_NAME	20	/* char[TIPC_MAX_LINK_NAME] */
+#define TIPC_TLV_NODE_INFO	21	/* struct tipc_node_info */
+#define TIPC_TLV_LINK_INFO	22	/* struct tipc_link_info */
+#define TIPC_TLV_BEARER_CONFIG  23	/* struct tipc_bearer_config */
+#define TIPC_TLV_LINK_CONFIG    24	/* struct tipc_link_config */
+#define TIPC_TLV_NAME_TBL_QUERY	25	/* struct tipc_name_table_query */
+#define TIPC_TLV_PORT_REF   	26	/* 32-bit port reference */
+
+/*
+ * Maximum sizes of TIPC bearer-related names (including terminating NUL)
+ */ 
+
+#define TIPC_MAX_MEDIA_NAME	16	/* format = media */
+#define TIPC_MAX_IF_NAME	16	/* format = interface */
+#define TIPC_MAX_BEARER_NAME	32	/* format = media:interface */
+#define TIPC_MAX_LINK_NAME	60	/* format = Z.C.N:interface-Z.C.N:interface */
+
+/*
+ * Link priority limits (range from 0 to # priorities - 1)
+ */
+
+#define TIPC_NUM_LINK_PRI 32
+
+/*
+ * Link tolerance limits (min, default, max), in ms
+ */
+
+#define TIPC_MIN_LINK_TOL 50
+#define TIPC_DEF_LINK_TOL 1500
+#define TIPC_MAX_LINK_TOL 30000
+
+/*
+ * Link window limits (min, default, max), in packets
+ */
+
+#define TIPC_MIN_LINK_WIN 16
+#define TIPC_DEF_LINK_WIN 50
+#define TIPC_MAX_LINK_WIN 150
+
+
+struct tipc_node_info {
+	__u32 addr;			/* network address of node */
+	__u32 up;			/* 0=down, 1= up */
+};
+
+struct tipc_link_info {
+	__u32 dest;			/* network address of peer node */
+	__u32 up;			/* 0=down, 1=up */
+	char str[TIPC_MAX_LINK_NAME];	/* link name */
+};
+
+struct tipc_bearer_config {
+	__u32 priority;			/* Range [1,31]. Override per link  */
+	__u32 detect_scope;     
+	char name[TIPC_MAX_BEARER_NAME];
+};
+
+struct tipc_link_config {
+	__u32 value;
+	char name[TIPC_MAX_LINK_NAME];
+};
+
+#define TIPC_NTQ_ALLTYPES 0x80000000
+
+struct tipc_name_table_query {
+	__u32 depth;	/* 1:type, 2:+name info, 3:+port info, 4+:+debug info */
+	__u32 type;	/* {t,l,u} info ignored if high bit of "depth" is set */
+	__u32 lowbound; /* (i.e. displays all entries of name table) */
+	__u32 upbound;
+};
+
+/*
+ * The error string TLV is a null-terminated string describing the cause 
+ * of the request failure.  To simplify error processing (and to save space)
+ * the first character of the string can be a special error code character
+ * (lying by the range 0x80 to 0xFF) which represents a pre-defined reason.
+ */
+
+#define TIPC_CFG_TLV_ERROR      "\x80"  /* request contains incorrect TLV(s) */
+#define TIPC_CFG_NOT_NET_ADMIN  "\x81"	/* must be network administrator */
+#define TIPC_CFG_NOT_ZONE_MSTR	"\x82"	/* must be zone master */
+#define TIPC_CFG_NO_REMOTE	"\x83"	/* remote management not enabled */
+#define TIPC_CFG_NOT_SUPPORTED  "\x84"	/* request is not supported by TIPC */
+#define TIPC_CFG_INVALID_VALUE  "\x85"  /* request has invalid argument value */
+
+#if 0
+/* prototypes TLV structures for proposed commands */
+struct tipc_link_create {
+	__u32   domain;
+	struct tipc_media_addr peer_addr;
+	char bearer_name[TIPC_MAX_BEARER_NAME];
+};
+
+struct tipc_route_info {
+	__u32 dest;
+	__u32 router;
+};
+#endif
+
+/*
+ * A TLV consists of a descriptor, followed by the TLV value.
+ * TLV descriptor fields are stored in network byte order; 
+ * TLV values must also be stored in network byte order (where applicable).
+ * TLV descriptors must be aligned to addresses which are multiple of 4,
+ * so up to 3 bytes of padding may exist at the end of the TLV value area.
+ * There must not be any padding between the TLV descriptor and its value.
+ */
+
+struct tlv_desc {
+	__u16 tlv_len;		/* TLV length (descriptor + value) */
+	__u16 tlv_type;		/* TLV identifier */
+};
+
+#define TLV_ALIGNTO 4
+
+#define TLV_ALIGN(datalen) (((datalen)+(TLV_ALIGNTO-1)) & ~(TLV_ALIGNTO-1))
+#define TLV_LENGTH(datalen) (sizeof(struct tlv_desc) + (datalen))
+#define TLV_SPACE(datalen) (TLV_ALIGN(TLV_LENGTH(datalen)))
+#define TLV_DATA(tlv) ((void *)((char *)(tlv) + TLV_LENGTH(0)))
+
+static inline int TLV_OK(const void *tlv, __u16 space)
+{
+	/*
+	 * Would also like to check that "tlv" is a multiple of 4,
+	 * but don't know how to do this in a portable way.
+	 * - Tried doing (!(tlv & (TLV_ALIGNTO-1))), but GCC compiler
+	 *   won't allow binary "&" with a pointer.
+	 * - Tried casting "tlv" to integer type, but causes warning about size
+	 *   mismatch when pointer is bigger than chosen type (int, long, ...).
+	 */
+
+	return (space >= TLV_SPACE(0)) &&
+		(ntohs(((struct tlv_desc *)tlv)->tlv_len) <= space);
+}
+
+static inline int TLV_CHECK(const void *tlv, __u16 space, __u16 exp_type)
+{
+	return TLV_OK(tlv, space) && 
+		(ntohs(((struct tlv_desc *)tlv)->tlv_type) == exp_type);
+}
+
+static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
+{
+	struct tlv_desc *tlv_ptr;
+	int tlv_len;
+
+	tlv_len = TLV_LENGTH(len);
+	tlv_ptr = (struct tlv_desc *)tlv;
+	tlv_ptr->tlv_type = htons(type);
+	tlv_ptr->tlv_len  = htons(tlv_len);
+	if (len && data)
+		memcpy(TLV_DATA(tlv_ptr), data, tlv_len);
+	return TLV_SPACE(len);
+}
+
+/*
+ * A TLV list descriptor simplifies processing of messages 
+ * containing multiple TLVs.
+ */
+
+struct tlv_list_desc {
+	struct tlv_desc *tlv_ptr;	/* ptr to current TLV */
+	__u32 tlv_space;		/* # bytes from curr TLV to list end */
+};
+
+static inline void TLV_LIST_INIT(struct tlv_list_desc *list, 
+				 void *data, __u32 space)
+{
+	list->tlv_ptr = (struct tlv_desc *)data;
+	list->tlv_space = space;
+}
+	     
+static inline int TLV_LIST_EMPTY(struct tlv_list_desc *list)
+{ 
+	return (list->tlv_space == 0);
+}
+
+static inline int TLV_LIST_CHECK(struct tlv_list_desc *list, __u16 exp_type)
+{
+	return TLV_CHECK(list->tlv_ptr, list->tlv_space, exp_type);
+}
+
+static inline void *TLV_LIST_DATA(struct tlv_list_desc *list)
+{
+	return TLV_DATA(list->tlv_ptr);
+}
+
+static inline void TLV_LIST_STEP(struct tlv_list_desc *list)
+{
+	__u16 tlv_space = TLV_ALIGN(ntohs(list->tlv_ptr->tlv_len));
+
+        list->tlv_ptr = (struct tlv_desc *)((char *)list->tlv_ptr + tlv_space);
+	list->tlv_space -= tlv_space;
+}
+
+/*
+ * Configuration messages exchanged via NETLINK_GENERIC use the following
+ * family id, name, version and command.
+ */
+#define TIPC_GENL_NAME		"TIPC"
+#define TIPC_GENL_VERSION	0x1
+#define TIPC_GENL_CMD		0x1
+
+/*
+ * TIPC specific header used in NETLINK_GENERIC requests.
+ */
+struct tipc_genlmsghdr {
+	__u32 dest;		/* Destination address */
+	__u16 cmd;		/* Command */
+	__u16 reserved;		/* Unused */
+};
+
+#define TIPC_GENL_HDRLEN	NLMSG_ALIGN(sizeof(struct tipc_genlmsghdr))
+
+/*
+ * Configuration messages exchanged via TIPC sockets use the TIPC configuration 
+ * message header, which is defined below.  This structure is analogous 
+ * to the Netlink message header, but fields are stored in network byte order 
+ * and no padding is permitted between the header and the message data 
+ * that follows.
+ */
+
+struct tipc_cfg_msg_hdr
+{
+	__u32 tcm_len;		/* Message length (including header) */
+	__u16 tcm_type;		/* Command type */
+	__u16 tcm_flags;	/* Additional flags */
+	char  tcm_reserved[8];	/* Unused */
+};
+
+#define TCM_F_REQUEST	0x1	/* Flag: Request message */
+#define TCM_F_MORE	0x2	/* Flag: Message to be continued */
+
+#define TCM_ALIGN(datalen)  (((datalen)+3) & ~3)
+#define TCM_LENGTH(datalen) (sizeof(struct tipc_cfg_msg_hdr) + datalen)
+#define TCM_SPACE(datalen)  (TCM_ALIGN(TCM_LENGTH(datalen)))
+#define TCM_DATA(tcm_hdr)   ((void *)((char *)(tcm_hdr) + TCM_LENGTH(0)))
+
+static inline int TCM_SET(void *msg, __u16 cmd, __u16 flags,
+			  void *data, __u16 data_len)
+{
+	struct tipc_cfg_msg_hdr *tcm_hdr;
+	int msg_len;
+
+	msg_len = TCM_LENGTH(data_len);
+	tcm_hdr = (struct tipc_cfg_msg_hdr *)msg;
+	tcm_hdr->tcm_len   = htonl(msg_len);
+	tcm_hdr->tcm_type  = htons(cmd);
+	tcm_hdr->tcm_flags = htons(flags);
+	if (data_len && data)
+		memcpy(TCM_DATA(msg), data, data_len);
+	return TCM_SPACE(data_len);
+}
+
+#endif
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index c5b96b2..805de50 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -22,7 +22,6 @@
 	char			name[GENL_NAMSIZ];
 	unsigned int		version;
 	unsigned int		maxattr;
-	struct module *		owner;
 	struct nlattr **	attrbuf;	/* private */
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
index 25b081a..9168443 100644
--- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
@@ -37,7 +37,4 @@
 struct sk_buff *
 nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
 
-/* call to create an explicit dependency on nf_conntrack_l3proto_ipv4. */
-extern void need_ip_conntrack(void);
-
 #endif /*_NF_CONNTRACK_IPV4_H*/
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 64b82b7..6d075ca 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -221,9 +221,6 @@
 extern struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name);
 
-/* call to create an explicit dependency on nf_conntrack. */
-extern void need_nf_conntrack(void);
-
 extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
 				const struct nf_conntrack_tuple *orig);
 
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index 14ce790..530ef1f 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -111,7 +111,7 @@
 #ifdef __KERNEL__
 
 #define NF_CT_DUMP_TUPLE(tp)						    \
-DEBUGP("tuple %p: %u %u %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu -> %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu\n",					    \
+DEBUGP("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n",	    \
 	(tp), (tp)->src.l3num, (tp)->dst.protonum,			    \
 	NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
 	NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 8f24121..a553f39 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -225,13 +225,13 @@
 	if (sctp_debug_flag) { \
 		if (saddr->sa.sa_family == AF_INET6) { \
 			printk(KERN_DEBUG \
-			       lead "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" trail, \
+			       lead NIP6_FMT trail, \
 			       leadparm, \
 			       NIP6(saddr->v6.sin6_addr), \
 			       otherparms); \
 		} else { \
 			printk(KERN_DEBUG \
-			       lead "%u.%u.%u.%u" trail, \
+			       lead NIPQUAD_FMT trail, \
 			       leadparm, \
 			       NIPQUAD(saddr->v4.sin_addr.s_addr), \
 			       otherparms); \
diff --git a/include/net/tipc/tipc.h b/include/net/tipc/tipc.h
new file mode 100644
index 0000000..9566608
--- /dev/null
+++ b/include/net/tipc/tipc.h
@@ -0,0 +1,257 @@
+/*
+ * include/net/tipc/tipc.h: Main include file for TIPC users
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_H_
+#define _NET_TIPC_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc.h>
+#include <linux/skbuff.h>
+
+/* 
+ * Native API
+ */
+
+/*
+ * TIPC operating mode routines
+ */
+
+u32 tipc_get_addr(void);
+
+#define TIPC_NOT_RUNNING  0
+#define TIPC_NODE_MODE    1
+#define TIPC_NET_MODE     2
+
+typedef void (*tipc_mode_event)(void *usr_handle, int mode, u32 addr);
+
+int tipc_attach(unsigned int *userref, tipc_mode_event, void *usr_handle);
+
+void tipc_detach(unsigned int userref);
+
+int tipc_get_mode(void);
+
+/*
+ * TIPC port manipulation routines
+ */
+
+typedef void (*tipc_msg_err_event) (void *usr_handle,
+				    u32 portref,
+				    struct sk_buff **buf,
+				    unsigned char const *data,
+				    unsigned int size,
+				    int reason, 
+				    struct tipc_portid const *attmpt_destid);
+
+typedef void (*tipc_named_msg_err_event) (void *usr_handle,
+					  u32 portref,
+					  struct sk_buff **buf,
+					  unsigned char const *data,
+					  unsigned int size,
+					  int reason, 
+					  struct tipc_name_seq const *attmpt_dest);
+
+typedef void (*tipc_conn_shutdown_event) (void *usr_handle,
+					  u32 portref,
+					  struct sk_buff **buf,
+					  unsigned char const *data,
+					  unsigned int size,
+					  int reason);
+
+typedef void (*tipc_msg_event) (void *usr_handle,
+				u32 portref,
+				struct sk_buff **buf,
+				unsigned char const *data,
+				unsigned int size,
+				unsigned int importance, 
+				struct tipc_portid const *origin);
+
+typedef void (*tipc_named_msg_event) (void *usr_handle,
+				      u32 portref,
+				      struct sk_buff **buf,
+				      unsigned char const *data,
+				      unsigned int size,
+				      unsigned int importance, 
+				      struct tipc_portid const *orig,
+				      struct tipc_name_seq const *dest);
+
+typedef void (*tipc_conn_msg_event) (void *usr_handle,
+				     u32 portref,
+				     struct sk_buff **buf,
+				     unsigned char const *data,
+				     unsigned int size);
+
+typedef void (*tipc_continue_event) (void *usr_handle, 
+				     u32 portref);
+
+int tipc_createport(unsigned int tipc_user, 
+		    void *usr_handle, 
+		    unsigned int importance, 
+		    tipc_msg_err_event error_cb, 
+		    tipc_named_msg_err_event named_error_cb, 
+		    tipc_conn_shutdown_event conn_error_cb, 
+		    tipc_msg_event message_cb, 
+		    tipc_named_msg_event named_message_cb, 
+		    tipc_conn_msg_event conn_message_cb, 
+		    tipc_continue_event continue_event_cb,/* May be zero */
+		    u32 *portref);
+
+int tipc_deleteport(u32 portref);
+
+int tipc_ownidentity(u32 portref, struct tipc_portid *port);
+
+int tipc_portimportance(u32 portref, unsigned int *importance);
+int tipc_set_portimportance(u32 portref, unsigned int importance);
+
+int tipc_portunreliable(u32 portref, unsigned int *isunreliable);
+int tipc_set_portunreliable(u32 portref, unsigned int isunreliable);
+
+int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable);
+int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable);
+
+int tipc_publish(u32 portref, unsigned int scope, 
+		 struct tipc_name_seq const *name_seq);
+int tipc_withdraw(u32 portref, unsigned int scope,
+		  struct tipc_name_seq const *name_seq); /* 0: all */
+
+int tipc_connect2port(u32 portref, struct tipc_portid const *port);
+
+int tipc_disconnect(u32 portref);
+
+int tipc_shutdown(u32 ref); /* Sends SHUTDOWN msg */
+
+int tipc_isconnected(u32 portref, int *isconnected);
+
+int tipc_peer(u32 portref, struct tipc_portid *peer);
+
+int tipc_ref_valid(u32 portref); 
+
+/*
+ * TIPC messaging routines
+ */
+
+#define TIPC_PORT_IMPORTANCE 100	/* send using current port setting */
+
+
+int tipc_send(u32 portref,
+	      unsigned int num_sect,
+	      struct iovec const *msg_sect);
+
+int tipc_send_buf(u32 portref,
+		  struct sk_buff *buf,
+		  unsigned int dsz);
+
+int tipc_send2name(u32 portref, 
+		   struct tipc_name const *name, 
+		   u32 domain,	/* 0:own zone */
+		   unsigned int num_sect,
+		   struct iovec const *msg_sect);
+
+int tipc_send_buf2name(u32 portref,
+		       struct tipc_name const *name,
+		       u32 domain,
+		       struct sk_buff *buf,
+		       unsigned int dsz);
+
+int tipc_forward2name(u32 portref, 
+		      struct tipc_name const *name, 
+		      u32 domain,   /*0: own zone */
+		      unsigned int section_count,
+		      struct iovec const *msg_sect,
+		      struct tipc_portid const *origin,
+		      unsigned int importance);
+
+int tipc_forward_buf2name(u32 portref,
+			  struct tipc_name const *name,
+			  u32 domain,
+			  struct sk_buff *buf,
+			  unsigned int dsz,
+			  struct tipc_portid const *orig,
+			  unsigned int importance);
+
+int tipc_send2port(u32 portref,
+		   struct tipc_portid const *dest,
+		   unsigned int num_sect,
+		   struct iovec const *msg_sect);
+
+int tipc_send_buf2port(u32 portref,
+		       struct tipc_portid const *dest,
+		       struct sk_buff *buf,
+		       unsigned int dsz);
+
+int tipc_forward2port(u32 portref,
+		      struct tipc_portid const *dest,
+		      unsigned int num_sect,
+		      struct iovec const *msg_sect,
+		      struct tipc_portid const *origin,
+		      unsigned int importance);
+
+int tipc_forward_buf2port(u32 portref,
+			  struct tipc_portid const *dest,
+			  struct sk_buff *buf,
+			  unsigned int dsz,
+			  struct tipc_portid const *orig,
+			  unsigned int importance);
+
+int tipc_multicast(u32 portref, 
+		   struct tipc_name_seq const *seq, 
+		   u32 domain,	/* 0:own zone */
+		   unsigned int section_count,
+		   struct iovec const *msg);
+
+#if 0
+int tipc_multicast_buf(u32 portref, 
+		       struct tipc_name_seq const *seq, 
+		       u32 domain,	/* 0:own zone */
+		       void *buf,
+		       unsigned int size);
+#endif
+
+/*
+ * TIPC subscription routines
+ */
+
+int tipc_ispublished(struct tipc_name const *name);
+
+/*
+ * Get number of available nodes within specified domain (excluding own node)
+ */
+
+unsigned int tipc_available_nodes(const u32 domain);
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h
new file mode 100644
index 0000000..098607c
--- /dev/null
+++ b/include/net/tipc/tipc_bearer.h
@@ -0,0 +1,121 @@
+/*
+ * include/net/tipc/tipc_bearer.h: Include file for privileged access to TIPC bearers
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_BEARER_H_
+#define _NET_TIPC_BEARER_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc_config.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+/*
+ * Identifiers of supported TIPC media types
+ */
+
+#define TIPC_MEDIA_TYPE_ETH	1
+
+struct tipc_media_addr {
+	__u32  type;
+	union {
+		__u8   eth_addr[6];	/* Ethernet bearer */ 
+#if 0
+		/* Prototypes for other possible bearer types */
+
+		struct {
+			__u16 sin_family;
+			__u16 sin_port;
+			struct {
+				__u32 s_addr;
+			} sin_addr;
+			char pad[4];
+		} addr_in;		/* IP-based bearer */
+		__u16  sock_descr;	/* generic socket bearer */
+#endif
+	} dev_addr;
+};
+
+/**
+ * struct tipc_bearer - TIPC bearer info available to privileged users
+ * @usr_handle: pointer to additional user-defined information about bearer
+ * @mtu: max packet size bearer can support
+ * @blocked: non-zero if bearer is blocked
+ * @lock: spinlock for controlling access to bearer
+ * @addr: media-specific address associated with bearer
+ * @name: bearer name (format = media:interface)
+ * 
+ * Note: TIPC initializes "name" and "lock" fields; user is responsible for
+ * initialization all other fields when a bearer is enabled.
+ */
+
+struct tipc_bearer {
+	void *usr_handle;
+	u32 mtu;
+	int blocked;
+	spinlock_t lock;
+	struct tipc_media_addr addr;
+	char name[TIPC_MAX_BEARER_NAME];
+};
+
+
+int  tipc_register_media(u32 media_type,
+			 char *media_name, 
+			 int (*enable)(struct tipc_bearer *), 
+			 void (*disable)(struct tipc_bearer *), 
+			 int (*send_msg)(struct sk_buff *, 
+					 struct tipc_bearer *,
+					 struct tipc_media_addr *), 
+			 char *(*addr2str)(struct tipc_media_addr *a,
+					   char *str_buf,
+					   int str_size),
+			 struct tipc_media_addr *bcast_addr,
+			 const u32 bearer_priority,
+			 const u32 link_tolerance,  /* [ms] */
+			 const u32 send_window_limit); 
+
+void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
+
+int  tipc_block_bearer(const char *name);
+void tipc_continue(struct tipc_bearer *tb_ptr); 
+
+int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority);
+int tipc_disable_bearer(const char *name);
+
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h
new file mode 100644
index 0000000..4d096ee
--- /dev/null
+++ b/include/net/tipc/tipc_msg.h
@@ -0,0 +1,223 @@
+/*
+ * include/net/tipc/tipc_msg.h: Include file for privileged access to TIPC message headers
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_MSG_H_
+#define _NET_TIPC_MSG_H_
+
+#ifdef __KERNEL__
+
+struct tipc_msg {
+	u32 hdr[15];
+};
+
+
+/*
+		TIPC user data message header format, version 2:
+
+
+       1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w0:|vers | user  |hdr sz |n|d|s|-|          message size           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w1:|mstyp| error |rer cnt|lsc|opt p|      broadcast ack no         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w2:|        link level ack no      |   broadcast/link level seq no |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w3:|                       previous node                           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w4:|                      originating port                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w5:|                      destination port                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+   w6:|                      originating node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w7:|                      destination node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w8:|            name type / transport sequence number              |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w9:|              name instance/multicast lower bound              |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+   wA:|                    multicast upper bound                      |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+      /                                                               /
+      \                           options                             \
+      /                                                               /
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+*/
+
+#define TIPC_CONN_MSG	0
+#define TIPC_MCAST_MSG	1
+#define TIPC_NAMED_MSG	2
+#define TIPC_DIRECT_MSG	3
+
+
+static inline u32 msg_word(struct tipc_msg *m, u32 pos)
+{
+	return ntohl(m->hdr[pos]);
+}
+
+static inline u32 msg_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask)
+{
+	return (msg_word(m, w) >> pos) & mask;
+}
+
+static inline u32 msg_importance(struct tipc_msg *m)
+{
+	return msg_bits(m, 0, 25, 0xf);
+}
+
+static inline u32 msg_hdr_sz(struct tipc_msg *m)
+{
+	return msg_bits(m, 0, 21, 0xf) << 2;
+}
+
+static inline int msg_short(struct tipc_msg *m)
+{
+	return (msg_hdr_sz(m) == 24);
+}
+
+static inline u32 msg_size(struct tipc_msg *m)
+{
+	return msg_bits(m, 0, 0, 0x1ffff);
+}
+
+static inline u32 msg_data_sz(struct tipc_msg *m)
+{
+	return (msg_size(m) - msg_hdr_sz(m));
+}
+
+static inline unchar *msg_data(struct tipc_msg *m)
+{
+	return ((unchar *)m) + msg_hdr_sz(m);
+}
+
+static inline u32 msg_type(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 29, 0x7);
+}
+
+static inline u32 msg_direct(struct tipc_msg *m)
+{
+	return (msg_type(m) == TIPC_DIRECT_MSG);
+}
+
+static inline u32 msg_named(struct tipc_msg *m)
+{
+	return (msg_type(m) == TIPC_NAMED_MSG);
+}
+
+static inline u32 msg_mcast(struct tipc_msg *m)
+{
+	return (msg_type(m) == TIPC_MCAST_MSG);
+}
+
+static inline u32 msg_connected(struct tipc_msg *m)
+{
+	return (msg_type(m) == TIPC_CONN_MSG);
+}
+
+static inline u32 msg_errcode(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 25, 0xf);
+}
+
+static inline u32 msg_prevnode(struct tipc_msg *m)
+{
+	return msg_word(m, 3);
+}
+
+static inline u32 msg_origport(struct tipc_msg *m)
+{
+	return msg_word(m, 4);
+}
+
+static inline u32 msg_destport(struct tipc_msg *m)
+{
+	return msg_word(m, 5);
+}
+
+static inline u32 msg_mc_netid(struct tipc_msg *m)
+{
+	return msg_word(m, 5);
+}
+
+static inline u32 msg_orignode(struct tipc_msg *m)
+{
+	if (likely(msg_short(m)))
+		return msg_prevnode(m);
+	return msg_word(m, 6);
+}
+
+static inline u32 msg_destnode(struct tipc_msg *m)
+{
+	return msg_word(m, 7);
+}
+
+static inline u32 msg_nametype(struct tipc_msg *m)
+{
+	return msg_word(m, 8);
+}
+
+static inline u32 msg_nameinst(struct tipc_msg *m)
+{
+	return msg_word(m, 9);
+}
+
+static inline u32 msg_namelower(struct tipc_msg *m)
+{
+	return msg_nameinst(m);
+}
+
+static inline u32 msg_nameupper(struct tipc_msg *m)
+{
+	return msg_word(m, 10);
+}
+
+static inline char *msg_options(struct tipc_msg *m, u32 *len)
+{
+	u32 pos = msg_bits(m, 1, 16, 0x7);
+
+	if (!pos)
+		return 0;
+	pos = (pos * 4) + 28;
+	*len = msg_hdr_sz(m) - pos;
+	return (char *)&m->hdr[pos/4];
+}
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
new file mode 100644
index 0000000..333bba6
--- /dev/null
+++ b/include/net/tipc/tipc_port.h
@@ -0,0 +1,108 @@
+/*
+ * include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports
+ * 
+ * Copyright (c) 1994-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_PORT_H_
+#define _NET_TIPC_PORT_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc.h>
+#include <linux/skbuff.h>
+#include <net/tipc/tipc_msg.h>
+
+#define TIPC_FLOW_CONTROL_WIN 512
+
+/**
+ * struct tipc_port - native TIPC port info available to privileged users
+ * @usr_handle: pointer to additional user-defined information about port
+ * @lock: pointer to spinlock for controlling access to port
+ * @connected: non-zero if port is currently connected to a peer port
+ * @conn_type: TIPC type used when connection was established
+ * @conn_instance: TIPC instance used when connection was established
+ * @conn_unacked: number of unacknowledged messages received from peer port
+ * @published: non-zero if port has one or more associated names
+ * @congested: non-zero if cannot send because of link or port congestion
+ * @ref: unique reference to port in TIPC object registry
+ * @phdr: preformatted message header used when sending messages
+ */
+
+struct tipc_port {
+        void *usr_handle;
+        spinlock_t *lock;
+	int connected;
+        u32 conn_type;
+        u32 conn_instance;
+	u32 conn_unacked;
+	int published;
+	u32 congested;
+	u32 ref;
+	struct tipc_msg phdr;
+};
+
+
+/**
+ * tipc_createport_raw - create a native TIPC port and return it's reference
+ *
+ * Note: 'dispatcher' and 'wakeup' deliver a locked port.
+ */
+
+u32 tipc_createport_raw(void *usr_handle,
+			u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
+			void (*wakeup)(struct tipc_port *),
+			const u32 importance);
+
+/*
+ * tipc_set_msg_option(): port must be locked.
+ */
+int tipc_set_msg_option(struct tipc_port *tp_ptr,
+			const char *opt,
+			const u32 len);
+
+int tipc_reject_msg(struct sk_buff *buf, u32 err);
+
+int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode);
+
+void tipc_acknowledge(u32 port_ref,u32 ack);
+
+struct tipc_port *tipc_get_port(const u32 ref);
+
+void *tipc_get_handle(const u32 ref);
+
+
+#endif
+
+#endif
+
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index a7f4c35..22fc886 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -88,7 +88,6 @@
 
 struct ib_device_attr {
 	u64			fw_ver;
-	__be64			node_guid;
 	__be64			sys_image_guid;
 	u64			max_mr_size;
 	u64			page_size_cap;
@@ -951,6 +950,7 @@
 	u64			     uverbs_cmd_mask;
 	int			     uverbs_abi_ver;
 
+	__be64			     node_guid;
 	u8                           node_type;
 	u8                           phys_port_cnt;
 };
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index be1bc79..3e5cb5a 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -168,6 +168,12 @@
 
 #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
 #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_hostdata - get LLD hostdata from scsi_host
+ * @_hostdata: pointer to scsi host's hostdata
+ **/
 #define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
 
 /*
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 6cb1e27..c60b8ff 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -32,6 +32,12 @@
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 
 /*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given shost.
+ */
+#define SCAN_WILD_CARD	~0
+
+/*
  *      SCSI opcodes
  */
 
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 41cfc29..7529f43 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -151,6 +151,5 @@
 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 void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd);
 
 #endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 230bc55..467274a 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -5,6 +5,7 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 struct block_device;
 struct completion;
@@ -469,7 +470,7 @@
 	spinlock_t		default_lock;
 	spinlock_t		*host_lock;
 
-	struct semaphore	scan_mutex;/* serialize scanning activity */
+	struct mutex		scan_mutex;/* serialize scanning activity */
 
 	struct list_head	eh_cmd_q;
 	struct task_struct    * ehandler;  /* Error recovery thread. */
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index f6e0bb4..e7b1054 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -30,12 +30,9 @@
 	struct transport_container device_attrs;
 
 	/*
-	 * If set, call target_parent prior to allocating a scsi_target,
-	 * so we get the appropriate parent for the target. This function
-	 * is required for transports like FC and iSCSI that do not put the
-	 * scsi_target under scsi_host.
+	 * If set, called from sysfs and legacy procfs rescanning code.
 	 */
-	struct device *(*target_parent)(struct Scsi_Host *, int, uint);
+	int (*user_scan)(struct Scsi_Host *, uint, uint, uint);
 
 	/* The size of the specific transport attribute structure (a
 	 * space of this size will be left at the end of the
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 394f14a..cf3fec8 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -303,6 +303,7 @@
 	/* Fixed Attributes */
 	u64 node_name;
 	u64 port_name;
+	u64 permanent_port_name;
 	u32 supported_classes;
 	u8  supported_fc4s[FC_FC4_LIST_SIZE];
 	char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
@@ -338,6 +339,8 @@
 	(((struct fc_host_attrs *)(x)->shost_data)->node_name)
 #define fc_host_port_name(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->port_name)
+#define fc_host_permanent_port_name(x)	\
+	(((struct fc_host_attrs *)(x)->shost_data)->permanent_port_name)
 #define fc_host_supported_classes(x)	\
 	(((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
 #define fc_host_supported_fc4s(x)	\
@@ -426,6 +429,7 @@
 	/* host fixed attributes */
 	unsigned long	show_host_node_name:1;
 	unsigned long	show_host_port_name:1;
+	unsigned long	show_host_permanent_port_name:1;
 	unsigned long	show_host_supported_classes:1;
 	unsigned long	show_host_supported_fc4s:1;
 	unsigned long	show_host_symbolic_name:1;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index f25041c..16602a5 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -23,8 +23,14 @@
 #ifndef SCSI_TRANSPORT_ISCSI_H
 #define SCSI_TRANSPORT_ISCSI_H
 
+#include <linux/device.h>
 #include <scsi/iscsi_if.h>
 
+struct scsi_transport_template;
+struct Scsi_Host;
+struct mempool_zone;
+struct iscsi_cls_conn;
+
 /**
  * struct iscsi_transport - iSCSI Transport template
  *
@@ -48,23 +54,31 @@
 	char *name;
 	unsigned int caps;
 	struct scsi_host_template *host_template;
+	/* LLD session/scsi_host data size */
 	int hostdata_size;
+	/* LLD iscsi_host data size */
+	int ihostdata_size;
+	/* LLD connection data size */
+	int conndata_size;
 	int max_lun;
 	unsigned int max_conn;
 	unsigned int max_cmd_len;
-	iscsi_sessionh_t (*create_session) (uint32_t initial_cmdsn,
-					    struct Scsi_Host *shost);
-	void (*destroy_session) (iscsi_sessionh_t session);
-	iscsi_connh_t (*create_conn) (iscsi_sessionh_t session, uint32_t cid);
+	struct Scsi_Host *(*create_session) (struct scsi_transport_template *t,
+					     uint32_t initial_cmdsn);
+	void (*destroy_session) (struct Scsi_Host *shost);
+	struct iscsi_cls_conn *(*create_conn) (struct Scsi_Host *shost,
+				uint32_t cid);
 	int (*bind_conn) (iscsi_sessionh_t session, iscsi_connh_t conn,
 			  uint32_t transport_fd, int is_leading);
 	int (*start_conn) (iscsi_connh_t conn);
 	void (*stop_conn) (iscsi_connh_t conn, int flag);
-	void (*destroy_conn) (iscsi_connh_t conn);
+	void (*destroy_conn) (struct iscsi_cls_conn *conn);
 	int (*set_param) (iscsi_connh_t conn, enum iscsi_param param,
 			  uint32_t value);
-	int (*get_param) (iscsi_connh_t conn, enum iscsi_param param,
-			  uint32_t *value);
+	int (*get_conn_param) (void *conndata, enum iscsi_param param,
+			       uint32_t *value);
+	int (*get_session_param) (struct Scsi_Host *shost,
+				  enum iscsi_param param, uint32_t *value);
 	int (*send_pdu) (iscsi_connh_t conn, struct iscsi_hdr *hdr,
 			 char *data, uint32_t data_size);
 	void (*get_stats) (iscsi_connh_t conn, struct iscsi_stats *stats);
@@ -73,7 +87,7 @@
 /*
  * transport registration upcalls
  */
-extern int iscsi_register_transport(struct iscsi_transport *tt);
+extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
 extern int iscsi_unregister_transport(struct iscsi_transport *tt);
 
 /*
@@ -83,4 +97,49 @@
 extern int iscsi_recv_pdu(iscsi_connh_t conn, struct iscsi_hdr *hdr,
 			  char *data, uint32_t data_size);
 
+struct iscsi_cls_conn {
+	struct list_head conn_list;	/* item in connlist */
+	void *dd_data;			/* LLD private data */
+	struct iscsi_transport *transport;
+	iscsi_connh_t connh;
+	int active;			/* must be accessed with the connlock */
+	struct device dev;		/* sysfs transport/container device */
+	struct mempool_zone *z_error;
+	struct mempool_zone *z_pdu;
+	struct list_head freequeue;
+};
+
+#define iscsi_dev_to_conn(_dev) \
+	container_of(_dev, struct iscsi_cls_conn, dev)
+
+struct iscsi_cls_session {
+	struct list_head list;	/* item in session_list */
+	struct iscsi_transport *transport;
+	struct device dev;	/* sysfs transport/container device */
+};
+
+#define iscsi_dev_to_session(_dev) \
+	container_of(_dev, struct iscsi_cls_session, dev)
+
+#define iscsi_session_to_shost(_session) \
+	dev_to_shost(_session->dev.parent)
+
+/*
+ * session and connection functions that can be used by HW iSCSI LLDs
+ */
+extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
+				struct iscsi_transport *t);
+extern int iscsi_destroy_session(struct iscsi_cls_session *session);
+extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
+					    uint32_t cid);
+extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
+
+/*
+ * session functions used by software iscsi
+ */
+extern struct Scsi_Host *
+iscsi_transport_create_session(struct scsi_transport_template *scsit,
+                               struct iscsi_transport *transport);
+extern int iscsi_transport_destroy_session(struct Scsi_Host *shost);
+
 #endif
diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
index 54a8961..2b5930b 100644
--- a/include/scsi/scsi_transport_spi.h
+++ b/include/scsi/scsi_transport_spi.h
@@ -54,7 +54,7 @@
 	unsigned int support_qas; /* supports quick arbitration and selection */
 	/* Private Fields */
 	unsigned int dv_pending:1; /* Internal flag */
-	struct semaphore dv_sem; /* semaphore to serialise dv */
+	struct mutex dv_mutex; /* semaphore to serialise dv */
 };
 
 enum spi_signal_type {
diff --git a/init/main.c b/init/main.c
index e092b19..7c79da5 100644
--- a/init/main.c
+++ b/init/main.c
@@ -54,20 +54,18 @@
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
 
-/*
- * This is one of the first .c files built. Error out early
- * if we have compiler trouble..
- */
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
 
 /*
- * Versions of gcc older than that listed below may actually compile
- * and link okay, but the end product can have subtle run time bugs.
- * To avoid associated bogus bug reports, we flatly refuse to compile
- * with a gcc that is known to be too old from the very beginning.
+ * This is one of the first .c files built. Error out early if we have compiler
+ * trouble.
+ *
+ * Versions of gcc older than that listed below may actually compile and link
+ * okay, but the end product can have subtle run time bugs.  To avoid associated
+ * bogus bug reports, we flatly refuse to compile with a gcc that is known to be
+ * too old from the very beginning.
  */
 #if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2)
 #error Sorry, your GCC is too old. It builds incorrect kernels.
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4e776f9..59302fc 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -599,15 +599,16 @@
 static struct file *do_create(struct dentry *dir, struct dentry *dentry,
 			int oflag, mode_t mode, struct mq_attr __user *u_attr)
 {
-	struct file *filp;
 	struct mq_attr attr;
 	int ret;
 
-	if (u_attr != NULL) {
+	if (u_attr) {
+		ret = -EFAULT;
 		if (copy_from_user(&attr, u_attr, sizeof(attr)))
-			return ERR_PTR(-EFAULT);
+			goto out;
+		ret = -EINVAL;
 		if (!mq_attr_ok(&attr))
-			return ERR_PTR(-EINVAL);
+			goto out;
 		/* store for use during create */
 		dentry->d_fsdata = &attr;
 	}
@@ -616,13 +617,14 @@
 	ret = vfs_create(dir->d_inode, dentry, mode, NULL);
 	dentry->d_fsdata = NULL;
 	if (ret)
-		return ERR_PTR(ret);
+		goto out;
 
-	filp = dentry_open(dentry, mqueue_mnt, oflag);
-	if (!IS_ERR(filp))
-		dget(dentry);
+	return dentry_open(dentry, mqueue_mnt, oflag);
 
-	return filp;
+out:
+	dput(dentry);
+	mntput(mqueue_mnt);
+	return ERR_PTR(ret);
 }
 
 /* Opens existing queue */
@@ -630,20 +632,20 @@
 {
 static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
 					MAY_READ | MAY_WRITE };
-	struct file *filp;
 
-	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
+	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
+		dput(dentry);
+		mntput(mqueue_mnt);
 		return ERR_PTR(-EINVAL);
+	}
 
-	if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL))
+	if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
+		dput(dentry);
+		mntput(mqueue_mnt);
 		return ERR_PTR(-EACCES);
+	}
 
-	filp = dentry_open(dentry, mqueue_mnt, oflag);
-
-	if (!IS_ERR(filp))
-		dget(dentry);
-
-	return filp;
+	return dentry_open(dentry, mqueue_mnt, oflag);
 }
 
 asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
@@ -671,17 +673,20 @@
 
 	if (oflag & O_CREAT) {
 		if (dentry->d_inode) {	/* entry already exists */
-			filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) :
-					do_open(dentry, oflag);
+			error = -EEXIST;
+			if (oflag & O_EXCL)
+				goto out;
+			filp = do_open(dentry, oflag);
 		} else {
 			filp = do_create(mqueue_mnt->mnt_root, dentry,
 						oflag, mode, u_attr);
 		}
-	} else
-		filp = (dentry->d_inode) ? do_open(dentry, oflag) :
-					ERR_PTR(-ENOENT);
-
-	dput(dentry);
+	} else {
+		error = -ENOENT;
+		if (!dentry->d_inode)
+			goto out;
+		filp = do_open(dentry, oflag);
+	}
 
 	if (IS_ERR(filp)) {
 		error = PTR_ERR(filp);
@@ -692,8 +697,10 @@
 	fd_install(fd, filp);
 	goto out_upsem;
 
-out_putfd:
+out:
+	dput(dentry);
 	mntput(mqueue_mnt);
+out_putfd:
 	put_unused_fd(fd);
 out_err:
 	fd = error;
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 2a75e44..fe2f71f 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1554,7 +1554,7 @@
  * when reading out p->cpuset, as we don't really care if it changes
  * on the next cycle, and we are not going to try to dereference it.
  */
-static inline int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
+static int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
 {
 	int n = 0;
 	struct task_struct *g, *p;
@@ -2150,6 +2150,33 @@
 }
 
 /**
+ * cpuset_lock - lock out any changes to cpuset structures
+ *
+ * The out of memory (oom) code needs to lock down cpusets
+ * from being changed while it scans the tasklist looking for a
+ * task in an overlapping cpuset.  Expose callback_sem via this
+ * cpuset_lock() routine, so the oom code can lock it, before
+ * locking the task list.  The tasklist_lock is a spinlock, so
+ * must be taken inside callback_sem.
+ */
+
+void cpuset_lock(void)
+{
+	down(&callback_sem);
+}
+
+/**
+ * cpuset_unlock - release lock on cpuset changes
+ *
+ * Undo the lock taken in a previous cpuset_lock() call.
+ */
+
+void cpuset_unlock(void)
+{
+	up(&callback_sem);
+}
+
+/**
  * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors?
  * @p: pointer to task_struct of some other task.
  *
@@ -2158,7 +2185,7 @@
  * determine if task @p's memory usage might impact the memory
  * available to the current task.
  *
- * Acquires callback_sem - not suitable for calling from a fast path.
+ * Call while holding callback_sem.
  **/
 
 int cpuset_excl_nodes_overlap(const struct task_struct *p)
@@ -2166,8 +2193,6 @@
 	const struct cpuset *cs1, *cs2;	/* my and p's cpuset ancestors */
 	int overlap = 0;		/* do cpusets overlap? */
 
-	down(&callback_sem);
-
 	task_lock(current);
 	if (current->flags & PF_EXITING) {
 		task_unlock(current);
@@ -2186,8 +2211,6 @@
 
 	overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed);
 done:
-	up(&callback_sem);
-
 	return overlap;
 }
 
diff --git a/kernel/exit.c b/kernel/exit.c
index f8e609f..93cee36 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -193,7 +193,7 @@
 	return retval;
 }
 
-static inline int has_stopped_jobs(int pgrp)
+static int has_stopped_jobs(int pgrp)
 {
 	int retval = 0;
 	struct task_struct *p;
@@ -230,7 +230,7 @@
  *
  * NOTE that reparent_to_init() gives the caller full capabilities.
  */
-static inline void reparent_to_init(void)
+static void reparent_to_init(void)
 {
 	write_lock_irq(&tasklist_lock);
 
@@ -244,7 +244,9 @@
 	/* Set the exit signal to SIGCHLD so we signal init on exit */
 	current->exit_signal = SIGCHLD;
 
-	if ((current->policy == SCHED_NORMAL) && (task_nice(current) < 0))
+	if ((current->policy == SCHED_NORMAL ||
+			current->policy == SCHED_BATCH)
+				&& (task_nice(current) < 0))
 		set_user_nice(current, 0);
 	/* cpus_allowed? */
 	/* rt_priority? */
@@ -367,7 +369,7 @@
 
 EXPORT_SYMBOL(daemonize);
 
-static inline void close_files(struct files_struct * files)
+static void close_files(struct files_struct * files)
 {
 	int i, j;
 	struct fdtable *fdt;
@@ -541,7 +543,7 @@
 	p->real_parent = reaper;
 }
 
-static inline void reparent_thread(task_t *p, task_t *father, int traced)
+static void reparent_thread(task_t *p, task_t *father, int traced)
 {
 	/* We don't want people slaying init.  */
 	if (p->exit_signal != -1)
@@ -605,7 +607,7 @@
  * group, and if no such member exists, give it to
  * the global child reaper process (ie "init")
  */
-static inline void forget_original_parent(struct task_struct * father,
+static void forget_original_parent(struct task_struct * father,
 					  struct list_head *to_release)
 {
 	struct task_struct *p, *reaper = father;
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 9e66e61..197208b 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -192,7 +192,7 @@
 	return do_sys_settimeofday(tp, NULL);
 }
 
-static inline int common_timer_create(struct k_itimer *new_timer)
+static int common_timer_create(struct k_itimer *new_timer)
 {
 	hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock);
 	new_timer->it.real.timer.data = new_timer;
@@ -361,7 +361,7 @@
 	return ret;
 }
 
-static inline struct task_struct * good_sigevent(sigevent_t * event)
+static struct task_struct * good_sigevent(sigevent_t * event)
 {
 	struct task_struct *rtn = current->group_leader;
 
@@ -687,7 +687,7 @@
 
 /* Set a POSIX.1b interval timer. */
 /* timr->it_lock is taken. */
-static inline int
+static int
 common_timer_set(struct k_itimer *timr, int flags,
 		 struct itimerspec *new_setting, struct itimerspec *old_setting)
 {
@@ -829,7 +829,7 @@
 /*
  * return timer owned by the process, used by exit_itimers
  */
-static inline void itimer_delete(struct k_itimer *timer)
+static void itimer_delete(struct k_itimer *timer)
 {
 	unsigned long flags;
 
diff --git a/kernel/sched.c b/kernel/sched.c
index c9dec2a..788ecce 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -521,7 +521,7 @@
  * long it was waiting to run.  We also note when it began so that we
  * can keep stats on how long its timeslice is.
  */
-static inline void sched_info_arrive(task_t *t)
+static void sched_info_arrive(task_t *t)
 {
 	unsigned long now = jiffies, diff = 0;
 	struct runqueue *rq = task_rq(t);
@@ -748,10 +748,14 @@
 	unsigned long long __sleep_time = now - p->timestamp;
 	unsigned long sleep_time;
 
-	if (__sleep_time > NS_MAX_SLEEP_AVG)
-		sleep_time = NS_MAX_SLEEP_AVG;
-	else
-		sleep_time = (unsigned long)__sleep_time;
+	if (unlikely(p->policy == SCHED_BATCH))
+		sleep_time = 0;
+	else {
+		if (__sleep_time > NS_MAX_SLEEP_AVG)
+			sleep_time = NS_MAX_SLEEP_AVG;
+		else
+			sleep_time = (unsigned long)__sleep_time;
+	}
 
 	if (likely(sleep_time > 0)) {
 		/*
@@ -1003,7 +1007,7 @@
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long __source_load(int cpu, int type, enum idle_type idle)
+static unsigned long __source_load(int cpu, int type, enum idle_type idle)
 {
 	runqueue_t *rq = cpu_rq(cpu);
 	unsigned long running = rq->nr_running;
@@ -1866,7 +1870,7 @@
  * pull_task - move a task from a remote runqueue to the local runqueue.
  * Both runqueues must be locked.
  */
-static inline
+static
 void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
 	       runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
@@ -1888,7 +1892,7 @@
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
  */
-static inline
+static
 int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
 		     struct sched_domain *sd, enum idle_type idle,
 		     int *all_pinned)
@@ -2374,7 +2378,7 @@
  * idle_balance is called by schedule() if this_cpu is about to become
  * idle. Attempts to pull tasks from other CPUs.
  */
-static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
+static void idle_balance(int this_cpu, runqueue_t *this_rq)
 {
 	struct sched_domain *sd;
 
@@ -2758,7 +2762,7 @@
 		resched_task(rq->idle);
 }
 
-static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+static void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
 {
 	struct sched_domain *tmp, *sd = NULL;
 	cpumask_t sibling_map;
@@ -2812,7 +2816,7 @@
 	return p->time_slice * (100 - sd->per_cpu_gain) / 100;
 }
 
-static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
 {
 	struct sched_domain *tmp, *sd = NULL;
 	cpumask_t sibling_map;
@@ -3560,7 +3564,7 @@
 	 * The RT priorities are set via sched_setscheduler(), but we still
 	 * allow the 'normal' nice value to be set - but as expected
 	 * it wont have any effect on scheduling until the task is
-	 * not SCHED_NORMAL:
+	 * not SCHED_NORMAL/SCHED_BATCH:
 	 */
 	if (rt_task(p)) {
 		p->static_prio = NICE_TO_PRIO(nice);
@@ -3706,10 +3710,16 @@
 	BUG_ON(p->array);
 	p->policy = policy;
 	p->rt_priority = prio;
-	if (policy != SCHED_NORMAL)
+	if (policy != SCHED_NORMAL && policy != SCHED_BATCH) {
 		p->prio = MAX_RT_PRIO-1 - p->rt_priority;
-	else
+	} else {
 		p->prio = p->static_prio;
+		/*
+		 * SCHED_BATCH tasks are treated as perpetual CPU hogs:
+		 */
+		if (policy == SCHED_BATCH)
+			p->sleep_avg = 0;
+	}
 }
 
 /**
@@ -3733,29 +3743,35 @@
 	if (policy < 0)
 		policy = oldpolicy = p->policy;
 	else if (policy != SCHED_FIFO && policy != SCHED_RR &&
-				policy != SCHED_NORMAL)
-			return -EINVAL;
+			policy != SCHED_NORMAL && policy != SCHED_BATCH)
+		return -EINVAL;
 	/*
 	 * Valid priorities for SCHED_FIFO and SCHED_RR are
-	 * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL is 0.
+	 * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL and
+	 * SCHED_BATCH is 0.
 	 */
 	if (param->sched_priority < 0 ||
 	    (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) ||
 	    (!p->mm && param->sched_priority > MAX_RT_PRIO-1))
 		return -EINVAL;
-	if ((policy == SCHED_NORMAL) != (param->sched_priority == 0))
+	if ((policy == SCHED_NORMAL || policy == SCHED_BATCH)
+					!= (param->sched_priority == 0))
 		return -EINVAL;
 
 	/*
 	 * Allow unprivileged RT tasks to decrease priority:
 	 */
 	if (!capable(CAP_SYS_NICE)) {
-		/* can't change policy */
-		if (policy != p->policy &&
-			!p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+		/*
+		 * can't change policy, except between SCHED_NORMAL
+		 * and SCHED_BATCH:
+		 */
+		if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
+			(policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
+				!p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
 			return -EPERM;
 		/* can't increase priority */
-		if (policy != SCHED_NORMAL &&
+		if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) &&
 		    param->sched_priority > p->rt_priority &&
 		    param->sched_priority >
 				p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
@@ -4233,6 +4249,7 @@
 		ret = MAX_USER_RT_PRIO-1;
 		break;
 	case SCHED_NORMAL:
+	case SCHED_BATCH:
 		ret = 0;
 		break;
 	}
@@ -4256,6 +4273,7 @@
 		ret = 1;
 		break;
 	case SCHED_NORMAL:
+	case SCHED_BATCH:
 		ret = 0;
 	}
 	return ret;
@@ -5990,7 +6008,7 @@
  * Detach sched domains from a group of cpus specified in cpu_map
  * These cpus will now be attached to the NULL domain
  */
-static inline void detach_destroy_domains(const cpumask_t *cpu_map)
+static void detach_destroy_domains(const cpumask_t *cpu_map)
 {
 	int i;
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 1da2e74..5dafbd3 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -476,7 +476,7 @@
 	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
-static inline int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
+static int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
 {
 	struct sigqueue *q, *first = NULL;
 	int still_pending = 0;
@@ -1881,7 +1881,7 @@
  * We return zero if we still hold the siglock and should look
  * for another signal without checking group_stop_count again.
  */
-static inline int handle_group_stop(void)
+static int handle_group_stop(void)
 {
 	int stop_count;
 
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 62d4d95..f5d69b6 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -648,7 +648,7 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
-#if defined(CONFIG_S390)
+#if defined(CONFIG_S390) && defined(CONFIG_SMP)
 	{
 		.ctl_name	= KERN_SPIN_RETRY,
 		.procname	= "spin_retry",
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 82c4fa7..b052e2c 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -147,7 +147,7 @@
 	return ret;
 }
 
-static inline void run_workqueue(struct cpu_workqueue_struct *cwq)
+static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
 	unsigned long flags;
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a609235..a314e66 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -195,6 +195,20 @@
 	  some architectures or if you use external debuggers.
 	  If you don't debug the kernel, you can say N.
 
+config FORCED_INLINING
+	bool "Force gcc to inline functions marked 'inline'"
+	depends on DEBUG_KERNEL
+	default y
+	help
+	  This option determines if the kernel forces gcc to inline the functions
+	  developers have marked 'inline'. Doing so takes away freedom from gcc to
+	  do what it thinks is best, which is desirable for the gcc 3.x series of
+	  compilers. The gcc 4.x series have a rewritten inlining algorithm and
+	  disabling this option will generate a smaller kernel there. Hopefully
+	  this algorithm is so good that allowing gcc4 to make the decision can
+	  become the default in the future, until then this option is there to
+	  test gcc for this.
+
 config RCU_TORTURE_TEST
 	tristate "torture tests for RCU"
 	depends on DEBUG_KERNEL
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b62cab5..3171f88 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1359,6 +1359,30 @@
 	return 0;
 }
 
+void mpol_shared_policy_init(struct shared_policy *info, int policy,
+				nodemask_t *policy_nodes)
+{
+	info->root = RB_ROOT;
+	spin_lock_init(&info->lock);
+
+	if (policy != MPOL_DEFAULT) {
+		struct mempolicy *newpol;
+
+		/* Falls back to MPOL_DEFAULT on any error */
+		newpol = mpol_new(policy, policy_nodes);
+		if (!IS_ERR(newpol)) {
+			/* Create pseudo-vma that contains just the policy */
+			struct vm_area_struct pvma;
+
+			memset(&pvma, 0, sizeof(struct vm_area_struct));
+			/* Policy covers entire file */
+			pvma.vm_end = TASK_SIZE;
+			mpol_set_shared_policy(info, &pvma, newpol);
+			mpol_free(newpol);
+		}
+	}
+}
+
 int mpol_set_shared_policy(struct shared_policy *info,
 			struct vm_area_struct *vma, struct mempolicy *npol)
 {
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 4748b90..14bd4ec 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -274,6 +274,7 @@
 		show_mem();
 	}
 
+	cpuset_lock();
 	read_lock(&tasklist_lock);
 retry:
 	p = select_bad_process();
@@ -284,6 +285,7 @@
 	/* Found nothing?!?! Either we hang forever, or we panic. */
 	if (!p) {
 		read_unlock(&tasklist_lock);
+		cpuset_unlock();
 		panic("Out of memory and no killable processes...\n");
 	}
 
@@ -293,6 +295,7 @@
 
  out:
 	read_unlock(&tasklist_lock);
+	cpuset_unlock();
 	if (mm)
 		mmput(mm);
 
diff --git a/mm/shmem.c b/mm/shmem.c
index 343b3c0..ce501bc 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1316,7 +1316,8 @@
 		case S_IFREG:
 			inode->i_op = &shmem_inode_operations;
 			inode->i_fop = &shmem_file_operations;
-			mpol_shared_policy_init(&info->policy);
+			mpol_shared_policy_init(&info->policy, sbinfo->policy,
+							&sbinfo->policy_nodes);
 			break;
 		case S_IFDIR:
 			inode->i_nlink++;
@@ -1330,7 +1331,8 @@
 			 * Must not load anything in the rbtree,
 			 * mpol_free_shared_policy will not be called.
 			 */
-			mpol_shared_policy_init(&info->policy);
+			mpol_shared_policy_init(&info->policy, MPOL_DEFAULT,
+						NULL);
 			break;
 		}
 	} else if (sbinfo->max_inodes) {
@@ -1843,7 +1845,9 @@
 	.put_link	= shmem_put_link,
 };
 
-static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
+static int shmem_parse_options(char *options, int *mode, uid_t *uid,
+	gid_t *gid, unsigned long *blocks, unsigned long *inodes,
+	int *policy, nodemask_t *policy_nodes)
 {
 	char *this_char, *value, *rest;
 
@@ -1897,6 +1901,19 @@
 			*gid = simple_strtoul(value,&rest,0);
 			if (*rest)
 				goto bad_val;
+		} else if (!strcmp(this_char,"mpol")) {
+			if (!strcmp(value,"default"))
+				*policy = MPOL_DEFAULT;
+			else if (!strcmp(value,"preferred"))
+				*policy = MPOL_PREFERRED;
+			else if (!strcmp(value,"bind"))
+				*policy = MPOL_BIND;
+			else if (!strcmp(value,"interleave"))
+				*policy = MPOL_INTERLEAVE;
+			else
+				goto bad_val;
+		} else if (!strcmp(this_char,"mpol_nodelist")) {
+			nodelist_parse(value, *policy_nodes);
 		} else {
 			printk(KERN_ERR "tmpfs: Bad mount option %s\n",
 			       this_char);
@@ -1917,12 +1934,14 @@
 	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 	unsigned long max_blocks = sbinfo->max_blocks;
 	unsigned long max_inodes = sbinfo->max_inodes;
+	int policy = sbinfo->policy;
+	nodemask_t policy_nodes = sbinfo->policy_nodes;
 	unsigned long blocks;
 	unsigned long inodes;
 	int error = -EINVAL;
 
-	if (shmem_parse_options(data, NULL, NULL, NULL,
-				&max_blocks, &max_inodes))
+	if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks,
+				&max_inodes, &policy, &policy_nodes))
 		return error;
 
 	spin_lock(&sbinfo->stat_lock);
@@ -1948,6 +1967,8 @@
 	sbinfo->free_blocks = max_blocks - blocks;
 	sbinfo->max_inodes  = max_inodes;
 	sbinfo->free_inodes = max_inodes - inodes;
+	sbinfo->policy = policy;
+	sbinfo->policy_nodes = policy_nodes;
 out:
 	spin_unlock(&sbinfo->stat_lock);
 	return error;
@@ -1972,6 +1993,8 @@
 	struct shmem_sb_info *sbinfo;
 	unsigned long blocks = 0;
 	unsigned long inodes = 0;
+	int policy = MPOL_DEFAULT;
+	nodemask_t policy_nodes = node_online_map;
 
 #ifdef CONFIG_TMPFS
 	/*
@@ -1984,8 +2007,8 @@
 		inodes = totalram_pages - totalhigh_pages;
 		if (inodes > blocks)
 			inodes = blocks;
-		if (shmem_parse_options(data, &mode, &uid, &gid,
-					&blocks, &inodes))
+		if (shmem_parse_options(data, &mode, &uid, &gid, &blocks,
+					&inodes, &policy, &policy_nodes))
 			return -EINVAL;
 	}
 #else
@@ -2003,6 +2026,8 @@
 	sbinfo->free_blocks = blocks;
 	sbinfo->max_inodes = inodes;
 	sbinfo->free_inodes = inodes;
+	sbinfo->policy = policy;
+	sbinfo->policy_nodes = policy_nodes;
 
 	sb->s_fs_info = sbinfo;
 	sb->s_maxbytes = SHMEM_MAX_BYTES;
diff --git a/net/Kconfig b/net/Kconfig
index 60f6f32..9296b269 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -159,6 +159,7 @@
 source "drivers/net/appletalk/Kconfig"
 source "net/x25/Kconfig"
 source "net/lapb/Kconfig"
+source "net/tipc/Kconfig"
 
 config NET_DIVERT
 	bool "Frame Diverter (EXPERIMENTAL)"
diff --git a/net/Makefile b/net/Makefile
index f5141b9..065796f 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
+obj-$(CONFIG_TIPC)		+= tipc/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 9f6e019..a29c123 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -15,6 +15,7 @@
 #include <linux/netfilter.h>
 #include <linux/module.h>
 #include <linux/ip.h>
+#include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/spinlock.h>
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 9eb9d00..a52665f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -287,7 +287,9 @@
  * no references or jumps that are out of range, no illegal
  * instructions, and must end with a RET instruction.
  *
- * Returns 0 if the rule set is legal or a negative errno code if not.
+ * All jumps are forward as they are not signed.
+ *
+ * Returns 0 if the rule set is legal or -EINVAL if not.
  */
 int sk_chk_filter(struct sock_filter *filter, int flen)
 {
@@ -299,7 +301,6 @@
 
 	/* check the filter code now */
 	for (pc = 0; pc < flen; pc++) {
-		/* all jumps are forward as they are not signed */
 		ftest = &filter[pc];
 
 		/* Only allow valid instructions */
@@ -383,11 +384,6 @@
 		}
 	}
 
-	/*
-	 * The program must end with a return. We don't care where they
-	 * jumped within the script (its always forwards) but in the end
-	 * they _will_ hit this.
-	 */
         return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL;
 }
 
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index 321287b..90d18b7 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -62,7 +62,7 @@
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
 {
 	if (ieee->networks)
 		return 0;
@@ -90,7 +90,7 @@
 	ieee->networks = NULL;
 }
 
-static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
 {
 	int i;
 
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 5e33803..7a12180 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -35,7 +35,7 @@
 
 #include <net/ieee80211.h>
 
-static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
 					struct sk_buff *skb,
 					struct ieee80211_rx_stats *rx_stats)
 {
@@ -165,7 +165,7 @@
  * Responsible for handling management control frames
  *
  * Called by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
 			struct ieee80211_rx_stats *rx_stats, u16 type,
 			u16 stype)
@@ -266,7 +266,7 @@
 }
 
 /* Called only as a tasklet (software IRQ), by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
 			   struct ieee80211_crypt_data *crypt)
 {
@@ -297,7 +297,7 @@
 }
 
 /* Called only as a tasklet (software IRQ), by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
 				struct sk_buff *skb, int keyidx,
 				struct ieee80211_crypt_data *crypt)
@@ -1156,7 +1156,7 @@
 
 /***************************************************/
 
-static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
+static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
 					 *beacon,
 					 struct ieee80211_network *network,
 					 struct ieee80211_rx_stats *stats)
@@ -1235,7 +1235,7 @@
 		!memcmp(src->ssid, dst->ssid, src->ssid_len));
 }
 
-static inline void update_network(struct ieee80211_network *dst,
+static void update_network(struct ieee80211_network *dst,
 				  struct ieee80211_network *src)
 {
 	int qos_active;
@@ -1294,7 +1294,7 @@
 	return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
 }
 
-static inline void ieee80211_process_probe_response(struct ieee80211_device
+static void ieee80211_process_probe_response(struct ieee80211_device
 						    *ieee, struct
 						    ieee80211_probe_response
 						    *beacon, struct ieee80211_rx_stats
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index e5b33c8..8fdd943 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -127,7 +127,7 @@
 static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
 static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
 
-static inline int ieee80211_copy_snap(u8 * data, u16 h_proto)
+static int ieee80211_copy_snap(u8 * data, u16 h_proto)
 {
 	struct ieee80211_snap_hdr *snap;
 	u8 *oui;
@@ -150,7 +150,7 @@
 	return SNAP_SIZE + sizeof(u16);
 }
 
-static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
 					     struct sk_buff *frag, int hdr_len)
 {
 	struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 406d5b9..23e1630 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -42,7 +42,7 @@
 };
 
 #define MAX_CUSTOM_LEN 64
-static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
+static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
 					   char *start, char *stop,
 					   struct ieee80211_network *network)
 {
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index a9893ec..db78303 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -182,6 +182,7 @@
 
 config IP_NF_IPTABLES
 	tristate "IP tables support (required for filtering/masq/NAT)"
+	depends on NETFILTER_XTABLES
 	help
 	  iptables is a general, extensible packet identification framework.
 	  The packet filtering and full NAT (masquerading, port forwarding,
@@ -191,16 +192,6 @@
 	  To compile it as a module, choose M here.  If unsure, say N.
 
 # The matches.
-config IP_NF_MATCH_LIMIT
-	tristate "limit match support"
-	depends on IP_NF_IPTABLES
-	help
-	  limit matching allows you to control the rate at which a rule can be
-	  matched: mainly useful in combination with the LOG target ("LOG
-	  target support", below) and to avoid some Denial of Service attacks.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_IPRANGE
 	tristate "IP range match support"
 	depends on IP_NF_IPTABLES
@@ -210,37 +201,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_MAC
-	tristate "MAC address match support"
-	depends on IP_NF_IPTABLES
-	help
-	  MAC matching allows you to match packets based on the source
-	  Ethernet address of the packet.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_PKTTYPE
-	tristate "Packet type match support"
-	depends on IP_NF_IPTABLES
-	help
-	  Packet type matching allows you to match a packet by
-	  its "class", eg. BROADCAST, MULTICAST, ...
-
-	  Typical usage:
-	  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_MARK
-	tristate "netfilter MARK match support"
-	depends on IP_NF_IPTABLES
-	help
-	  Netfilter mark matching allows you to match packets based on the
-	  `nfmark' value in the packet.  This can be set by the MARK target
-	  (see below).
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_MULTIPORT
 	tristate "Multiple port match support"
 	depends on IP_NF_IPTABLES
@@ -301,15 +261,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_LENGTH
-	tristate "LENGTH match support"
-	depends on IP_NF_IPTABLES
-	help
-	  This option allows you to match the length of a packet against a
-	  specific value or range of values.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_TTL
 	tristate "TTL match support"
 	depends on IP_NF_IPTABLES
@@ -319,50 +270,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_TCPMSS
-	tristate "tcpmss match support"
-	depends on IP_NF_IPTABLES
-	help
-	  This option adds a `tcpmss' match, which allows you to examine the
-	  MSS value of TCP SYN packets, which control the maximum packet size
-	  for that connection.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_HELPER
-	tristate "Helper match support"
-	depends on IP_NF_IPTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-	help
-	  Helper matching allows you to match packets in dynamic connections
-	  tracked by a conntrack-helper, ie. ip_conntrack_ftp
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_MATCH_STATE
-	tristate "Connection state match support"
-	depends on IP_NF_IPTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-	help
-	  Connection state matching allows you to match packets based on their
-	  relationship to a tracked connection (ie. previous packets).  This
-	  is a powerful tool for packet classification.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_CONNTRACK
-	tristate "Connection tracking match support"
-	depends on IP_NF_IPTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-	help
-	  This is a general conntrack match module, a superset of the state match.
-
-	  It allows matching on additional conntrack information, which is
-	  useful in complex configurations, such as NAT gateways with multiple
-	  internet links or tunnels.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_OWNER
 	tristate "Owner match support"
 	depends on IP_NF_IPTABLES
@@ -372,15 +279,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_PHYSDEV
-	tristate "Physdev match support"
-	depends on IP_NF_IPTABLES && BRIDGE_NETFILTER
-	help
-	  Physdev packet matching matches against the physical bridge ports
-	  the IP packet arrived on or will leave by.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_ADDRTYPE
 	tristate  'address type match support'
 	depends on IP_NF_IPTABLES
@@ -391,75 +289,6 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-config IP_NF_MATCH_REALM
-	tristate  'realm match support'
-	depends on IP_NF_IPTABLES
-	select NET_CLS_ROUTE
-	help
-	  This option adds a `realm' match, which allows you to use the realm
-	  key from the routing subsystem inside iptables.
-	
-	  This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option 
-	  in tc world.
-	
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-config IP_NF_MATCH_SCTP
-	tristate  'SCTP protocol match support'
-	depends on IP_NF_IPTABLES
-	help
-	  With this option enabled, you will be able to use the iptables
-	  `sctp' match in order to match on SCTP source/destination ports
-	  and SCTP chunk types.
-
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-config IP_NF_MATCH_DCCP
-	tristate  'DCCP protocol match support'
-	depends on IP_NF_IPTABLES
-	help
-	  With this option enabled, you will be able to use the iptables
-	  `dccp' match in order to match on DCCP source/destination ports
-	  and DCCP flags.
-
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-config IP_NF_MATCH_COMMENT
-	tristate  'comment match support'
-	depends on IP_NF_IPTABLES
-	help
-	  This option adds a `comment' dummy-match, which allows you to put
-	  comments in your iptables ruleset.
-
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-config IP_NF_MATCH_CONNMARK
-	tristate  'Connection mark match support'
-	depends on IP_NF_IPTABLES
-	depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
-	help
-	  This option adds a `connmark' match, which allows you to match the
-	  connection mark value previously set for the session by `CONNMARK'. 
-	
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  The module will be called
-	  ipt_connmark.o.  If unsure, say `N'.
-
-config IP_NF_MATCH_CONNBYTES
-	tristate  'Connection byte/packet counter match support'
-	depends on IP_NF_IPTABLES
-	depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || (NF_CT_ACCT && NF_CONNTRACK_IPV4)
-	help
-	  This option adds a `connbytes' match, which allows you to match the
-	  number of bytes and/or packets for each direction within a connection.
-
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
 config IP_NF_MATCH_HASHLIMIT
 	tristate  'hashlimit match support'
 	depends on IP_NF_IPTABLES
@@ -474,19 +303,6 @@
 	  destination IP' or `500pps from any given source IP'  with a single
 	  IPtables rule.
 
-config IP_NF_MATCH_STRING
-	tristate  'string match support'
-	depends on IP_NF_IPTABLES 
-	select TEXTSEARCH
-	select TEXTSEARCH_KMP
-	select TEXTSEARCH_BM
-	select TEXTSEARCH_FSM
-	help
-	  This option adds a `string' match, which allows you to look for
-	  pattern matchings in packets.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_POLICY
        tristate "IPsec policy match support"
        depends on IP_NF_IPTABLES && XFRM
@@ -572,17 +388,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_NFQUEUE
-	tristate "NFQUEUE Target Support"
-	depends on IP_NF_IPTABLES
-	help
-	  This Target replaced the old obsolete QUEUE target.
-
-	  As opposed to QUEUE, it supports 65535 different queues,
-	  not just one.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 # NAT + specific targets
 config IP_NF_NAT
 	tristate "Full NAT"
@@ -735,31 +540,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_MARK
-	tristate "MARK target support"
-	depends on IP_NF_MANGLE
-	help
-	  This option adds a `MARK' target, which allows you to create rules
-	  in the `mangle' table which alter the netfilter mark (nfmark) field
-	  associated with the packet prior to routing. This can change
-	  the routing method (see `Use netfilter MARK value as routing
-	  key') and can also be used by other subsystems to change their
-	  behavior.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_TARGET_CLASSIFY
-	tristate "CLASSIFY target support"
-	depends on IP_NF_MANGLE
-	help
-	  This option adds a `CLASSIFY' target, which enables the user to set
-	  the priority of a packet. Some qdiscs can use this value for
-	  classification, among these are:
-
-  	  atm, cbq, dsmark, pfifo_fast, htb, prio
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_TARGET_TTL
 	tristate  'TTL target support'
 	depends on IP_NF_MANGLE
@@ -774,19 +554,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_CONNMARK
-	tristate  'CONNMARK target support'
-	depends on IP_NF_MANGLE
-	depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
-	help
-	  This option adds a `CONNMARK' target, which allows one to manipulate
-	  the connection mark value.  Similar to the MARK target, but
-	  affects the connection mark value rather than the packet mark value.
-	
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  The module will be called
-	  ipt_CONNMARK.o.  If unsure, say `N'.
-
 config IP_NF_TARGET_CLUSTERIP
 	tristate "CLUSTERIP target support (EXPERIMENTAL)"
 	depends on IP_NF_MANGLE && EXPERIMENTAL
@@ -810,23 +577,10 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-config IP_NF_TARGET_NOTRACK
-	tristate  'NOTRACK target support'
-	depends on IP_NF_RAW
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-	help
-	  The NOTRACK target allows a select rule to specify
-	  which packets *not* to enter the conntrack/NAT
-	  subsystem with all the consequences (no ICMP error tracking,
-	  no protocol helpers for the selected packets).
-	
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-
 # ARP tables
 config IP_NF_ARPTABLES
 	tristate "ARP tables support"
+	depends on NETFILTER_XTABLES
 	help
 	  arptables is a general, extensible packet identification framework.
 	  The ARP packet filtering and mangling (manipulation)subsystems
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 549b01a..bcefe64 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -47,14 +47,8 @@
 
 # matches
 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
-obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
-obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
-obj-$(CONFIG_IP_NF_MATCH_DCCP) += ipt_dccp.o
-obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
-obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
-obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
@@ -62,40 +56,25 @@
 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
 obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
-obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
-obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
-obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
-obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
-obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
-obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
-obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
-obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
 obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
-obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
-obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
 obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
 obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
-obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
-obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
-obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
-obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
 obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
-obj-$(CONFIG_IP_NF_TARGET_NFQUEUE) += ipt_NFQUEUE.o
 
 # generic ARP tables
 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index b6d5284..afe3d8f 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -24,6 +24,7 @@
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp/arp_tables.h>
 
 MODULE_LICENSE("GPL");
@@ -55,28 +56,9 @@
 #else
 #define ARP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
-static DECLARE_MUTEX(arpt_mutex);
-
-#define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
 #include <linux/netfilter_ipv4/listhelp.h>
 
-struct arpt_table_info {
-	unsigned int size;
-	unsigned int number;
-	unsigned int initial_entries;
-	unsigned int hook_entry[NF_ARP_NUMHOOKS];
-	unsigned int underflow[NF_ARP_NUMHOOKS];
-	void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(arpt_target);
-static LIST_HEAD(arpt_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
 static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
 				      char *hdr_addr, int len)
 {
@@ -223,9 +205,9 @@
 }
 
 static unsigned int arpt_error(struct sk_buff **pskb,
-			       unsigned int hooknum,
 			       const struct net_device *in,
 			       const struct net_device *out,
+			       unsigned int hooknum,
 			       const void *targinfo,
 			       void *userinfo)
 {
@@ -254,6 +236,7 @@
 	struct arpt_entry *e, *back;
 	const char *indev, *outdev;
 	void *table_base;
+	struct xt_table_info *private = table->private;
 
 	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
 	if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) +
@@ -265,9 +248,9 @@
 	outdev = out ? out->name : nulldevname;
 
 	read_lock_bh(&table->lock);
-	table_base = (void *)table->private->entries[smp_processor_id()];
-	e = get_entry(table_base, table->private->hook_entry[hook]);
-	back = get_entry(table_base, table->private->underflow[hook]);
+	table_base = (void *)private->entries[smp_processor_id()];
+	e = get_entry(table_base, private->hook_entry[hook]);
+	back = get_entry(table_base, private->underflow[hook]);
 
 	arp = (*pskb)->nh.arph;
 	do {
@@ -315,8 +298,8 @@
 				 * abs. verdicts
 				 */
 				verdict = t->u.kernel.target->target(pskb,
-								     hook,
 								     in, out,
+								     hook,
 								     t->data,
 								     userdata);
 
@@ -341,106 +324,6 @@
 		return verdict;
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct arpt_table *find_table_lock(const char *name)
-{
-	struct arpt_table *t;
-
-	if (down_interruptible(&arpt_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &arpt_tables, list)
-		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-			return t;
-	up(&arpt_mutex);
-	return NULL;
-}
-
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct arpt_target *find_target(const char *name, u8 revision)
-{
-	struct arpt_target *t;
-	int err = 0;
-
-	if (down_interruptible(&arpt_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &arpt_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision == revision) {
-				if (try_module_get(t->me)) {
-					up(&arpt_mutex);
-					return t;
-				}
-			} else
-				err = -EPROTOTYPE; /* Found something. */
-		}
-	}
-	up(&arpt_mutex);
-	return ERR_PTR(err);
-}
-
-struct arpt_target *arpt_find_target(const char *name, u8 revision)
-{
-	struct arpt_target *target;
-
-	target = try_then_request_module(find_target(name, revision),
-					 "arpt_%s", name);
-	if (IS_ERR(target) || !target)
-		return NULL;
-	return target;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-	struct arpt_target *t;
-	int have_rev = 0;
-
-	list_for_each_entry(t, &arpt_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision > *bestp)
-				*bestp = t->revision;
-			if (t->revision == revision)
-				have_rev =1;
-		}
-	}
-	return have_rev;
-}
-
-/* Returns true or false (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-				int (*revfn)(const char *, u8, int *),
-				int *err)
-{
-	int have_rev, best = -1;
-
-	if (down_interruptible(&arpt_mutex) != 0) {
-		*err = -EINTR;
-		return 1;
-	}
-	have_rev = revfn(name, revision, &best);
-	up(&arpt_mutex);
-
-	/* Nothing at all?  Return 0 to try loading module. */
-	if (best == -1) {
-		*err = -ENOENT;
-		return 0;
-	}
-
-	*err = best;
-	if (!have_rev)
-		*err = -EPROTONOSUPPORT;
-	return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int unconditional(const struct arpt_arp *arp)
 {
@@ -456,7 +339,7 @@
 /* Figures out from what hook each rule can be called: returns 0 if
  * there are loops.  Puts hook bitmask in comefrom.
  */
-static int mark_source_chains(struct arpt_table_info *newinfo,
+static int mark_source_chains(struct xt_table_info *newinfo,
 			      unsigned int valid_hooks, void *entry0)
 {
 	unsigned int hook;
@@ -587,8 +470,8 @@
 	}
 
 	t = arpt_get_target(e);
-	target = try_then_request_module(find_target(t->u.user.name,
-						     t->u.user.revision),
+	target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
+							t->u.user.revision),
 					 "arpt_%s", t->u.user.name);
 	if (IS_ERR(target) || !target) {
 		duprintf("check_entry: `%s' not found\n", t->u.user.name);
@@ -622,7 +505,7 @@
 }
 
 static inline int check_entry_size_and_hooks(struct arpt_entry *e,
-					     struct arpt_table_info *newinfo,
+					     struct xt_table_info *newinfo,
 					     unsigned char *base,
 					     unsigned char *limit,
 					     const unsigned int *hook_entries,
@@ -656,7 +539,7 @@
            < 0 (not ARPT_RETURN). --RR */
 
 	/* Clear counters and comefrom */
-	e->counters = ((struct arpt_counters) { 0, 0 });
+	e->counters = ((struct xt_counters) { 0, 0 });
 	e->comefrom = 0;
 
 	(*i)++;
@@ -683,7 +566,7 @@
  */
 static int translate_table(const char *name,
 			   unsigned int valid_hooks,
-			   struct arpt_table_info *newinfo,
+			   struct xt_table_info *newinfo,
 			   void *entry0,
 			   unsigned int size,
 			   unsigned int number,
@@ -764,34 +647,9 @@
 	return ret;
 }
 
-static struct arpt_table_info *replace_table(struct arpt_table *table,
-					     unsigned int num_counters,
-					     struct arpt_table_info *newinfo,
-					     int *error)
-{
-	struct arpt_table_info *oldinfo;
-
-	/* Do the substitution. */
-	write_lock_bh(&table->lock);
-	/* Check inside lock: is the old number correct? */
-	if (num_counters != table->private->number) {
-		duprintf("num_counters != table->private->number (%u/%u)\n",
-			 num_counters, table->private->number);
-		write_unlock_bh(&table->lock);
-		*error = -EAGAIN;
-		return NULL;
-	}
-	oldinfo = table->private;
-	table->private = newinfo;
-	newinfo->initial_entries = oldinfo->initial_entries;
-	write_unlock_bh(&table->lock);
-
-	return oldinfo;
-}
-
 /* Gets counters. */
 static inline int add_entry_to_counter(const struct arpt_entry *e,
-				       struct arpt_counters total[],
+				       struct xt_counters total[],
 				       unsigned int *i)
 {
 	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -801,7 +659,7 @@
 }
 
 static inline int set_entry_to_counter(const struct arpt_entry *e,
-				       struct arpt_counters total[],
+				       struct xt_counters total[],
 				       unsigned int *i)
 {
 	SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -810,8 +668,8 @@
 	return 0;
 }
 
-static void get_counters(const struct arpt_table_info *t,
-			 struct arpt_counters counters[])
+static void get_counters(const struct xt_table_info *t,
+			 struct xt_counters counters[])
 {
 	unsigned int cpu;
 	unsigned int i;
@@ -849,7 +707,8 @@
 {
 	unsigned int off, num, countersize;
 	struct arpt_entry *e;
-	struct arpt_counters *counters;
+	struct xt_counters *counters;
+	struct xt_table_info *private = table->private;
 	int ret = 0;
 	void *loc_cpu_entry;
 
@@ -857,18 +716,18 @@
 	 * (other than comefrom, which userspace doesn't care
 	 * about).
 	 */
-	countersize = sizeof(struct arpt_counters) * table->private->number;
-	counters = vmalloc(countersize);
+	countersize = sizeof(struct xt_counters) * private->number;
+	counters = vmalloc_node(countersize, numa_node_id());
 
 	if (counters == NULL)
 		return -ENOMEM;
 
 	/* First, sum counters... */
 	write_lock_bh(&table->lock);
-	get_counters(table->private, counters);
+	get_counters(private, counters);
 	write_unlock_bh(&table->lock);
 
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
 	/* ... then copy entire thing ... */
 	if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
 		ret = -EFAULT;
@@ -911,75 +770,34 @@
 	int ret;
 	struct arpt_table *t;
 
-	t = find_table_lock(entries->name);
+	t = xt_find_table_lock(NF_ARP, entries->name);
 	if (t || !IS_ERR(t)) {
+		struct xt_table_info *private = t->private;
 		duprintf("t->private->number = %u\n",
-			 t->private->number);
-		if (entries->size == t->private->size)
-			ret = copy_entries_to_user(t->private->size,
+			 private->number);
+		if (entries->size == private->size)
+			ret = copy_entries_to_user(private->size,
 						   t, uptr->entrytable);
 		else {
 			duprintf("get_entries: I've got %u not %u!\n",
-				 t->private->size,
-				 entries->size);
+				 private->size, entries->size);
 			ret = -EINVAL;
 		}
 		module_put(t->me);
-		up(&arpt_mutex);
+		xt_table_unlock(t);
 	} else
 		ret = t ? PTR_ERR(t) : -ENOENT;
 
 	return ret;
 }
 
-static void free_table_info(struct arpt_table_info *info)
-{
-	int cpu;
-	for_each_cpu(cpu) {
-		if (info->size <= PAGE_SIZE)
-			kfree(info->entries[cpu]);
-		else
-			vfree(info->entries[cpu]);
-	}
-	kfree(info);
-}
-
-static struct arpt_table_info *alloc_table_info(unsigned int size)
-{
-	struct arpt_table_info *newinfo;
-	int cpu;
-	
-	newinfo = kzalloc(sizeof(struct arpt_table_info), GFP_KERNEL);
-	if (!newinfo)
-		return NULL;
-
-	newinfo->size = size;
-
-	for_each_cpu(cpu) {
-		if (size <= PAGE_SIZE)
-			newinfo->entries[cpu] = kmalloc_node(size,
-							GFP_KERNEL,
-							cpu_to_node(cpu));
-		else
-			newinfo->entries[cpu] = vmalloc_node(size,
-							     cpu_to_node(cpu));
-
-		if (newinfo->entries[cpu] == NULL) {
-			free_table_info(newinfo);
-			return NULL;
-		}
-	}
-
-	return newinfo;
-}
-
 static int do_replace(void __user *user, unsigned int len)
 {
 	int ret;
 	struct arpt_replace tmp;
 	struct arpt_table *t;
-	struct arpt_table_info *newinfo, *oldinfo;
-	struct arpt_counters *counters;
+	struct xt_table_info *newinfo, *oldinfo;
+	struct xt_counters *counters;
 	void *loc_cpu_entry, *loc_cpu_old_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
@@ -989,11 +807,7 @@
 	if (len != sizeof(tmp) + tmp.size)
 		return -ENOPROTOOPT;
 
-	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-	if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-		return -ENOMEM;
-
-	newinfo = alloc_table_info(tmp.size);
+	newinfo = xt_alloc_table_info(tmp.size);
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1005,7 +819,7 @@
 		goto free_newinfo;
 	}
 
-	counters = vmalloc(tmp.num_counters * sizeof(struct arpt_counters));
+	counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
 	if (!counters) {
 		ret = -ENOMEM;
 		goto free_newinfo;
@@ -1019,7 +833,7 @@
 
 	duprintf("arp_tables: Translated table\n");
 
-	t = try_then_request_module(find_table_lock(tmp.name),
+	t = try_then_request_module(xt_find_table_lock(NF_ARP, tmp.name),
 				    "arptable_%s", tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1034,7 +848,7 @@
 		goto put_module;
 	}
 
-	oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+	oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
 	if (!oldinfo)
 		goto put_module;
 
@@ -1054,23 +868,23 @@
 	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
 	ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
 
-	free_table_info(oldinfo);
+	xt_free_table_info(oldinfo);
 	if (copy_to_user(tmp.counters, counters,
-			 sizeof(struct arpt_counters) * tmp.num_counters) != 0)
+			 sizeof(struct xt_counters) * tmp.num_counters) != 0)
 		ret = -EFAULT;
 	vfree(counters);
-	up(&arpt_mutex);
+	xt_table_unlock(t);
 	return ret;
 
  put_module:
 	module_put(t->me);
-	up(&arpt_mutex);
+	xt_table_unlock(t);
  free_newinfo_counters_untrans:
 	ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
  free_newinfo_counters:
 	vfree(counters);
  free_newinfo:
-	free_table_info(newinfo);
+	xt_free_table_info(newinfo);
 	return ret;
 }
 
@@ -1078,7 +892,7 @@
  * and everything is OK.
  */
 static inline int add_counter_to_entry(struct arpt_entry *e,
-				       const struct arpt_counters addme[],
+				       const struct xt_counters addme[],
 				       unsigned int *i)
 {
 
@@ -1091,15 +905,16 @@
 static int do_add_counters(void __user *user, unsigned int len)
 {
 	unsigned int i;
-	struct arpt_counters_info tmp, *paddc;
+	struct xt_counters_info tmp, *paddc;
 	struct arpt_table *t;
+	struct xt_table_info *private;
 	int ret = 0;
 	void *loc_cpu_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 		return -EFAULT;
 
-	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct arpt_counters))
+	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
 		return -EINVAL;
 
 	paddc = vmalloc(len);
@@ -1111,29 +926,30 @@
 		goto free;
 	}
 
-	t = find_table_lock(tmp.name);
+	t = xt_find_table_lock(NF_ARP, tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
 		goto free;
 	}
 
 	write_lock_bh(&t->lock);
-	if (t->private->number != paddc->num_counters) {
+	private = t->private;
+	if (private->number != paddc->num_counters) {
 		ret = -EINVAL;
 		goto unlock_up_free;
 	}
 
 	i = 0;
 	/* Choose the copy that is on our node */
-	loc_cpu_entry = t->private->entries[smp_processor_id()];
+	loc_cpu_entry = private->entries[smp_processor_id()];
 	ARPT_ENTRY_ITERATE(loc_cpu_entry,
-			   t->private->size,
+			   private->size,
 			   add_counter_to_entry,
 			   paddc->counters,
 			   &i);
  unlock_up_free:
 	write_unlock_bh(&t->lock);
-	up(&arpt_mutex);
+	xt_table_unlock(t);
 	module_put(t->me);
  free:
 	vfree(paddc);
@@ -1190,25 +1006,26 @@
 		}
 		name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
 
-		t = try_then_request_module(find_table_lock(name),
+		t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
 					    "arptable_%s", name);
 		if (t && !IS_ERR(t)) {
 			struct arpt_getinfo info;
+			struct xt_table_info *private = t->private;
 
 			info.valid_hooks = t->valid_hooks;
-			memcpy(info.hook_entry, t->private->hook_entry,
+			memcpy(info.hook_entry, private->hook_entry,
 			       sizeof(info.hook_entry));
-			memcpy(info.underflow, t->private->underflow,
+			memcpy(info.underflow, private->underflow,
 			       sizeof(info.underflow));
-			info.num_entries = t->private->number;
-			info.size = t->private->size;
+			info.num_entries = private->number;
+			info.size = private->size;
 			strcpy(info.name, name);
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
 			else
 				ret = 0;
-			up(&arpt_mutex);
+			xt_table_unlock(t);
 			module_put(t->me);
 		} else
 			ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1233,7 +1050,7 @@
 	}
 
 	case ARPT_SO_GET_REVISION_TARGET: {
-		struct arpt_get_revision rev;
+		struct xt_get_revision rev;
 
 		if (*len != sizeof(rev)) {
 			ret = -EINVAL;
@@ -1244,8 +1061,8 @@
 			break;
 		}
 
-		try_then_request_module(find_revision(rev.name, rev.revision,
-						      target_revfn, &ret),
+		try_then_request_module(xt_find_revision(NF_ARP, rev.name,
+							 rev.revision, 1, &ret),
 					"arpt_%s", rev.name);
 		break;
 	}
@@ -1258,38 +1075,16 @@
 	return ret;
 }
 
-/* Registration hooks for targets. */
-int arpt_register_target(struct arpt_target *target)
-{
-	int ret;
-
-	ret = down_interruptible(&arpt_mutex);
-	if (ret != 0)
-		return ret;
-
-	list_add(&target->list, &arpt_target);
-	up(&arpt_mutex);
-
-	return ret;
-}
-
-void arpt_unregister_target(struct arpt_target *target)
-{
-	down(&arpt_mutex);
-	LIST_DELETE(&arpt_target, target);
-	up(&arpt_mutex);
-}
-
 int arpt_register_table(struct arpt_table *table,
 			const struct arpt_replace *repl)
 {
 	int ret;
-	struct arpt_table_info *newinfo;
-	static struct arpt_table_info bootstrap
+	struct xt_table_info *newinfo;
+	static struct xt_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 	void *loc_cpu_entry;
 
-	newinfo = alloc_table_info(repl->size);
+	newinfo = xt_alloc_table_info(repl->size);
 	if (!newinfo) {
 		ret = -ENOMEM;
 		return ret;
@@ -1304,60 +1099,33 @@
 			      repl->num_entries,
 			      repl->hook_entry,
 			      repl->underflow);
+
 	duprintf("arpt_register_table: translate table gives %d\n", ret);
 	if (ret != 0) {
-		free_table_info(newinfo);
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	ret = down_interruptible(&arpt_mutex);
-	if (ret != 0) {
-		free_table_info(newinfo);
+	if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	/* Don't autoload: we'd eat our tail... */
-	if (list_named_find(&arpt_tables, table->name)) {
-		ret = -EEXIST;
-		goto free_unlock;
-	}
-
-	/* Simplifies replace_table code. */
-	table->private = &bootstrap;
-	if (!replace_table(table, 0, newinfo, &ret))
-		goto free_unlock;
-
-	duprintf("table->private->number = %u\n",
-		 table->private->number);
-	
-	/* save number of initial entries */
-	table->private->initial_entries = table->private->number;
-
-	rwlock_init(&table->lock);
-	list_prepend(&arpt_tables, table);
-
- unlock:
-	up(&arpt_mutex);
-	return ret;
-
- free_unlock:
-	free_table_info(newinfo);
-	goto unlock;
+	return 0;
 }
 
 void arpt_unregister_table(struct arpt_table *table)
 {
+	struct xt_table_info *private;
 	void *loc_cpu_entry;
 
-	down(&arpt_mutex);
-	LIST_DELETE(&arpt_tables, table);
-	up(&arpt_mutex);
+	private = xt_unregister_table(table);
 
 	/* Decrease module usage counts and free resources */
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-	ARPT_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+	ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
 			   cleanup_entry, NULL);
-	free_table_info(table->private);
+	xt_free_table_info(private);
 }
 
 /* The built-in targets: standard (NULL) and error. */
@@ -1380,52 +1148,15 @@
 	.get		= do_arpt_get_ctl,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const struct arpt_table *t,
-			     off_t start_offset, char *buffer, int length,
-			     off_t *pos, unsigned int *count)
-{
-	if ((*count)++ >= start_offset) {
-		unsigned int namelen;
-
-		namelen = sprintf(buffer + *pos, "%s\n", t->name);
-		if (*pos + namelen > length) {
-			/* Stop iterating */
-			return 1;
-		}
-		*pos += namelen;
-	}
-	return 0;
-}
-
-static int arpt_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&arpt_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&arpt_tables, print_name, struct arpt_table *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&arpt_mutex);
-
-	/* `start' hack - see fs/proc/generic.c line ~105 */
-	*start=(char *)((unsigned long)count-offset);
-	return pos;
-}
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
 	int ret;
 
+	xt_proto_init(NF_ARP);
+
 	/* Noone else will be downing sem now, so we won't sleep */
-	down(&arpt_mutex);
-	list_append(&arpt_target, &arpt_standard_target);
-	list_append(&arpt_target, &arpt_error_target);
-	up(&arpt_mutex);
+	xt_register_target(NF_ARP, &arpt_standard_target);
+	xt_register_target(NF_ARP, &arpt_error_target);
 
 	/* Register setsockopt */
 	ret = nf_register_sockopt(&arpt_sockopts);
@@ -1434,19 +1165,6 @@
 		return ret;
 	}
 
-#ifdef CONFIG_PROC_FS
-	{
-		struct proc_dir_entry *proc;
-
-		proc = proc_net_create("arp_tables_names", 0, arpt_get_tables);
-		if (!proc) {
-			nf_unregister_sockopt(&arpt_sockopts);
-			return -ENOMEM;
-		}
-		proc->owner = THIS_MODULE;
-	}
-#endif
-
 	printk("arp_tables: (C) 2002 David S. Miller\n");
 	return 0;
 }
@@ -1454,16 +1172,12 @@
 static void __exit fini(void)
 {
 	nf_unregister_sockopt(&arpt_sockopts);
-#ifdef CONFIG_PROC_FS
-	proc_net_remove("arp_tables_names");
-#endif
+	xt_proto_fini(NF_ARP);
 }
 
 EXPORT_SYMBOL(arpt_register_table);
 EXPORT_SYMBOL(arpt_unregister_table);
 EXPORT_SYMBOL(arpt_do_table);
-EXPORT_SYMBOL(arpt_register_target);
-EXPORT_SYMBOL(arpt_unregister_target);
 
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index 3e592ec..c97650a 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -8,8 +8,9 @@
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in,
-   const struct net_device *out, const void *targinfo, void *userinfo)
+target(struct sk_buff **pskb, const struct net_device *in,
+   const struct net_device *out, unsigned int hooknum, const void *targinfo,
+   void *userinfo)
 {
 	const struct arpt_mangle *mangle = targinfo;
 	struct arphdr *arp;
@@ -64,7 +65,7 @@
 }
 
 static int
-checkentry(const char *tablename, const struct arpt_entry *e, void *targinfo,
+checkentry(const char *tablename, const void *e, void *targinfo,
    unsigned int targinfosize, unsigned int hook_mask)
 {
 	const struct arpt_mangle *mangle = targinfo;
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 0d759f5..f6ab45f 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -145,6 +145,7 @@
 	.lock		= RW_LOCK_UNLOCKED,
 	.private	= NULL,
 	.me		= THIS_MODULE,
+	.af		= NF_ARP,
 };
 
 /* The work comes in here from netfilter.c */
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 9dec129..833fcb4 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -944,7 +944,7 @@
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
-void need_ip_conntrack(void)
+void need_conntrack(void)
 {
 }
 
@@ -962,7 +962,7 @@
 EXPORT_SYMBOL(invert_tuplepr);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
-EXPORT_SYMBOL(need_ip_conntrack);
+EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_iterate_cleanup);
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index cb66b8b..1de8628 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -95,6 +95,7 @@
 	.valid_hooks	= NAT_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
 	.me		= THIS_MODULE,
+	.af		= AF_INET,
 };
 
 /* Source NAT */
@@ -168,7 +169,7 @@
 }
 
 static int ipt_snat_checkentry(const char *tablename,
-			       const struct ipt_entry *e,
+			       const void *entry,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
@@ -201,7 +202,7 @@
 }
 
 static int ipt_dnat_checkentry(const char *tablename,
-			       const struct ipt_entry *e,
+			       const void *entry,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 8b8a1f0..ad438fb 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -364,7 +364,7 @@
 {
 	int ret = 0;
 
-	need_ip_conntrack();
+	need_conntrack();
 
 	if (!init) goto cleanup;
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 877bc96..2371b20 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -2,7 +2,7 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
- * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
  *
  * 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
@@ -11,6 +11,8 @@
  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  * 	- increase module usage count as soon as we have rules inside
  * 	  a table
+ * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
+ * 	- Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
  */
 #include <linux/config.h>
 #include <linux/cache.h>
@@ -20,8 +22,6 @@
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
 #include <linux/icmp.h>
 #include <net/ip.h>
 #include <asm/uaccess.h>
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/cpumask.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 MODULE_LICENSE("GPL");
@@ -62,14 +63,6 @@
 #else
 #define IP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-
-static DECLARE_MUTEX(ipt_mutex);
-
-/* Must have mutex */
-#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
-#include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
 /* All the better to debug you with... */
@@ -86,36 +79,6 @@
 
    Hence the start of any table is given by get_table() below.  */
 
-/* The table itself */
-struct ipt_table_info
-{
-	/* Size per table */
-	unsigned int size;
-	/* Number of entries: FIXME. --RR */
-	unsigned int number;
-	/* Initial number of entries. Needed for module usage count */
-	unsigned int initial_entries;
-
-	/* Entry points and underflows */
-	unsigned int hook_entry[NF_IP_NUMHOOKS];
-	unsigned int underflow[NF_IP_NUMHOOKS];
-
-	/* ipt_entry tables: one per CPU */
-	void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(ipt_target);
-static LIST_HEAD(ipt_match);
-static LIST_HEAD(ipt_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
-#if 0
-#define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
-#define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
-#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
-#endif
-
 /* Returns whether matches rule or not. */
 static inline int
 ip_packet_match(const struct iphdr *ip,
@@ -234,7 +197,8 @@
 	     int *hotdrop)
 {
 	/* Stop iteration if it doesn't match */
-	if (!m->u.kernel.match->match(skb, in, out, m->data, offset, hotdrop))
+	if (!m->u.kernel.match->match(skb, in, out, m->data, offset, 
+	    skb->nh.iph->ihl*4, hotdrop))
 		return 1;
 	else
 		return 0;
@@ -265,6 +229,7 @@
 	const char *indev, *outdev;
 	void *table_base;
 	struct ipt_entry *e, *back;
+	struct xt_table_info *private = table->private;
 
 	/* Initialization */
 	ip = (*pskb)->nh.iph;
@@ -281,24 +246,11 @@
 
 	read_lock_bh(&table->lock);
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-	table_base = (void *)table->private->entries[smp_processor_id()];
-	e = get_entry(table_base, table->private->hook_entry[hook]);
-
-#ifdef CONFIG_NETFILTER_DEBUG
-	/* Check noone else using our table */
-	if (((struct ipt_entry *)table_base)->comefrom != 0xdead57ac
-	    && ((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec) {
-		printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
-		       smp_processor_id(),
-		       table->name,
-		       &((struct ipt_entry *)table_base)->comefrom,
-		       ((struct ipt_entry *)table_base)->comefrom);
-	}
-	((struct ipt_entry *)table_base)->comefrom = 0x57acc001;
-#endif
+	table_base = (void *)private->entries[smp_processor_id()];
+	e = get_entry(table_base, private->hook_entry[hook]);
 
 	/* For return from builtin chain */
-	back = get_entry(table_base, table->private->underflow[hook]);
+	back = get_entry(table_base, private->underflow[hook]);
 
 	do {
 		IP_NF_ASSERT(e);
@@ -384,9 +336,6 @@
 		}
 	} while (!hotdrop);
 
-#ifdef CONFIG_NETFILTER_DEBUG
-	((struct ipt_entry *)table_base)->comefrom = 0xdead57ac;
-#endif
 	read_unlock_bh(&table->lock);
 
 #ifdef DEBUG_ALLOW_ALL
@@ -398,145 +347,6 @@
 #endif
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_table *find_table_lock(const char *name)
-{
-	struct ipt_table *t;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &ipt_tables, list)
-		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-			return t;
-	up(&ipt_mutex);
-	return NULL;
-}
-
-/* Find match, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_match *find_match(const char *name, u8 revision)
-{
-	struct ipt_match *m;
-	int err = 0;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(m, &ipt_match, list) {
-		if (strcmp(m->name, name) == 0) {
-			if (m->revision == revision) {
-				if (try_module_get(m->me)) {
-					up(&ipt_mutex);
-					return m;
-				}
-			} else
-				err = -EPROTOTYPE; /* Found something. */
-		}
-	}
-	up(&ipt_mutex);
-	return ERR_PTR(err);
-}
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_target *find_target(const char *name, u8 revision)
-{
-	struct ipt_target *t;
-	int err = 0;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &ipt_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision == revision) {
-				if (try_module_get(t->me)) {
-					up(&ipt_mutex);
-					return t;
-				}
-			} else
-				err = -EPROTOTYPE; /* Found something. */
-		}
-	}
-	up(&ipt_mutex);
-	return ERR_PTR(err);
-}
-
-struct ipt_target *ipt_find_target(const char *name, u8 revision)
-{
-	struct ipt_target *target;
-
-	target = try_then_request_module(find_target(name, revision),
-					 "ipt_%s", name);
-	if (IS_ERR(target) || !target)
-		return NULL;
-	return target;
-}
-
-static int match_revfn(const char *name, u8 revision, int *bestp)
-{
-	struct ipt_match *m;
-	int have_rev = 0;
-
-	list_for_each_entry(m, &ipt_match, list) {
-		if (strcmp(m->name, name) == 0) {
-			if (m->revision > *bestp)
-				*bestp = m->revision;
-			if (m->revision == revision)
-				have_rev = 1;
-		}
-	}
-	return have_rev;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-	struct ipt_target *t;
-	int have_rev = 0;
-
-	list_for_each_entry(t, &ipt_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision > *bestp)
-				*bestp = t->revision;
-			if (t->revision == revision)
-				have_rev = 1;
-		}
-	}
-	return have_rev;
-}
-
-/* Returns true or false (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-				int (*revfn)(const char *, u8, int *),
-				int *err)
-{
-	int have_rev, best = -1;
-
-	if (down_interruptible(&ipt_mutex) != 0) {
-		*err = -EINTR;
-		return 1;
-	}
-	have_rev = revfn(name, revision, &best);
-	up(&ipt_mutex);
-
-	/* Nothing at all?  Return 0 to try loading module. */
-	if (best == -1) {
-		*err = -ENOENT;
-		return 0;
-	}
-
-	*err = best;
-	if (!have_rev)
-		*err = -EPROTONOSUPPORT;
-	return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int
 unconditional(const struct ipt_ip *ip)
@@ -553,7 +363,7 @@
 /* Figures out from what hook each rule can be called: returns 0 if
    there are loops.  Puts hook bitmask in comefrom. */
 static int
-mark_source_chains(struct ipt_table_info *newinfo,
+mark_source_chains(struct xt_table_info *newinfo,
 		   unsigned int valid_hooks, void *entry0)
 {
 	unsigned int hook;
@@ -699,7 +509,7 @@
 {
 	struct ipt_match *match;
 
-	match = try_then_request_module(find_match(m->u.user.name,
+	match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
 						   m->u.user.revision),
 					"ipt_%s", m->u.user.name);
 	if (IS_ERR(match) || !match) {
@@ -744,7 +554,8 @@
 		goto cleanup_matches;
 
 	t = ipt_get_target(e);
-	target = try_then_request_module(find_target(t->u.user.name,
+	target = try_then_request_module(xt_find_target(AF_INET,
+						     t->u.user.name,
 						     t->u.user.revision),
 					 "ipt_%s", t->u.user.name);
 	if (IS_ERR(target) || !target) {
@@ -781,7 +592,7 @@
 
 static inline int
 check_entry_size_and_hooks(struct ipt_entry *e,
-			   struct ipt_table_info *newinfo,
+			   struct xt_table_info *newinfo,
 			   unsigned char *base,
 			   unsigned char *limit,
 			   const unsigned int *hook_entries,
@@ -815,7 +626,7 @@
            < 0 (not IPT_RETURN). --RR */
 
 	/* Clear counters and comefrom */
-	e->counters = ((struct ipt_counters) { 0, 0 });
+	e->counters = ((struct xt_counters) { 0, 0 });
 	e->comefrom = 0;
 
 	(*i)++;
@@ -845,7 +656,7 @@
 static int
 translate_table(const char *name,
 		unsigned int valid_hooks,
-		struct ipt_table_info *newinfo,
+		struct xt_table_info *newinfo,
 		void *entry0,
 		unsigned int size,
 		unsigned int number,
@@ -922,48 +733,10 @@
 	return ret;
 }
 
-static struct ipt_table_info *
-replace_table(struct ipt_table *table,
-	      unsigned int num_counters,
-	      struct ipt_table_info *newinfo,
-	      int *error)
-{
-	struct ipt_table_info *oldinfo;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-	{
-		int cpu;
-
-		for_each_cpu(cpu) {
-			struct ipt_entry *table_base = newinfo->entries[cpu];
-			if (table_base)
-				table_base->comefrom = 0xdead57ac;
-		}
-	}
-#endif
-
-	/* Do the substitution. */
-	write_lock_bh(&table->lock);
-	/* Check inside lock: is the old number correct? */
-	if (num_counters != table->private->number) {
-		duprintf("num_counters != table->private->number (%u/%u)\n",
-			 num_counters, table->private->number);
-		write_unlock_bh(&table->lock);
-		*error = -EAGAIN;
-		return NULL;
-	}
-	oldinfo = table->private;
-	table->private = newinfo;
-	newinfo->initial_entries = oldinfo->initial_entries;
-	write_unlock_bh(&table->lock);
-
-	return oldinfo;
-}
-
 /* Gets counters. */
 static inline int
 add_entry_to_counter(const struct ipt_entry *e,
-		     struct ipt_counters total[],
+		     struct xt_counters total[],
 		     unsigned int *i)
 {
 	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -984,8 +757,8 @@
 }
 
 static void
-get_counters(const struct ipt_table_info *t,
-	     struct ipt_counters counters[])
+get_counters(const struct xt_table_info *t,
+	     struct xt_counters counters[])
 {
 	unsigned int cpu;
 	unsigned int i;
@@ -1024,14 +797,15 @@
 {
 	unsigned int off, num, countersize;
 	struct ipt_entry *e;
-	struct ipt_counters *counters;
+	struct xt_counters *counters;
+	struct xt_table_info *private = table->private;
 	int ret = 0;
 	void *loc_cpu_entry;
 
 	/* We need atomic snapshot of counters: rest doesn't change
 	   (other than comefrom, which userspace doesn't care
 	   about). */
-	countersize = sizeof(struct ipt_counters) * table->private->number;
+	countersize = sizeof(struct xt_counters) * private->number;
 	counters = vmalloc_node(countersize, numa_node_id());
 
 	if (counters == NULL)
@@ -1039,14 +813,14 @@
 
 	/* First, sum counters... */
 	write_lock_bh(&table->lock);
-	get_counters(table->private, counters);
+	get_counters(private, counters);
 	write_unlock_bh(&table->lock);
 
 	/* choose the copy that is on our node/cpu, ...
 	 * This choice is lazy (because current thread is
 	 * allowed to migrate to another cpu)
 	 */
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
 	/* ... then copy entire thing ... */
 	if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
 		ret = -EFAULT;
@@ -1108,74 +882,36 @@
 	int ret;
 	struct ipt_table *t;
 
-	t = find_table_lock(entries->name);
+	t = xt_find_table_lock(AF_INET, entries->name);
 	if (t && !IS_ERR(t)) {
+		struct xt_table_info *private = t->private;
 		duprintf("t->private->number = %u\n",
-			 t->private->number);
-		if (entries->size == t->private->size)
-			ret = copy_entries_to_user(t->private->size,
+			 private->number);
+		if (entries->size == private->size)
+			ret = copy_entries_to_user(private->size,
 						   t, uptr->entrytable);
 		else {
 			duprintf("get_entries: I've got %u not %u!\n",
-				 t->private->size,
+				 private->size,
 				 entries->size);
 			ret = -EINVAL;
 		}
 		module_put(t->me);
-		up(&ipt_mutex);
+		xt_table_unlock(t);
 	} else
 		ret = t ? PTR_ERR(t) : -ENOENT;
 
 	return ret;
 }
 
-static void free_table_info(struct ipt_table_info *info)
-{
-	int cpu;
-	for_each_cpu(cpu) {
-		if (info->size <= PAGE_SIZE)
-			kfree(info->entries[cpu]);
-		else
-			vfree(info->entries[cpu]);
-	}
-	kfree(info);
-}
-
-static struct ipt_table_info *alloc_table_info(unsigned int size)
-{
-	struct ipt_table_info *newinfo;
-	int cpu;
-
-	newinfo = kzalloc(sizeof(struct ipt_table_info), GFP_KERNEL);
-	if (!newinfo)
-		return NULL;
-
-	newinfo->size = size;
-
-	for_each_cpu(cpu) {
-		if (size <= PAGE_SIZE)
-			newinfo->entries[cpu] = kmalloc_node(size,
-				GFP_KERNEL,
-				cpu_to_node(cpu));
-		else
-			newinfo->entries[cpu] = vmalloc_node(size, cpu_to_node(cpu));
-		if (newinfo->entries[cpu] == 0) {
-			free_table_info(newinfo);
-			return NULL;
-		}
-	}
-
-	return newinfo;
-}
-
 static int
 do_replace(void __user *user, unsigned int len)
 {
 	int ret;
 	struct ipt_replace tmp;
 	struct ipt_table *t;
-	struct ipt_table_info *newinfo, *oldinfo;
-	struct ipt_counters *counters;
+	struct xt_table_info *newinfo, *oldinfo;
+	struct xt_counters *counters;
 	void *loc_cpu_entry, *loc_cpu_old_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
@@ -1185,11 +921,7 @@
 	if (len != sizeof(tmp) + tmp.size)
 		return -ENOPROTOOPT;
 
-	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-	if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-		return -ENOMEM;
-
-	newinfo = alloc_table_info(tmp.size);
+	newinfo = xt_alloc_table_info(tmp.size);
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1201,7 +933,7 @@
 		goto free_newinfo;
 	}
 
-	counters = vmalloc(tmp.num_counters * sizeof(struct ipt_counters));
+	counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
 	if (!counters) {
 		ret = -ENOMEM;
 		goto free_newinfo;
@@ -1215,7 +947,7 @@
 
 	duprintf("ip_tables: Translated table\n");
 
-	t = try_then_request_module(find_table_lock(tmp.name),
+	t = try_then_request_module(xt_find_table_lock(AF_INET, tmp.name),
 				    "iptable_%s", tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1230,7 +962,7 @@
 		goto put_module;
 	}
 
-	oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+	oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
 	if (!oldinfo)
 		goto put_module;
 
@@ -1249,23 +981,23 @@
 	/* Decrease module usage counts and free resource */
 	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
 	IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
-	free_table_info(oldinfo);
+	xt_free_table_info(oldinfo);
 	if (copy_to_user(tmp.counters, counters,
-			 sizeof(struct ipt_counters) * tmp.num_counters) != 0)
+			 sizeof(struct xt_counters) * tmp.num_counters) != 0)
 		ret = -EFAULT;
 	vfree(counters);
-	up(&ipt_mutex);
+	xt_table_unlock(t);
 	return ret;
 
  put_module:
 	module_put(t->me);
-	up(&ipt_mutex);
+	xt_table_unlock(t);
  free_newinfo_counters_untrans:
 	IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
  free_newinfo_counters:
 	vfree(counters);
  free_newinfo:
-	free_table_info(newinfo);
+	xt_free_table_info(newinfo);
 	return ret;
 }
 
@@ -1273,7 +1005,7 @@
  * and everything is OK. */
 static inline int
 add_counter_to_entry(struct ipt_entry *e,
-		     const struct ipt_counters addme[],
+		     const struct xt_counters addme[],
 		     unsigned int *i)
 {
 #if 0
@@ -1295,15 +1027,16 @@
 do_add_counters(void __user *user, unsigned int len)
 {
 	unsigned int i;
-	struct ipt_counters_info tmp, *paddc;
+	struct xt_counters_info tmp, *paddc;
 	struct ipt_table *t;
+	struct xt_table_info *private;
 	int ret = 0;
 	void *loc_cpu_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 		return -EFAULT;
 
-	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ipt_counters))
+	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
 		return -EINVAL;
 
 	paddc = vmalloc_node(len, numa_node_id());
@@ -1315,29 +1048,30 @@
 		goto free;
 	}
 
-	t = find_table_lock(tmp.name);
+	t = xt_find_table_lock(AF_INET, tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
 		goto free;
 	}
 
 	write_lock_bh(&t->lock);
-	if (t->private->number != paddc->num_counters) {
+	private = t->private;
+	if (private->number != paddc->num_counters) {
 		ret = -EINVAL;
 		goto unlock_up_free;
 	}
 
 	i = 0;
 	/* Choose the copy that is on our node */
-	loc_cpu_entry = t->private->entries[raw_smp_processor_id()];
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
 	IPT_ENTRY_ITERATE(loc_cpu_entry,
-			  t->private->size,
+			  private->size,
 			  add_counter_to_entry,
 			  paddc->counters,
 			  &i);
  unlock_up_free:
 	write_unlock_bh(&t->lock);
-	up(&ipt_mutex);
+	xt_table_unlock(t);
 	module_put(t->me);
  free:
 	vfree(paddc);
@@ -1396,25 +1130,26 @@
 		}
 		name[IPT_TABLE_MAXNAMELEN-1] = '\0';
 
-		t = try_then_request_module(find_table_lock(name),
+		t = try_then_request_module(xt_find_table_lock(AF_INET, name),
 					    "iptable_%s", name);
 		if (t && !IS_ERR(t)) {
 			struct ipt_getinfo info;
+			struct xt_table_info *private = t->private;
 
 			info.valid_hooks = t->valid_hooks;
-			memcpy(info.hook_entry, t->private->hook_entry,
+			memcpy(info.hook_entry, private->hook_entry,
 			       sizeof(info.hook_entry));
-			memcpy(info.underflow, t->private->underflow,
+			memcpy(info.underflow, private->underflow,
 			       sizeof(info.underflow));
-			info.num_entries = t->private->number;
-			info.size = t->private->size;
+			info.num_entries = private->number;
+			info.size = private->size;
 			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
 			else
 				ret = 0;
-			up(&ipt_mutex);
+			xt_table_unlock(t);
 			module_put(t->me);
 		} else
 			ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1441,7 +1176,7 @@
 	case IPT_SO_GET_REVISION_MATCH:
 	case IPT_SO_GET_REVISION_TARGET: {
 		struct ipt_get_revision rev;
-		int (*revfn)(const char *, u8, int *);
+		int target;
 
 		if (*len != sizeof(rev)) {
 			ret = -EINVAL;
@@ -1453,12 +1188,13 @@
 		}
 
 		if (cmd == IPT_SO_GET_REVISION_TARGET)
-			revfn = target_revfn;
+			target = 1;
 		else
-			revfn = match_revfn;
+			target = 0;
 
-		try_then_request_module(find_revision(rev.name, rev.revision,
-						      revfn, &ret),
+		try_then_request_module(xt_find_revision(AF_INET, rev.name,
+							 rev.revision,
+							 target, &ret),
 					"ipt_%s", rev.name);
 		break;
 	}
@@ -1471,60 +1207,15 @@
 	return ret;
 }
 
-/* Registration hooks for targets. */
-int
-ipt_register_target(struct ipt_target *target)
+int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
 {
 	int ret;
-
-	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0)
-		return ret;
-	list_add(&target->list, &ipt_target);
-	up(&ipt_mutex);
-	return ret;
-}
-
-void
-ipt_unregister_target(struct ipt_target *target)
-{
-	down(&ipt_mutex);
-	LIST_DELETE(&ipt_target, target);
-	up(&ipt_mutex);
-}
-
-int
-ipt_register_match(struct ipt_match *match)
-{
-	int ret;
-
-	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0)
-		return ret;
-
-	list_add(&match->list, &ipt_match);
-	up(&ipt_mutex);
-
-	return ret;
-}
-
-void
-ipt_unregister_match(struct ipt_match *match)
-{
-	down(&ipt_mutex);
-	LIST_DELETE(&ipt_match, match);
-	up(&ipt_mutex);
-}
-
-int ipt_register_table(struct ipt_table *table, const struct ipt_replace *repl)
-{
-	int ret;
-	struct ipt_table_info *newinfo;
-	static struct ipt_table_info bootstrap
+	struct xt_table_info *newinfo;
+	static struct xt_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 	void *loc_cpu_entry;
 
-	newinfo = alloc_table_info(repl->size);
+	newinfo = xt_alloc_table_info(repl->size);
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1540,246 +1231,29 @@
 			      repl->hook_entry,
 			      repl->underflow);
 	if (ret != 0) {
-		free_table_info(newinfo);
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0) {
-		free_table_info(newinfo);
+	if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	/* Don't autoload: we'd eat our tail... */
-	if (list_named_find(&ipt_tables, table->name)) {
-		ret = -EEXIST;
-		goto free_unlock;
-	}
-
-	/* Simplifies replace_table code. */
-	table->private = &bootstrap;
-	if (!replace_table(table, 0, newinfo, &ret))
-		goto free_unlock;
-
-	duprintf("table->private->number = %u\n",
-		 table->private->number);
-	
-	/* save number of initial entries */
-	table->private->initial_entries = table->private->number;
-
-	rwlock_init(&table->lock);
-	list_prepend(&ipt_tables, table);
-
- unlock:
-	up(&ipt_mutex);
-	return ret;
-
- free_unlock:
-	free_table_info(newinfo);
-	goto unlock;
+	return 0;
 }
 
 void ipt_unregister_table(struct ipt_table *table)
 {
+	struct xt_table_info *private;
 	void *loc_cpu_entry;
 
-	down(&ipt_mutex);
-	LIST_DELETE(&ipt_tables, table);
-	up(&ipt_mutex);
+ 	private = xt_unregister_table(table);
 
 	/* Decrease module usage counts and free resources */
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-	IPT_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
-			  cleanup_entry, NULL);
-	free_table_info(table->private);
-}
-
-/* Returns 1 if the port is matched by the range, 0 otherwise */
-static inline int
-port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
-{
-	int ret;
-
-	ret = (port >= min && port <= max) ^ invert;
-	return ret;
-}
-
-static int
-tcp_find_option(u_int8_t option,
-		const struct sk_buff *skb,
-		unsigned int optlen,
-		int invert,
-		int *hotdrop)
-{
-	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-	u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
-	unsigned int i;
-
-	duprintf("tcp_match: finding option\n");
-
-	if (!optlen)
-		return invert;
-
-	/* If we don't have the whole header, drop packet. */
-	op = skb_header_pointer(skb,
-				skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
-				optlen, _opt);
-	if (op == NULL) {
-		*hotdrop = 1;
-		return 0;
-	}
-
-	for (i = 0; i < optlen; ) {
-		if (op[i] == option) return !invert;
-		if (op[i] < 2) i++;
-		else i += op[i+1]?:1;
-	}
-
-	return invert;
-}
-
-static int
-tcp_match(const struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  const void *matchinfo,
-	  int offset,
-	  int *hotdrop)
-{
-	struct tcphdr _tcph, *th;
-	const struct ipt_tcp *tcpinfo = matchinfo;
-
-	if (offset) {
-		/* To quote Alan:
-
-		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
-		   causes this. Its a cracker trying to break in by doing a
-		   flag overwrite to pass the direction checks.
-		*/
-		if (offset == 1) {
-			duprintf("Dropping evil TCP offset=1 frag.\n");
-			*hotdrop = 1;
-		}
-		/* Must not be a fragment. */
-		return 0;
-	}
-
-#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
-
-	th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL) {
-		/* We've been asked to examine this packet, and we
-		   can't.  Hence, no choice but to drop. */
-		duprintf("Dropping evil TCP offset=0 tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
-			ntohs(th->source),
-			!!(tcpinfo->invflags & IPT_TCP_INV_SRCPT)))
-		return 0;
-	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
-			ntohs(th->dest),
-			!!(tcpinfo->invflags & IPT_TCP_INV_DSTPT)))
-		return 0;
-	if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
-		      == tcpinfo->flg_cmp,
-		      IPT_TCP_INV_FLAGS))
-		return 0;
-	if (tcpinfo->option) {
-		if (th->doff * 4 < sizeof(_tcph)) {
-			*hotdrop = 1;
-			return 0;
-		}
-		if (!tcp_find_option(tcpinfo->option, skb,
-				     th->doff*4 - sizeof(_tcph),
-				     tcpinfo->invflags & IPT_TCP_INV_OPTION,
-				     hotdrop))
-			return 0;
-	}
-	return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp_checkentry(const char *tablename,
-	       const struct ipt_ip *ip,
-	       void *matchinfo,
-	       unsigned int matchsize,
-	       unsigned int hook_mask)
-{
-	const struct ipt_tcp *tcpinfo = matchinfo;
-
-	/* Must specify proto == TCP, and no unknown invflags */
-	return ip->proto == IPPROTO_TCP
-		&& !(ip->invflags & IPT_INV_PROTO)
-		&& matchsize == IPT_ALIGN(sizeof(struct ipt_tcp))
-		&& !(tcpinfo->invflags & ~IPT_TCP_INV_MASK);
-}
-
-static int
-udp_match(const struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  const void *matchinfo,
-	  int offset,
-	  int *hotdrop)
-{
-	struct udphdr _udph, *uh;
-	const struct ipt_udp *udpinfo = matchinfo;
-
-	/* Must not be a fragment. */
-	if (offset)
-		return 0;
-
-	uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-				sizeof(_udph), &_udph);
-	if (uh == NULL) {
-		/* We've been asked to examine this packet, and we
-		   can't.  Hence, no choice but to drop. */
-		duprintf("Dropping evil UDP tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return port_match(udpinfo->spts[0], udpinfo->spts[1],
-			  ntohs(uh->source),
-			  !!(udpinfo->invflags & IPT_UDP_INV_SRCPT))
-		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
-			      ntohs(uh->dest),
-			      !!(udpinfo->invflags & IPT_UDP_INV_DSTPT));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp_checkentry(const char *tablename,
-	       const struct ipt_ip *ip,
-	       void *matchinfo,
-	       unsigned int matchinfosize,
-	       unsigned int hook_mask)
-{
-	const struct ipt_udp *udpinfo = matchinfo;
-
-	/* Must specify proto == UDP, and no unknown invflags */
-	if (ip->proto != IPPROTO_UDP || (ip->invflags & IPT_INV_PROTO)) {
-		duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
-			 IPPROTO_UDP);
-		return 0;
-	}
-	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_udp))) {
-		duprintf("ipt_udp: matchsize %u != %u\n",
-			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_udp)));
-		return 0;
-	}
-	if (udpinfo->invflags & ~IPT_UDP_INV_MASK) {
-		duprintf("ipt_udp: unknown flags %X\n",
-			 udpinfo->invflags);
-		return 0;
-	}
-
-	return 1;
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+	IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+	xt_free_table_info(private);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1798,6 +1272,7 @@
 	   const struct net_device *out,
 	   const void *matchinfo,
 	   int offset,
+	   unsigned int protoff,
 	   int *hotdrop)
 {
 	struct icmphdr _icmph, *ic;
@@ -1807,8 +1282,7 @@
 	if (offset)
 		return 0;
 
-	ic = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-				sizeof(_icmph), &_icmph);
+	ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
 	if (ic == NULL) {
 		/* We've been asked to examine this packet, and we
 		 * can't.  Hence, no choice but to drop.
@@ -1828,11 +1302,12 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 icmp_checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *info,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
+	const struct ipt_ip *ip = info;
 	const struct ipt_icmp *icmpinfo = matchinfo;
 
 	/* Must specify proto == ICMP, and no unknown invflags */
@@ -1862,123 +1337,22 @@
 	.get		= do_ipt_get_ctl,
 };
 
-static struct ipt_match tcp_matchstruct = {
-	.name		= "tcp",
-	.match		= &tcp_match,
-	.checkentry	= &tcp_checkentry,
-};
-
-static struct ipt_match udp_matchstruct = {
-	.name		= "udp",
-	.match		= &udp_match,
-	.checkentry	= &udp_checkentry,
-};
-
 static struct ipt_match icmp_matchstruct = {
 	.name		= "icmp",
 	.match		= &icmp_match,
 	.checkentry	= &icmp_checkentry,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const char *i,
-			     off_t start_offset, char *buffer, int length,
-			     off_t *pos, unsigned int *count)
-{
-	if ((*count)++ >= start_offset) {
-		unsigned int namelen;
-
-		namelen = sprintf(buffer + *pos, "%s\n",
-				  i + sizeof(struct list_head));
-		if (*pos + namelen > length) {
-			/* Stop iterating */
-			return 1;
-		}
-		*pos += namelen;
-	}
-	return 0;
-}
-
-static inline int print_target(const struct ipt_target *t,
-                               off_t start_offset, char *buffer, int length,
-                               off_t *pos, unsigned int *count)
-{
-	if (t == &ipt_standard_target || t == &ipt_error_target)
-		return 0;
-	return print_name((char *)t, start_offset, buffer, length, pos, count);
-}
-
-static int ipt_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&ipt_tables, print_name, void *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&ipt_mutex);
-
-	/* `start' hack - see fs/proc/generic.c line ~105 */
-	*start=(char *)((unsigned long)count-offset);
-	return pos;
-}
-
-static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&ipt_target, print_target, struct ipt_target *,
-		  offset, buffer, length, &pos, &count);
-	
-	up(&ipt_mutex);
-
-	*start = (char *)((unsigned long)count - offset);
-	return pos;
-}
-
-static int ipt_get_matches(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ipt_mutex) != 0)
-		return 0;
-	
-	LIST_FIND(&ipt_match, print_name, void *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&ipt_mutex);
-
-	*start = (char *)((unsigned long)count - offset);
-	return pos;
-}
-
-static const struct { char *name; get_info_t *get_info; } ipt_proc_entry[] =
-{ { "ip_tables_names", ipt_get_tables },
-  { "ip_tables_targets", ipt_get_targets },
-  { "ip_tables_matches", ipt_get_matches },
-  { NULL, NULL} };
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
 	int ret;
 
+	xt_proto_init(AF_INET);
+
 	/* Noone else will be downing sem now, so we won't sleep */
-	down(&ipt_mutex);
-	list_append(&ipt_target, &ipt_standard_target);
-	list_append(&ipt_target, &ipt_error_target);
-	list_append(&ipt_match, &tcp_matchstruct);
-	list_append(&ipt_match, &udp_matchstruct);
-	list_append(&ipt_match, &icmp_matchstruct);
-	up(&ipt_mutex);
+	xt_register_target(AF_INET, &ipt_standard_target);
+	xt_register_target(AF_INET, &ipt_error_target);
+	xt_register_match(AF_INET, &icmp_matchstruct);
 
 	/* Register setsockopt */
 	ret = nf_register_sockopt(&ipt_sockopts);
@@ -1987,49 +1361,23 @@
 		return ret;
 	}
 
-#ifdef CONFIG_PROC_FS
-	{
-	struct proc_dir_entry *proc;
-	int i;
-
-	for (i = 0; ipt_proc_entry[i].name; i++) {
-		proc = proc_net_create(ipt_proc_entry[i].name, 0,
-				       ipt_proc_entry[i].get_info);
-		if (!proc) {
-			while (--i >= 0)
-				proc_net_remove(ipt_proc_entry[i].name);
-			nf_unregister_sockopt(&ipt_sockopts);
-			return -ENOMEM;
-		}
-		proc->owner = THIS_MODULE;
-	}
-	}
-#endif
-
-	printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
+	printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
 	return 0;
 }
 
 static void __exit fini(void)
 {
 	nf_unregister_sockopt(&ipt_sockopts);
-#ifdef CONFIG_PROC_FS
-	{
-	int i;
-	for (i = 0; ipt_proc_entry[i].name; i++)
-		proc_net_remove(ipt_proc_entry[i].name);
-	}
-#endif
+
+	xt_unregister_match(AF_INET, &icmp_matchstruct);
+	xt_unregister_target(AF_INET, &ipt_error_target);
+	xt_unregister_target(AF_INET, &ipt_standard_target);
+
+	xt_proto_fini(AF_INET);
 }
 
 EXPORT_SYMBOL(ipt_register_table);
 EXPORT_SYMBOL(ipt_unregister_table);
-EXPORT_SYMBOL(ipt_register_match);
-EXPORT_SYMBOL(ipt_unregister_match);
 EXPORT_SYMBOL(ipt_do_table);
-EXPORT_SYMBOL(ipt_register_target);
-EXPORT_SYMBOL(ipt_unregister_target);
-EXPORT_SYMBOL(ipt_find_target);
-
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 45c52d8..d9bc971 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -379,12 +379,13 @@
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
 	struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+	const struct ipt_entry *e = e_void;
 
 	struct clusterip_config *config;
 
diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c
index 6e31957..898cdf7 100644
--- a/net/ipv4/netfilter/ipt_DSCP.c
+++ b/net/ipv4/netfilter/ipt_DSCP.c
@@ -57,7 +57,7 @@
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index a131969..7064454 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -113,12 +113,13 @@
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
 	const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+	const struct ipt_entry *e = e_void;
 
 	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
 		printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 30be0f1..6606ddb 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -431,7 +431,7 @@
 }
 
 static int ipt_log_checkentry(const char *tablename,
-			      const struct ipt_entry *e,
+			      const void *e,
 			      void *targinfo,
 			      unsigned int targinfosize,
 			      unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 2786051..12c56d3 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -40,7 +40,7 @@
 /* FIXME: Multiple targets. --RR */
 static int
 masquerade_check(const char *tablename,
-		 const struct ipt_entry *e,
+		 const void *e,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index e6e7b60..b074467 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -31,7 +31,7 @@
 
 static int
 check(const char *tablename,
-      const struct ipt_entry *e,
+      const void *e,
       void *targinfo,
       unsigned int targinfosize,
       unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_NFQUEUE.c b/net/ipv4/netfilter/ipt_NFQUEUE.c
deleted file mode 100644
index 3cedc9b..0000000
--- a/net/ipv4/netfilter/ipt_NFQUEUE.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* iptables module for using new netfilter netlink queue
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as 
- * published by the Free Software Foundation.
- * 
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
-
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("iptables NFQUEUE target");
-MODULE_LICENSE("GPL");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-	const struct ipt_NFQ_info *tinfo = targinfo;
-
-	return NF_QUEUE_NR(tinfo->queuenum);
-}
-
-static int
-checkentry(const char *tablename,
-	   const struct ipt_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_NFQ_info))) {
-		printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_NFQ_info)));
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ipt_target ipt_NFQ_reg = {
-	.name		= "NFQUEUE",
-	.target		= target,
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_target(&ipt_NFQ_reg);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_target(&ipt_NFQ_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 5245bfd..140be51 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -33,7 +33,7 @@
 /* FIXME: Take multiple ranges --RR */
 static int
 redirect_check(const char *tablename,
-	       const struct ipt_entry *e,
+	       const void *e,
 	       void *targinfo,
 	       unsigned int targinfosize,
 	       unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 6693526..3eb47aa 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -282,12 +282,13 @@
 }
 
 static int check(const char *tablename,
-		 const struct ipt_entry *e,
+		 const void *e_void,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
 {
  	const struct ipt_reject_info *rejinfo = targinfo;
+	const struct ipt_entry *e = e_void;
 
  	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
   		DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 7a0536d..a22de59 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -49,7 +49,7 @@
 
 static int
 same_check(const char *tablename,
-	      const struct ipt_entry *e,
+	      const void *e,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
index 8db70d6..c122841 100644
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c
@@ -210,12 +210,13 @@
 /* Must specify -p tcp --syn/--tcp-flags SYN */
 static int
 ipt_tcpmss_checkentry(const char *tablename,
-		      const struct ipt_entry *e,
+		      const void *e_void,
 		      void *targinfo,
 		      unsigned int targinfosize,
 		      unsigned int hook_mask)
 {
 	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+	const struct ipt_entry *e = e_void;
 
 	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
 		DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index deadb36..3a44a56 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -52,7 +52,7 @@
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index b9ae6a9..b769eb2 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -66,7 +66,7 @@
 }
 
 static int ipt_ttl_checkentry(const char *tablename,
-		const struct ipt_entry *e,
+		const void *e,
 		void *targinfo,
 		unsigned int targinfosize,
 		unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 38641cd..641dbc4 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -330,7 +330,7 @@
 }
 
 static int ipt_ulog_checkentry(const char *tablename,
-			       const struct ipt_entry *e,
+			       const void *e,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hookmask)
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index e19c2a5..d6b83a9 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -29,7 +29,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_addrtype_info *info = matchinfo;
 	const struct iphdr *iph = skb->nh.iph;
@@ -43,7 +43,7 @@
 	return ret;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index a0fea84..144adfe 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -41,6 +41,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	struct ip_auth_hdr _ahdr, *ah;
@@ -50,7 +51,7 @@
 	if (offset)
 		return 0;
 
-	ah = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+	ah = skb_header_pointer(skb, protoff,
 				sizeof(_ahdr), &_ahdr);
 	if (ah == NULL) {
 		/* We've been asked to examine this packet, and we
@@ -69,12 +70,13 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *ip_void,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ipt_ah *ahinfo = matchinfo;
+	const struct ipt_ip *ip = ip_void;
 
 	/* Must specify proto == AH, and no unknown invflags */
 	if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
diff --git a/net/ipv4/netfilter/ipt_comment.c b/net/ipv4/netfilter/ipt_comment.c
deleted file mode 100644
index 6b76a1e..0000000
--- a/net/ipv4/netfilter/ipt_comment.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Implements a dummy match to allow attaching comments to rules
- *
- * 2003-05-13 Brad Fisher (brad@info-link.net)
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_comment.h>
-
-MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
-MODULE_DESCRIPTION("iptables comment match module");
-MODULE_LICENSE("GPL");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	/* We always match */
-	return 1;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	/* Check the size */
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_comment_info)))
-		return 0;
-	return 1;
-}
-
-static struct ipt_match comment_match = {
-	.name		= "comment",
-	.match		= match,
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&comment_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&comment_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_dccp.c b/net/ipv4/netfilter/ipt_dccp.c
deleted file mode 100644
index ad3278b..0000000
--- a/net/ipv4/netfilter/ipt_dccp.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * iptables module for DCCP protocol header matching
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <net/ip.h>
-#include <linux/dccp.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_dccp.h>
-
-#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
-		                  || (!!((invflag) & (option)) ^ (cond)))
-
-static unsigned char *dccp_optbuf;
-static DEFINE_SPINLOCK(dccp_buflock);
-
-static inline int
-dccp_find_option(u_int8_t option,
-		 const struct sk_buff *skb,
-		 const struct dccp_hdr *dh,
-		 int *hotdrop)
-{
-	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-	unsigned char *op;
-	unsigned int optoff = __dccp_hdr_len(dh);
-	unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
-	unsigned int i;
-
-	if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
-		*hotdrop = 1;
-		return 0;
-	}
-
-	if (!optlen)
-		return 0;
-
-	spin_lock_bh(&dccp_buflock);
-	op = skb_header_pointer(skb,
-				skb->nh.iph->ihl*4 + optoff,
-				optlen, dccp_optbuf);
-	if (op == NULL) {
-		/* If we don't have the whole header, drop packet. */
-		spin_unlock_bh(&dccp_buflock);
-		*hotdrop = 1;
-		return 0;
-	}
-
-	for (i = 0; i < optlen; ) {
-		if (op[i] == option) {
-			spin_unlock_bh(&dccp_buflock);
-			return 1;
-		}
-
-		if (op[i] < 2) 
-			i++;
-		else 
-			i += op[i+1]?:1;
-	}
-
-	spin_unlock_bh(&dccp_buflock);
-	return 0;
-}
-
-
-static inline int
-match_types(const struct dccp_hdr *dh, u_int16_t typemask)
-{
-	return (typemask & (1 << dh->dccph_type));
-}
-
-static inline int
-match_option(u_int8_t option, const struct sk_buff *skb,
-	     const struct dccp_hdr *dh, int *hotdrop)
-{
-	return dccp_find_option(option, skb, dh, hotdrop);
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	const struct ipt_dccp_info *info = 
-				(const struct ipt_dccp_info *)matchinfo;
-	struct dccp_hdr _dh, *dh;
-
-	if (offset)
-		return 0;
-	
-	dh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_dh), &_dh);
-	if (dh == NULL) {
-		*hotdrop = 1;
-		return 0;
-       	}
-
-	return  DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) 
-			&& (ntohs(dh->dccph_sport) <= info->spts[1])), 
-		   	IPT_DCCP_SRC_PORTS, info->flags, info->invflags)
-		&& DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) 
-			&& (ntohs(dh->dccph_dport) <= info->dpts[1])), 
-			IPT_DCCP_DEST_PORTS, info->flags, info->invflags)
-		&& DCCHECK(match_types(dh, info->typemask),
-			   IPT_DCCP_TYPE, info->flags, info->invflags)
-		&& DCCHECK(match_option(info->option, skb, dh, hotdrop),
-			   IPT_DCCP_OPTION, info->flags, info->invflags);
-}
-
-static int
-checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
-	   void *matchinfo,
-	   unsigned int matchsize,
-	   unsigned int hook_mask)
-{
-	const struct ipt_dccp_info *info;
-
-	info = (const struct ipt_dccp_info *)matchinfo;
-
-	return ip->proto == IPPROTO_DCCP
-		&& !(ip->invflags & IPT_INV_PROTO)
-		&& matchsize == IPT_ALIGN(sizeof(struct ipt_dccp_info))
-		&& !(info->flags & ~IPT_DCCP_VALID_FLAGS)
-		&& !(info->invflags & ~IPT_DCCP_VALID_FLAGS)
-		&& !(info->invflags & ~info->flags);
-}
-
-static struct ipt_match dccp_match = 
-{ 
-	.name 		= "dccp",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me 		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	int ret;
-
-	/* doff is 8 bits, so the maximum option size is (4*256).  Don't put
-	 * this in BSS since DaveM is worried about locked TLB's for kernel
-	 * BSS. */
-	dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
-	if (!dccp_optbuf)
-		return -ENOMEM;
-	ret = ipt_register_match(&dccp_match);
-	if (ret)
-		kfree(dccp_optbuf);
-
-	return ret;
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&dccp_match);
-	kfree(dccp_optbuf);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("Match for DCCP protocol packets");
-
diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c
index 5df52a6..92063b4 100644
--- a/net/ipv4/netfilter/ipt_dscp.c
+++ b/net/ipv4/netfilter/ipt_dscp.c
@@ -21,7 +21,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_dscp_info *info = matchinfo;
 	const struct iphdr *iph = skb->nh.iph;
@@ -31,7 +31,7 @@
 	return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index b6f7181..e68b0c7 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -67,7 +67,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_ecn_info *info = matchinfo;
 
@@ -85,11 +85,12 @@
 	return 1;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip_void,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
 	const struct ipt_ecn_info *info = matchinfo;
+	const struct ipt_ip *ip = ip_void;
 
 	if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
 		return 0;
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
index e1d0dd3..9de191a 100644
--- a/net/ipv4/netfilter/ipt_esp.c
+++ b/net/ipv4/netfilter/ipt_esp.c
@@ -42,6 +42,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	struct ip_esp_hdr _esp, *eh;
@@ -51,7 +52,7 @@
 	if (offset)
 		return 0;
 
-	eh = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+	eh = skb_header_pointer(skb, protoff,
 				sizeof(_esp), &_esp);
 	if (eh == NULL) {
 		/* We've been asked to examine this packet, and we
@@ -70,12 +71,13 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *ip_void,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
 {
 	const struct ipt_esp *espinfo = matchinfo;
+	const struct ipt_ip *ip = ip_void;
 
 	/* Must specify proto == ESP, and no unknown invflags */
 	if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index 2dd1ccc..4fe48c1 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -429,6 +429,7 @@
 		const struct net_device *out,
 		const void *matchinfo,
 		int offset,
+		unsigned int protoff,
 		int *hotdrop)
 {
 	struct ipt_hashlimit_info *r = 
@@ -504,7 +505,7 @@
 
 static int
 hashlimit_checkentry(const char *tablename,
-		     const struct ipt_ip *ip,
+		     const void *inf,
 		     void *matchinfo,
 		     unsigned int matchsize,
 		     unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index b835b7b..13fb16f 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -28,7 +28,7 @@
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
-      int offset, int *hotdrop)
+      int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_iprange_info *info = matchinfo;
 	const struct iphdr *iph = skb->nh.iph;
@@ -63,7 +63,7 @@
 }
 
 static int check(const char *tablename,
-		 const struct ipt_ip *ip,
+		 const void *inf,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_length.c b/net/ipv4/netfilter/ipt_length.c
deleted file mode 100644
index 4eabcfb..0000000
--- a/net/ipv4/netfilter/ipt_length.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Kernel module to match packet length. */
-/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter_ipv4/ipt_length.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
-MODULE_DESCRIPTION("IP tables packet length matching module");
-MODULE_LICENSE("GPL");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	const struct ipt_length_info *info = matchinfo;
-	u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
-	
-	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_length_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ipt_match length_match = {
-	.name		= "length",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&length_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&length_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
index 99e8188..2d52326 100644
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ b/net/ipv4/netfilter/ipt_multiport.c
@@ -97,6 +97,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	u16 _ports[2], *pptr;
@@ -105,7 +106,7 @@
 	if (offset)
 		return 0;
 
-	pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+	pptr = skb_header_pointer(skb, protoff,
 				  sizeof(_ports), _ports);
 	if (pptr == NULL) {
 		/* We've been asked to examine this packet, and we
@@ -128,6 +129,7 @@
 	 const struct net_device *out,
 	 const void *matchinfo,
 	 int offset,
+	 unsigned int protoff,
 	 int *hotdrop)
 {
 	u16 _ports[2], *pptr;
@@ -136,7 +138,7 @@
 	if (offset)
 		return 0;
 
-	pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+	pptr = skb_header_pointer(skb, protoff,
 				  sizeof(_ports), _ports);
 	if (pptr == NULL) {
 		/* We've been asked to examine this packet, and we
@@ -154,7 +156,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *ip,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
@@ -164,7 +166,7 @@
 
 static int
 checkentry_v1(const char *tablename,
-	      const struct ipt_ip *ip,
+	      const void *ip,
 	      void *matchinfo,
 	      unsigned int matchsize,
 	      unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 0cee286..4843d0c 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -27,6 +27,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	const struct ipt_owner_info *info = matchinfo;
@@ -51,7 +52,7 @@
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_physdev.c b/net/ipv4/netfilter/ipt_physdev.c
deleted file mode 100644
index 03f5548..0000000
--- a/net/ipv4/netfilter/ipt_physdev.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Kernel module to match the bridge port in and
- * out device for IP packets coming into contact with a bridge. */
-
-/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ipt_physdev.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_bridge.h>
-#define MATCH   1
-#define NOMATCH 0
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-MODULE_DESCRIPTION("iptables bridge physical device match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	int i;
-	static const char nulldevname[IFNAMSIZ];
-	const struct ipt_physdev_info *info = matchinfo;
-	unsigned int ret;
-	const char *indev, *outdev;
-	struct nf_bridge_info *nf_bridge;
-
-	/* Not a bridged IP packet or no info available yet:
-	 * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
-	 * the destination device will be a bridge. */
-	if (!(nf_bridge = skb->nf_bridge)) {
-		/* Return MATCH if the invert flags of the used options are on */
-		if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
-		    !(info->invert & IPT_PHYSDEV_OP_BRIDGED))
-			return NOMATCH;
-		if ((info->bitmask & IPT_PHYSDEV_OP_ISIN) &&
-		    !(info->invert & IPT_PHYSDEV_OP_ISIN))
-			return NOMATCH;
-		if ((info->bitmask & IPT_PHYSDEV_OP_ISOUT) &&
-		    !(info->invert & IPT_PHYSDEV_OP_ISOUT))
-			return NOMATCH;
-		if ((info->bitmask & IPT_PHYSDEV_OP_IN) &&
-		    !(info->invert & IPT_PHYSDEV_OP_IN))
-			return NOMATCH;
-		if ((info->bitmask & IPT_PHYSDEV_OP_OUT) &&
-		    !(info->invert & IPT_PHYSDEV_OP_OUT))
-			return NOMATCH;
-		return MATCH;
-	}
-
-	/* This only makes sense in the FORWARD and POSTROUTING chains */
-	if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
-	    (!!(nf_bridge->mask & BRNF_BRIDGED) ^
-	    !(info->invert & IPT_PHYSDEV_OP_BRIDGED)))
-		return NOMATCH;
-
-	if ((info->bitmask & IPT_PHYSDEV_OP_ISIN &&
-	    (!nf_bridge->physindev ^ !!(info->invert & IPT_PHYSDEV_OP_ISIN))) ||
-	    (info->bitmask & IPT_PHYSDEV_OP_ISOUT &&
-	    (!nf_bridge->physoutdev ^ !!(info->invert & IPT_PHYSDEV_OP_ISOUT))))
-		return NOMATCH;
-
-	if (!(info->bitmask & IPT_PHYSDEV_OP_IN))
-		goto match_outdev;
-	indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
-	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-		ret |= (((const unsigned int *)indev)[i]
-			^ ((const unsigned int *)info->physindev)[i])
-			& ((const unsigned int *)info->in_mask)[i];
-	}
-
-	if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_IN))
-		return NOMATCH;
-
-match_outdev:
-	if (!(info->bitmask & IPT_PHYSDEV_OP_OUT))
-		return MATCH;
-	outdev = nf_bridge->physoutdev ?
-		 nf_bridge->physoutdev->name : nulldevname;
-	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-		ret |= (((const unsigned int *)outdev)[i]
-			^ ((const unsigned int *)info->physoutdev)[i])
-			& ((const unsigned int *)info->out_mask)[i];
-	}
-
-	return (ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_OUT);
-}
-
-static int
-checkentry(const char *tablename,
-		       const struct ipt_ip *ip,
-		       void *matchinfo,
-		       unsigned int matchsize,
-		       unsigned int hook_mask)
-{
-	const struct ipt_physdev_info *info = matchinfo;
-
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_physdev_info)))
-		return 0;
-	if (!(info->bitmask & IPT_PHYSDEV_OP_MASK) ||
-	    info->bitmask & ~IPT_PHYSDEV_OP_MASK)
-		return 0;
-	return 1;
-}
-
-static struct ipt_match physdev_match = {
-	.name		= "physdev",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&physdev_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&physdev_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_pkttype.c b/net/ipv4/netfilter/ipt_pkttype.c
deleted file mode 100644
index 8ddb1dc..0000000
--- a/net/ipv4/netfilter/ipt_pkttype.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* (C) 1999-2001 Michal Ludvig <michal@logix.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-
-#include <linux/netfilter_ipv4/ipt_pkttype.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>");
-MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
-
-static int match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-    const struct ipt_pkttype_info *info = matchinfo;
-
-    return (skb->pkt_type == info->pkttype) ^ info->invert;
-}
-
-static int checkentry(const char *tablename,
-		   const struct ipt_ip *ip,
-		   void *matchinfo,
-		   unsigned int matchsize,
-		   unsigned int hook_mask)
-{
-/*
-	if (hook_mask
-	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
-		| (1 << NF_IP_FORWARD))) {
-		printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-		return 0;
-	}
-*/
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ipt_match pkttype_match = {
-	.name		= "pkttype",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&pkttype_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&pkttype_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 5ddccb1..44611d6 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -104,6 +104,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop);
 
 /* Function to hash a given address into the hash table of table_size size */
@@ -317,7 +318,7 @@
 	skb->nh.iph->daddr = 0;
 	/* Clear ttl since we have no way of knowing it */
 	skb->nh.iph->ttl = 0;
-	match(skb,NULL,NULL,info,0,NULL);
+	match(skb,NULL,NULL,info,0,0,NULL);
 
 	kfree(skb->nh.iph);
 out_free_skb:
@@ -357,6 +358,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	int pkt_count, hits_found, ans;
@@ -654,7 +656,7 @@
  */
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c
deleted file mode 100644
index 4d7f16b..0000000
--- a/net/ipv4/netfilter/ipt_state.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Kernel module to match connection tracking information. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_state.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
-MODULE_DESCRIPTION("iptables connection tracking state match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	const struct ipt_state_info *sinfo = matchinfo;
-	enum ip_conntrack_info ctinfo;
-	unsigned int statebit;
-
-	if (nf_ct_is_untracked(skb))
-		statebit = IPT_STATE_UNTRACKED;
-	else if (!nf_ct_get_ctinfo(skb, &ctinfo))
-		statebit = IPT_STATE_INVALID;
-	else
-		statebit = IPT_STATE_BIT(ctinfo);
-
-	return (sinfo->statemask & statebit);
-}
-
-static int check(const char *tablename,
-		 const struct ipt_ip *ip,
-		 void *matchinfo,
-		 unsigned int matchsize,
-		 unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_state_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ipt_match state_match = {
-	.name		= "state",
-	.match		= &match,
-	.checkentry	= &check,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	need_ip_conntrack();
-	return ipt_register_match(&state_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&state_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_tcpmss.c b/net/ipv4/netfilter/ipt_tcpmss.c
deleted file mode 100644
index 4dc9b16..0000000
--- a/net/ipv4/netfilter/ipt_tcpmss.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Kernel module to match TCP MSS values. */
-
-/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ipt_tcpmss.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-#define TH_SYN 0x02
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables TCP MSS match module");
-
-/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
-static inline int
-mssoption_match(u_int16_t min, u_int16_t max,
-		const struct sk_buff *skb,
-		int invert,
-		int *hotdrop)
-{
-	struct tcphdr _tcph, *th;
-	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-	u8 _opt[15 * 4 - sizeof(_tcph)], *op;
-	unsigned int i, optlen;
-
-	/* If we don't have the whole header, drop packet. */
-	th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		goto dropit;
-
-	/* Malformed. */
-	if (th->doff*4 < sizeof(*th))
-		goto dropit;
-
-	optlen = th->doff*4 - sizeof(*th);
-	if (!optlen)
-		goto out;
-
-	/* Truncated options. */
-	op = skb_header_pointer(skb, skb->nh.iph->ihl * 4 + sizeof(*th),
-				optlen, _opt);
-	if (op == NULL)
-		goto dropit;
-
-	for (i = 0; i < optlen; ) {
-		if (op[i] == TCPOPT_MSS
-		    && (optlen - i) >= TCPOLEN_MSS
-		    && op[i+1] == TCPOLEN_MSS) {
-			u_int16_t mssval;
-
-			mssval = (op[i+2] << 8) | op[i+3];
-			
-			return (mssval >= min && mssval <= max) ^ invert;
-		}
-		if (op[i] < 2) i++;
-		else i += op[i+1]?:1;
-	}
-out:
-	return invert;
-
- dropit:
-	*hotdrop = 1;
-	return 0;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-	const struct ipt_tcpmss_match_info *info = matchinfo;
-
-	return mssoption_match(info->mss_min, info->mss_max, skb,
-			       info->invert, hotdrop);
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_tcpmss_match_info)))
-		return 0;
-
-	/* Must specify -p tcp */
-	if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
-		printk("tcpmss: Only works on TCP packets\n");
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ipt_match tcpmss_match = {
-	.name		= "tcpmss",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ipt_register_match(&tcpmss_match);
-}
-
-static void __exit fini(void)
-{
-	ipt_unregister_match(&tcpmss_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 086a1bb..9ab765e 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -23,6 +23,7 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
 	const struct ipt_tos_info *info = matchinfo;
@@ -32,7 +33,7 @@
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index 219aa9d..82da53f 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -21,7 +21,7 @@
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
 		 const struct net_device *out, const void *matchinfo,
-		 int offset, int *hotdrop)
+		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_ttl_info *info = matchinfo;
 
@@ -47,7 +47,7 @@
 	return 0;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void  *ip,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 260a4f0..212a307 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -78,7 +78,8 @@
 	.name		= "filter",
 	.valid_hooks	= FILTER_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
-	.me		= THIS_MODULE
+	.me		= THIS_MODULE,
+	.af		= AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 160eb11..3212a5c 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -109,6 +109,7 @@
 	.valid_hooks	= MANGLE_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
 	.me		= THIS_MODULE,
+	.af		= AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 47449ba..fdb9e9c 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -83,7 +83,8 @@
 	.name = "raw", 
 	.valid_hooks =  RAW_VALID_HOOKS, 
 	.lock = RW_LOCK_UNLOCKED, 
-	.me = THIS_MODULE
+	.me = THIS_MODULE,
+	.af = AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 0c56c52a..167619f 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -575,7 +575,7 @@
 
 static int __init init(void)
 {
-	need_nf_conntrack();
+	need_conntrack();
 	return init_or_cleanup(1);
 }
 
@@ -587,9 +587,4 @@
 module_init(init);
 module_exit(fini);
 
-void need_ip_conntrack(void)
-{
-}
-
-EXPORT_SYMBOL(need_ip_conntrack);
 EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index d23e07f..dbabf81 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -42,6 +42,21 @@
 	x->props.saddr = tmpl->saddr;
 	if (x->props.saddr.a4 == 0)
 		x->props.saddr.a4 = saddr->a4;
+	if (tmpl->mode && x->props.saddr.a4 == 0) {
+		struct rtable *rt;
+	        struct flowi fl_tunnel = {
+        	        .nl_u = {
+        			.ip4_u = {
+					.daddr = x->id.daddr.a4,
+				}
+			}
+		};
+		if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+		                     &fl_tunnel, AF_INET)) {
+			x->props.saddr.a4 = rt->rt_src;
+			dst_release(&rt->u.dst);
+		}
+	}
 	x->props.mode = tmpl->mode;
 	x->props.reqid = tmpl->reqid;
 	x->props.family = AF_INET;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 7129d42..dfb4f14 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2644,7 +2644,7 @@
 {
 	struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
 	seq_printf(seq,
-		   "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n",
+		   NIP6_FMT " %02x %02x %02x %02x %8s\n",
 		   NIP6(ifp->addr),
 		   ifp->idev->dev->ifindex,
 		   ifp->prefix_len,
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 13cc7f8..c7932cb 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -332,8 +332,7 @@
 	if (!x)
 		return;
 
-	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/"
-		 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+	NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/" NIP6_FMT "\n",
 		 ntohl(ah->spi), NIP6(iph->daddr));
 
 	xfrm_state_put(x);
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 65e73ac..72bd08af 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -532,9 +532,7 @@
 	struct ac6_iter_state *state = ac6_seq_private(seq);
 
 	seq_printf(seq,
-		   "%-4d %-15s "
-		   "%04x%04x%04x%04x%04x%04x%04x%04x "
-		   "%5d\n",
+		   "%-4d %-15s " NIP6_FMT " %5d\n",
 		   state->dev->ifindex, state->dev->name,
 		   NIP6(im->aca_addr),
 		   im->aca_users);
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 6de8ee1..7b5b94f 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -266,8 +266,7 @@
 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6);
 	if (!x)
 		return;
-	printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/"
-			"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 
+	printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/" NIP6_FMT "\n", 
 			ntohl(esph->spi), NIP6(iph->daddr));
 	xfrm_state_put(x);
 }
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 53c81fc..fcf8831 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -607,7 +607,7 @@
 		skb->csum = ~csum_ipv6_magic(saddr, daddr, skb->len,
 					     IPPROTO_ICMPV6, 0);
 		if (__skb_checksum_complete(skb)) {
-			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+			LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [" NIP6_FMT " > " NIP6_FMT "]\n",
 				       NIP6(*saddr), NIP6(*daddr));
 			goto discard_it;
 		}
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 964ad9d..4183c8d 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -629,9 +629,7 @@
 {
 	while(fl) {
 		seq_printf(seq,
-			   "%05X %-1d %-6d %-6d %-6ld %-8ld "
-			   "%02x%02x%02x%02x%02x%02x%02x%02x "
-			   "%-4d\n",
+			   "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_FMT " %-4d\n",
 			   (unsigned)ntohl(fl->label),
 			   fl->share,
 			   (unsigned)fl->owner,
@@ -647,8 +645,8 @@
 static int ip6fl_seq_show(struct seq_file *seq, void *v)
 {
 	if (v == SEQ_START_TOKEN)
-		seq_puts(seq, "Label S Owner  Users  Linger Expires  "
-			      "Dst                              Opt\n");
+		seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-39s %s\n",
+			   "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
 	else
 		ip6fl_fl_seq_show(seq, v);
 	return 0;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 626dd39..d511a884d 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -212,8 +212,7 @@
 	if (!x)
 		return;
 
-	printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/"
-			"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+	printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIP6_FMT "\n",
 			spi, NIP6(iph->daddr));
 	xfrm_state_put(x);
 }
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index cc3e9f5..0e03eab 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2373,7 +2373,7 @@
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
 	seq_printf(seq,
-		   "%-4d %-15s %04x%04x%04x%04x%04x%04x%04x%04x %5d %08X %ld\n", 
+		   "%-4d %-15s " NIP6_FMT " %5d %08X %ld\n", 
 		   state->dev->ifindex, state->dev->name,
 		   NIP6(im->mca_addr),
 		   im->mca_users, im->mca_flags,
@@ -2542,15 +2542,12 @@
 	if (v == SEQ_START_TOKEN) {
 		seq_printf(seq, 
 			   "%3s %6s "
-			   "%32s %32s %6s %6s\n", "Idx",
+			   "%39s %39s %6s %6s\n", "Idx",
 			   "Device", "Multicast Address",
 			   "Source Address", "INC", "EXC");
 	} else {
 		seq_printf(seq,
-			   "%3d %6.6s "
-			   "%04x%04x%04x%04x%04x%04x%04x%04x "
-			   "%04x%04x%04x%04x%04x%04x%04x%04x "
-			   "%6lu %6lu\n",
+			   "%3d %6.6s " NIP6_FMT " " NIP6_FMT " %6lu %6lu\n",
 			   state->dev->ifindex, state->dev->name,
 			   NIP6(state->im->mca_addr),
 			   NIP6(psf->sf_addr),
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 305d9ee..cb8856b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -692,7 +692,7 @@
 		if (!(neigh->nud_state & NUD_VALID)) {
 			ND_PRINTK1(KERN_DEBUG
 				   "%s(): trying to ucast probe in NUD_INVALID: "
-				   "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+				   NIP6_FMT "\n",
 				   __FUNCTION__,
 				   NIP6(*target));
 		}
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 105dd69..2d6f8ec 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -41,6 +41,7 @@
 
 config IP6_NF_IPTABLES
 	tristate "IP6 tables support (required for filtering/masq/NAT)"
+	depends on NETFILTER_XTABLES
 	help
 	  ip6tables is a general, extensible packet identification framework.
 	  Currently only the packet filtering and packet mangling subsystem
@@ -50,25 +51,6 @@
 	  To compile it as a module, choose M here.  If unsure, say N.
 
 # The simple matches.
-config IP6_NF_MATCH_LIMIT
-	tristate "limit match support"
-	depends on IP6_NF_IPTABLES
-	help
-	  limit matching allows you to control the rate at which a rule can be
-	  matched: mainly useful in combination with the LOG target ("LOG
-	  target support", below) and to avoid some Denial of Service attacks.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP6_NF_MATCH_MAC
-	tristate "MAC address match support"
-	depends on IP6_NF_IPTABLES
-	help
-	  mac matching allows you to match packets based on the source
-	  Ethernet address of the packet.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_RT
 	tristate "Routing header match support"
 	depends on IP6_NF_IPTABLES
@@ -124,16 +106,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_MARK
-	tristate "netfilter MARK match support"
-	depends on IP6_NF_IPTABLES
-	help
-	  Netfilter mark matching allows you to match packets based on the
-	  `nfmark' value in the packet.  This can be set by the MARK target
-	  (see below).
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_IPV6HEADER
 	tristate "IPv6 Extension Headers Match"
 	depends on IP6_NF_IPTABLES
@@ -151,15 +123,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_LENGTH
-	tristate "Packet Length match support"
-	depends on IP6_NF_IPTABLES
-	help
-	  This option allows you to match the length of a packet against a
-	  specific value or range of values.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_EUI64
 	tristate "EUI64 address check"
 	depends on IP6_NF_IPTABLES
@@ -170,15 +133,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_PHYSDEV
-	tristate "Physdev match support"
-	depends on IP6_NF_IPTABLES && BRIDGE_NETFILTER
-	help
-	  Physdev packet matching matches against the physical bridge ports
-	  the IP packet arrived on or will leave by.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_POLICY
 	tristate "IPsec policy match support"
 	depends on IP6_NF_IPTABLES && XFRM
@@ -219,17 +173,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_TARGET_NFQUEUE
-	tristate "NFQUEUE Target Support"
-	depends on IP6_NF_IPTABLES
-	help
-	  This Target replaced the old obsolete QUEUE target.
-
-	  As opposed to QUEUE, it supports 65535 different queues,
-	  not just one.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MANGLE
 	tristate "Packet mangling"
 	depends on IP6_NF_IPTABLES
@@ -240,19 +183,6 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_TARGET_MARK
-	tristate "MARK target support"
-	depends on IP6_NF_MANGLE
-	help
-	  This option adds a `MARK' target, which allows you to create rules
-	  in the `mangle' table which alter the netfilter mark (nfmark) field
-	  associated with the packet packet prior to routing. This can change
-	  the routing method (see `Use netfilter MARK value as routing
-	  key') and can also be used by other subsystems to change their
-	  behavior.
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_TARGET_HL
 	tristate  'HL (hoplimit) target support'
 	depends on IP6_NF_MANGLE
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c0c809b..663b474 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -4,10 +4,7 @@
 
 # Link order matters here.
 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
-obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
-obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
-obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
@@ -17,12 +14,9 @@
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
-obj-$(CONFIG_IP6_NF_MATCH_PHYSDEV) += ip6t_physdev.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
-obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
 obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
-obj-$(CONFIG_IP6_NF_TARGET_NFQUEUE) += ip6t_NFQUEUE.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 1390370..847068f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -13,6 +13,9 @@
  * 	  a table
  * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
  *      - new extension header parser code
+ * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
+ * 	- Unification of {ip,ip6}_tables into x_tables
+ * 	- Removed tcp and udp code, since it's not ipv6 specific
  */
 
 #include <linux/capability.h>
@@ -23,8 +26,6 @@
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <asm/uaccess.h>
@@ -33,6 +34,7 @@
 #include <linux/cpumask.h>
 
 #include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -67,13 +69,8 @@
 #else
 #define IP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
-static DECLARE_MUTEX(ip6t_mutex);
 
-/* Must have mutex */
-#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
 #include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
@@ -91,30 +88,6 @@
 
    Hence the start of any table is given by get_table() below.  */
 
-/* The table itself */
-struct ip6t_table_info
-{
-	/* Size per table */
-	unsigned int size;
-	/* Number of entries: FIXME. --RR */
-	unsigned int number;
-	/* Initial number of entries. Needed for module usage count */
-	unsigned int initial_entries;
-
-	/* Entry points and underflows */
-	unsigned int hook_entry[NF_IP6_NUMHOOKS];
-	unsigned int underflow[NF_IP6_NUMHOOKS];
-
-	/* ip6t_entry tables: one per CPU */
-	void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(ip6t_target);
-static LIST_HEAD(ip6t_match);
-static LIST_HEAD(ip6t_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
 #if 0
 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
@@ -297,7 +270,7 @@
 	      unsigned int hook,
 	      const struct net_device *in,
 	      const struct net_device *out,
-	      struct ip6t_table *table,
+	      struct xt_table *table,
 	      void *userdata)
 {
 	static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
@@ -309,6 +282,7 @@
 	const char *indev, *outdev;
 	void *table_base;
 	struct ip6t_entry *e, *back;
+	struct xt_table_info *private;
 
 	/* Initialization */
 	indev = in ? in->name : nulldevname;
@@ -321,9 +295,10 @@
 	 * match it. */
 
 	read_lock_bh(&table->lock);
+	private = table->private;
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-	table_base = (void *)table->private->entries[smp_processor_id()];
-	e = get_entry(table_base, table->private->hook_entry[hook]);
+	table_base = (void *)private->entries[smp_processor_id()];
+	e = get_entry(table_base, private->hook_entry[hook]);
 
 #ifdef CONFIG_NETFILTER_DEBUG
 	/* Check noone else using our table */
@@ -339,7 +314,7 @@
 #endif
 
 	/* For return from builtin chain */
-	back = get_entry(table_base, table->private->underflow[hook]);
+	back = get_entry(table_base, private->underflow[hook]);
 
 	do {
 		IP_NF_ASSERT(e);
@@ -439,145 +414,6 @@
 #endif
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_table *find_table_lock(const char *name)
-{
-	struct ip6t_table *t;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &ip6t_tables, list)
-		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-			return t;
-	up(&ip6t_mutex);
-	return NULL;
-}
-
-/* Find match, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_match *find_match(const char *name, u8 revision)
-{
-	struct ip6t_match *m;
-	int err = 0;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(m, &ip6t_match, list) {
-		if (strcmp(m->name, name) == 0) {
-			if (m->revision == revision) {
-				if (try_module_get(m->me)) {
-					up(&ip6t_mutex);
-					return m;
-				}
-			} else
-				err = -EPROTOTYPE; /* Found something. */
-		}
-	}
-	up(&ip6t_mutex);
-	return ERR_PTR(err);
-}
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_target *find_target(const char *name, u8 revision)
-{
-	struct ip6t_target *t;
-	int err = 0;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return ERR_PTR(-EINTR);
-
-	list_for_each_entry(t, &ip6t_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision == revision) {
-				if (try_module_get(t->me)) {
-					up(&ip6t_mutex);
-					return t;
-				}
-			} else
-				err = -EPROTOTYPE; /* Found something. */
-		}
-	}
-	up(&ip6t_mutex);
-	return ERR_PTR(err);
-}
-
-struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
-{
-	struct ip6t_target *target;
-
-	target = try_then_request_module(find_target(name, revision),
-					 "ip6t_%s", name);
-	if (IS_ERR(target) || !target)
-		return NULL;
-	return target;
-}
-
-static int match_revfn(const char *name, u8 revision, int *bestp)
-{
-	struct ip6t_match *m;
-	int have_rev = 0;
-
-	list_for_each_entry(m, &ip6t_match, list) {
-		if (strcmp(m->name, name) == 0) {
-			if (m->revision > *bestp)
-				*bestp = m->revision;
-			if (m->revision == revision)
-				have_rev = 1;
-		}
-	}
-	return have_rev;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-	struct ip6t_target *t;
-	int have_rev = 0;
-
-	list_for_each_entry(t, &ip6t_target, list) {
-		if (strcmp(t->name, name) == 0) {
-			if (t->revision > *bestp)
-				*bestp = t->revision;
-			if (t->revision == revision)
-				have_rev = 1;
-		}
-	}
-	return have_rev;
-}
-
-/* Returns true or fals (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-				int (*revfn)(const char *, u8, int *),
-				int *err)
-{
-	int have_rev, best = -1;
-
-	if (down_interruptible(&ip6t_mutex) != 0) {
-		*err = -EINTR;
-		return 1;
-	}
-	have_rev = revfn(name, revision, &best);
-	up(&ip6t_mutex);
-
-	/* Nothing at all?  Return 0 to try loading module. */
-	if (best == -1) {
-		*err = -ENOENT;
-		return 0;
-	}
-
-	*err = best;
-	if (!have_rev)
-		*err = -EPROTONOSUPPORT;
-	return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int
 unconditional(const struct ip6t_ip6 *ipv6)
@@ -594,7 +430,7 @@
 /* Figures out from what hook each rule can be called: returns 0 if
    there are loops.  Puts hook bitmask in comefrom. */
 static int
-mark_source_chains(struct ip6t_table_info *newinfo,
+mark_source_chains(struct xt_table_info *newinfo,
 		   unsigned int valid_hooks, void *entry0)
 {
 	unsigned int hook;
@@ -740,11 +576,11 @@
 {
 	struct ip6t_match *match;
 
-	match = try_then_request_module(find_match(m->u.user.name,
-						   m->u.user.revision),
+	match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
+			      		m->u.user.revision),
 					"ip6t_%s", m->u.user.name);
 	if (IS_ERR(match) || !match) {
-		duprintf("check_match: `%s' not found\n", m->u.user.name);
+	  	duprintf("check_match: `%s' not found\n", m->u.user.name);
 		return match ? PTR_ERR(match) : -ENOENT;
 	}
 	m->u.kernel.match = match;
@@ -785,8 +621,9 @@
 		goto cleanup_matches;
 
 	t = ip6t_get_target(e);
-	target = try_then_request_module(find_target(t->u.user.name,
-						     t->u.user.revision),
+	target = try_then_request_module(xt_find_target(AF_INET6,
+							t->u.user.name,
+							t->u.user.revision),
 					 "ip6t_%s", t->u.user.name);
 	if (IS_ERR(target) || !target) {
 		duprintf("check_entry: `%s' not found\n", t->u.user.name);
@@ -822,7 +659,7 @@
 
 static inline int
 check_entry_size_and_hooks(struct ip6t_entry *e,
-			   struct ip6t_table_info *newinfo,
+			   struct xt_table_info *newinfo,
 			   unsigned char *base,
 			   unsigned char *limit,
 			   const unsigned int *hook_entries,
@@ -856,7 +693,7 @@
            < 0 (not IP6T_RETURN). --RR */
 
 	/* Clear counters and comefrom */
-	e->counters = ((struct ip6t_counters) { 0, 0 });
+	e->counters = ((struct xt_counters) { 0, 0 });
 	e->comefrom = 0;
 
 	(*i)++;
@@ -886,7 +723,7 @@
 static int
 translate_table(const char *name,
 		unsigned int valid_hooks,
-		struct ip6t_table_info *newinfo,
+		struct xt_table_info *newinfo,
 		void *entry0,
 		unsigned int size,
 		unsigned int number,
@@ -963,48 +800,10 @@
 	return ret;
 }
 
-static struct ip6t_table_info *
-replace_table(struct ip6t_table *table,
-	      unsigned int num_counters,
-	      struct ip6t_table_info *newinfo,
-	      int *error)
-{
-	struct ip6t_table_info *oldinfo;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-	{
-		int cpu;
-
-		for_each_cpu(cpu) {
-			struct ip6t_entry *table_base = newinfo->entries[cpu];
-			if (table_base)
-				table_base->comefrom = 0xdead57ac;
-		}
-	}
-#endif
-
-	/* Do the substitution. */
-	write_lock_bh(&table->lock);
-	/* Check inside lock: is the old number correct? */
-	if (num_counters != table->private->number) {
-		duprintf("num_counters != table->private->number (%u/%u)\n",
-			 num_counters, table->private->number);
-		write_unlock_bh(&table->lock);
-		*error = -EAGAIN;
-		return NULL;
-	}
-	oldinfo = table->private;
-	table->private = newinfo;
-	newinfo->initial_entries = oldinfo->initial_entries;
-	write_unlock_bh(&table->lock);
-
-	return oldinfo;
-}
-
 /* Gets counters. */
 static inline int
 add_entry_to_counter(const struct ip6t_entry *e,
-		     struct ip6t_counters total[],
+		     struct xt_counters total[],
 		     unsigned int *i)
 {
 	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -1025,8 +824,8 @@
 }
 
 static void
-get_counters(const struct ip6t_table_info *t,
-	     struct ip6t_counters counters[])
+get_counters(const struct xt_table_info *t,
+	     struct xt_counters counters[])
 {
 	unsigned int cpu;
 	unsigned int i;
@@ -1060,19 +859,20 @@
 
 static int
 copy_entries_to_user(unsigned int total_size,
-		     struct ip6t_table *table,
+		     struct xt_table *table,
 		     void __user *userptr)
 {
 	unsigned int off, num, countersize;
 	struct ip6t_entry *e;
-	struct ip6t_counters *counters;
+	struct xt_counters *counters;
+	struct xt_table_info *private = table->private;
 	int ret = 0;
 	void *loc_cpu_entry;
 
 	/* We need atomic snapshot of counters: rest doesn't change
 	   (other than comefrom, which userspace doesn't care
 	   about). */
-	countersize = sizeof(struct ip6t_counters) * table->private->number;
+	countersize = sizeof(struct xt_counters) * private->number;
 	counters = vmalloc(countersize);
 
 	if (counters == NULL)
@@ -1080,11 +880,11 @@
 
 	/* First, sum counters... */
 	write_lock_bh(&table->lock);
-	get_counters(table->private, counters);
+	get_counters(private, counters);
 	write_unlock_bh(&table->lock);
 
 	/* choose the copy that is on ourc node/cpu */
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
 	if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
 		ret = -EFAULT;
 		goto free_counters;
@@ -1143,87 +943,42 @@
 	    struct ip6t_get_entries __user *uptr)
 {
 	int ret;
-	struct ip6t_table *t;
+	struct xt_table *t;
 
-	t = find_table_lock(entries->name);
+	t = xt_find_table_lock(AF_INET6, entries->name);
 	if (t && !IS_ERR(t)) {
-		duprintf("t->private->number = %u\n",
-			 t->private->number);
-		if (entries->size == t->private->size)
-			ret = copy_entries_to_user(t->private->size,
+		struct xt_table_info *private = t->private;
+		duprintf("t->private->number = %u\n", private->number);
+		if (entries->size == private->size)
+			ret = copy_entries_to_user(private->size,
 						   t, uptr->entrytable);
 		else {
 			duprintf("get_entries: I've got %u not %u!\n",
-				 t->private->size,
-				 entries->size);
+				 private->size, entries->size);
 			ret = -EINVAL;
 		}
 		module_put(t->me);
-		up(&ip6t_mutex);
+		xt_table_unlock(t);
 	} else
 		ret = t ? PTR_ERR(t) : -ENOENT;
 
 	return ret;
 }
 
-static void free_table_info(struct ip6t_table_info *info)
-{
-	int cpu;
-	for_each_cpu(cpu) {
-		if (info->size <= PAGE_SIZE)
-			kfree(info->entries[cpu]);
-		else
-			vfree(info->entries[cpu]);
-	}
-	kfree(info);
-}
-
-static struct ip6t_table_info *alloc_table_info(unsigned int size)
-{
-	struct ip6t_table_info *newinfo;
-	int cpu;
-
-	newinfo = kzalloc(sizeof(struct ip6t_table_info), GFP_KERNEL);
-	if (!newinfo)
-		return NULL;
-
-	newinfo->size = size;
-
-	for_each_cpu(cpu) {
-		if (size <= PAGE_SIZE)
-			newinfo->entries[cpu] = kmalloc_node(size,
-							GFP_KERNEL,
-							cpu_to_node(cpu));
-		else
-			newinfo->entries[cpu] = vmalloc_node(size,
-							     cpu_to_node(cpu));
-		if (newinfo->entries[cpu] == NULL) {
-			free_table_info(newinfo);
-			return NULL;
-		}
-	}
-
-	return newinfo;
-}
-
 static int
 do_replace(void __user *user, unsigned int len)
 {
 	int ret;
 	struct ip6t_replace tmp;
-	struct ip6t_table *t;
-	struct ip6t_table_info *newinfo, *oldinfo;
-	struct ip6t_counters *counters;
+	struct xt_table *t;
+	struct xt_table_info *newinfo, *oldinfo;
+	struct xt_counters *counters;
 	void *loc_cpu_entry, *loc_cpu_old_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 		return -EFAULT;
 
-	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-	if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-		return -ENOMEM;
-
-	newinfo = alloc_table_info(tmp.size);
+	newinfo = xt_alloc_table_info(tmp.size);
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1235,7 +990,7 @@
 		goto free_newinfo;
 	}
 
-	counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
+	counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
 	if (!counters) {
 		ret = -ENOMEM;
 		goto free_newinfo;
@@ -1249,7 +1004,7 @@
 
 	duprintf("ip_tables: Translated table\n");
 
-	t = try_then_request_module(find_table_lock(tmp.name),
+	t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
 				    "ip6table_%s", tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1264,7 +1019,7 @@
 		goto put_module;
 	}
 
-	oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+	oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
 	if (!oldinfo)
 		goto put_module;
 
@@ -1283,23 +1038,23 @@
 	/* Decrease module usage counts and free resource */
 	loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
 	IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
-	free_table_info(oldinfo);
+	xt_free_table_info(oldinfo);
 	if (copy_to_user(tmp.counters, counters,
-			 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
+			 sizeof(struct xt_counters) * tmp.num_counters) != 0)
 		ret = -EFAULT;
 	vfree(counters);
-	up(&ip6t_mutex);
+	xt_table_unlock(t);
 	return ret;
 
  put_module:
 	module_put(t->me);
-	up(&ip6t_mutex);
+	xt_table_unlock(t);
  free_newinfo_counters_untrans:
 	IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
  free_newinfo_counters:
 	vfree(counters);
  free_newinfo:
-	free_table_info(newinfo);
+	xt_free_table_info(newinfo);
 	return ret;
 }
 
@@ -1307,7 +1062,7 @@
  * and everything is OK. */
 static inline int
 add_counter_to_entry(struct ip6t_entry *e,
-		     const struct ip6t_counters addme[],
+		     const struct xt_counters addme[],
 		     unsigned int *i)
 {
 #if 0
@@ -1329,15 +1084,16 @@
 do_add_counters(void __user *user, unsigned int len)
 {
 	unsigned int i;
-	struct ip6t_counters_info tmp, *paddc;
-	struct ip6t_table *t;
+	struct xt_counters_info tmp, *paddc;
+	struct xt_table_info *private;
+	struct xt_table *t;
 	int ret = 0;
 	void *loc_cpu_entry;
 
 	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
 		return -EFAULT;
 
-	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
+	if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
 		return -EINVAL;
 
 	paddc = vmalloc(len);
@@ -1349,29 +1105,30 @@
 		goto free;
 	}
 
-	t = find_table_lock(tmp.name);
+	t = xt_find_table_lock(AF_INET6, tmp.name);
 	if (!t || IS_ERR(t)) {
 		ret = t ? PTR_ERR(t) : -ENOENT;
 		goto free;
 	}
 
 	write_lock_bh(&t->lock);
-	if (t->private->number != paddc->num_counters) {
+	private = t->private;
+	if (private->number != paddc->num_counters) {
 		ret = -EINVAL;
 		goto unlock_up_free;
 	}
 
 	i = 0;
 	/* Choose the copy that is on our node */
-	loc_cpu_entry = t->private->entries[smp_processor_id()];
+	loc_cpu_entry = private->entries[smp_processor_id()];
 	IP6T_ENTRY_ITERATE(loc_cpu_entry,
-			  t->private->size,
+			  private->size,
 			  add_counter_to_entry,
 			  paddc->counters,
 			  &i);
  unlock_up_free:
 	write_unlock_bh(&t->lock);
-	up(&ip6t_mutex);
+	xt_table_unlock(t);
 	module_put(t->me);
  free:
 	vfree(paddc);
@@ -1415,7 +1172,7 @@
 	switch (cmd) {
 	case IP6T_SO_GET_INFO: {
 		char name[IP6T_TABLE_MAXNAMELEN];
-		struct ip6t_table *t;
+		struct xt_table *t;
 
 		if (*len != sizeof(struct ip6t_getinfo)) {
 			duprintf("length %u != %u\n", *len,
@@ -1430,25 +1187,26 @@
 		}
 		name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
 
-		t = try_then_request_module(find_table_lock(name),
+		t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
 					    "ip6table_%s", name);
 		if (t && !IS_ERR(t)) {
 			struct ip6t_getinfo info;
+			struct xt_table_info *private = t->private;
 
 			info.valid_hooks = t->valid_hooks;
-			memcpy(info.hook_entry, t->private->hook_entry,
+			memcpy(info.hook_entry, private->hook_entry,
 			       sizeof(info.hook_entry));
-			memcpy(info.underflow, t->private->underflow,
+			memcpy(info.underflow, private->underflow,
 			       sizeof(info.underflow));
-			info.num_entries = t->private->number;
-			info.size = t->private->size;
+			info.num_entries = private->number;
+			info.size = private->size;
 			memcpy(info.name, name, sizeof(info.name));
 
 			if (copy_to_user(user, &info, *len) != 0)
 				ret = -EFAULT;
 			else
 				ret = 0;
-			up(&ip6t_mutex);
+			xt_table_unlock(t);
 			module_put(t->me);
 		} else
 			ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1475,7 +1233,7 @@
 	case IP6T_SO_GET_REVISION_MATCH:
 	case IP6T_SO_GET_REVISION_TARGET: {
 		struct ip6t_get_revision rev;
-		int (*revfn)(const char *, u8, int *);
+		int target;
 
 		if (*len != sizeof(rev)) {
 			ret = -EINVAL;
@@ -1487,12 +1245,13 @@
 		}
 
 		if (cmd == IP6T_SO_GET_REVISION_TARGET)
-			revfn = target_revfn;
+			target = 1;
 		else
-			revfn = match_revfn;
+			target = 0;
 
-		try_then_request_module(find_revision(rev.name, rev.revision,
-						      revfn, &ret),
+		try_then_request_module(xt_find_revision(AF_INET6, rev.name,
+							 rev.revision,
+							 target, &ret),
 					"ip6t_%s", rev.name);
 		break;
 	}
@@ -1505,61 +1264,16 @@
 	return ret;
 }
 
-/* Registration hooks for targets. */
-int
-ip6t_register_target(struct ip6t_target *target)
-{
-	int ret;
-
-	ret = down_interruptible(&ip6t_mutex);
-	if (ret != 0)
-		return ret;
-	list_add(&target->list, &ip6t_target);
-	up(&ip6t_mutex);
-	return ret;
-}
-
-void
-ip6t_unregister_target(struct ip6t_target *target)
-{
-	down(&ip6t_mutex);
-	LIST_DELETE(&ip6t_target, target);
-	up(&ip6t_mutex);
-}
-
-int
-ip6t_register_match(struct ip6t_match *match)
-{
-	int ret;
-
-	ret = down_interruptible(&ip6t_mutex);
-	if (ret != 0)
-		return ret;
-
-	list_add(&match->list, &ip6t_match);
-	up(&ip6t_mutex);
-
-	return ret;
-}
-
-void
-ip6t_unregister_match(struct ip6t_match *match)
-{
-	down(&ip6t_mutex);
-	LIST_DELETE(&ip6t_match, match);
-	up(&ip6t_mutex);
-}
-
-int ip6t_register_table(struct ip6t_table *table,
+int ip6t_register_table(struct xt_table *table,
 			const struct ip6t_replace *repl)
 {
 	int ret;
-	struct ip6t_table_info *newinfo;
-	static struct ip6t_table_info bootstrap
+	struct xt_table_info *newinfo;
+	static struct xt_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 	void *loc_cpu_entry;
 
-	newinfo = alloc_table_info(repl->size);
+	newinfo = xt_alloc_table_info(repl->size);
 	if (!newinfo)
 		return -ENOMEM;
 
@@ -1573,244 +1287,29 @@
 			      repl->hook_entry,
 			      repl->underflow);
 	if (ret != 0) {
-		free_table_info(newinfo);
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	ret = down_interruptible(&ip6t_mutex);
-	if (ret != 0) {
-		free_table_info(newinfo);
+	if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+		xt_free_table_info(newinfo);
 		return ret;
 	}
 
-	/* Don't autoload: we'd eat our tail... */
-	if (list_named_find(&ip6t_tables, table->name)) {
-		ret = -EEXIST;
-		goto free_unlock;
-	}
-
-	/* Simplifies replace_table code. */
-	table->private = &bootstrap;
-	if (!replace_table(table, 0, newinfo, &ret))
-		goto free_unlock;
-
-	duprintf("table->private->number = %u\n",
-		 table->private->number);
-
-	/* save number of initial entries */
-	table->private->initial_entries = table->private->number;
-
-	rwlock_init(&table->lock);
-	list_prepend(&ip6t_tables, table);
-
- unlock:
-	up(&ip6t_mutex);
-	return ret;
-
- free_unlock:
-	free_table_info(newinfo);
-	goto unlock;
+	return 0;
 }
 
-void ip6t_unregister_table(struct ip6t_table *table)
+void ip6t_unregister_table(struct xt_table *table)
 {
+	struct xt_table_info *private;
 	void *loc_cpu_entry;
 
-	down(&ip6t_mutex);
-	LIST_DELETE(&ip6t_tables, table);
-	up(&ip6t_mutex);
+	private = xt_unregister_table(table);
 
 	/* Decrease module usage counts and free resources */
-	loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-	IP6T_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
-			  cleanup_entry, NULL);
-	free_table_info(table->private);
-}
-
-/* Returns 1 if the port is matched by the range, 0 otherwise */
-static inline int
-port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
-{
-	int ret;
-
-	ret = (port >= min && port <= max) ^ invert;
-	return ret;
-}
-
-static int
-tcp_find_option(u_int8_t option,
-		const struct sk_buff *skb,
-		unsigned int tcpoff,
-		unsigned int optlen,
-		int invert,
-		int *hotdrop)
-{
-	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-	u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
-	unsigned int i;
-
-	duprintf("tcp_match: finding option\n");
-	if (!optlen)
-		return invert;
-	/* If we don't have the whole header, drop packet. */
-	op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
-				_opt);
-	if (op == NULL) {
-		*hotdrop = 1;
-		return 0;
-	}
-
-	for (i = 0; i < optlen; ) {
-		if (op[i] == option) return !invert;
-		if (op[i] < 2) i++;
-		else i += op[i+1]?:1;
-	}
-
-	return invert;
-}
-
-static int
-tcp_match(const struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  const void *matchinfo,
-	  int offset,
-	  unsigned int protoff,
-	  int *hotdrop)
-{
-	struct tcphdr _tcph, *th;
-	const struct ip6t_tcp *tcpinfo = matchinfo;
-
-	if (offset) {
-		/* To quote Alan:
-
-		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
-		   causes this. Its a cracker trying to break in by doing a
-		   flag overwrite to pass the direction checks.
-		*/
-		if (offset == 1) {
-			duprintf("Dropping evil TCP offset=1 frag.\n");
-			*hotdrop = 1;
-		}
-		/* Must not be a fragment. */
-		return 0;
-	}
-
-#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
-
-	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
-	if (th == NULL) {
-		/* We've been asked to examine this packet, and we
-		   can't.  Hence, no choice but to drop. */
-		duprintf("Dropping evil TCP offset=0 tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
-			ntohs(th->source),
-			!!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
-		return 0;
-	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
-			ntohs(th->dest),
-			!!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
-		return 0;
-	if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
-		      == tcpinfo->flg_cmp,
-		      IP6T_TCP_INV_FLAGS))
-		return 0;
-	if (tcpinfo->option) {
-		if (th->doff * 4 < sizeof(_tcph)) {
-			*hotdrop = 1;
-			return 0;
-		}
-		if (!tcp_find_option(tcpinfo->option, skb, protoff,
-				     th->doff*4 - sizeof(*th),
-				     tcpinfo->invflags & IP6T_TCP_INV_OPTION,
-				     hotdrop))
-			return 0;
-	}
-	return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp_checkentry(const char *tablename,
-	       const struct ip6t_ip6 *ipv6,
-	       void *matchinfo,
-	       unsigned int matchsize,
-	       unsigned int hook_mask)
-{
-	const struct ip6t_tcp *tcpinfo = matchinfo;
-
-	/* Must specify proto == TCP, and no unknown invflags */
-	return ipv6->proto == IPPROTO_TCP
-		&& !(ipv6->invflags & IP6T_INV_PROTO)
-		&& matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
-		&& !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
-}
-
-static int
-udp_match(const struct sk_buff *skb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  const void *matchinfo,
-	  int offset,
-	  unsigned int protoff,
-	  int *hotdrop)
-{
-	struct udphdr _udph, *uh;
-	const struct ip6t_udp *udpinfo = matchinfo;
-
-	/* Must not be a fragment. */
-	if (offset)
-		return 0;
-
-	uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
-	if (uh == NULL) {
-		/* We've been asked to examine this packet, and we
-		   can't.  Hence, no choice but to drop. */
-		duprintf("Dropping evil UDP tinygram.\n");
-		*hotdrop = 1;
-		return 0;
-	}
-
-	return port_match(udpinfo->spts[0], udpinfo->spts[1],
-			  ntohs(uh->source),
-			  !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
-		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
-			      ntohs(uh->dest),
-			      !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp_checkentry(const char *tablename,
-	       const struct ip6t_ip6 *ipv6,
-	       void *matchinfo,
-	       unsigned int matchinfosize,
-	       unsigned int hook_mask)
-{
-	const struct ip6t_udp *udpinfo = matchinfo;
-
-	/* Must specify proto == UDP, and no unknown invflags */
-	if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
-		duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
-			 IPPROTO_UDP);
-		return 0;
-	}
-	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
-		duprintf("ip6t_udp: matchsize %u != %u\n",
-			 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
-		return 0;
-	}
-	if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
-		duprintf("ip6t_udp: unknown flags %X\n",
-			 udpinfo->invflags);
-		return 0;
-	}
-
-	return 1;
+	loc_cpu_entry = private->entries[raw_smp_processor_id()];
+	IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+	xt_free_table_info(private);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1858,11 +1357,12 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 icmp6_checkentry(const char *tablename,
-	   const struct ip6t_ip6 *ipv6,
+	   const void *entry,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
+	const struct ip6t_ip6 *ipv6 = entry;
 	const struct ip6t_icmp *icmpinfo = matchinfo;
 
 	/* Must specify proto == ICMP, and no unknown invflags */
@@ -1892,164 +1392,42 @@
 	.get		= do_ip6t_get_ctl,
 };
 
-static struct ip6t_match tcp_matchstruct = {
-	.name		= "tcp",
-	.match		= &tcp_match,
-	.checkentry	= &tcp_checkentry,
-};
-
-static struct ip6t_match udp_matchstruct = {
-	.name		= "udp",
-	.match		= &udp_match,
-	.checkentry	= &udp_checkentry,
-};
-
 static struct ip6t_match icmp6_matchstruct = {
 	.name		= "icmp6",
 	.match		= &icmp6_match,
 	.checkentry	= &icmp6_checkentry,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const char *i,
-			     off_t start_offset, char *buffer, int length,
-			     off_t *pos, unsigned int *count)
-{
-	if ((*count)++ >= start_offset) {
-		unsigned int namelen;
-
-		namelen = sprintf(buffer + *pos, "%s\n",
-				  i + sizeof(struct list_head));
-		if (*pos + namelen > length) {
-			/* Stop iterating */
-			return 1;
-		}
-		*pos += namelen;
-	}
-	return 0;
-}
-
-static inline int print_target(const struct ip6t_target *t,
-                               off_t start_offset, char *buffer, int length,
-                               off_t *pos, unsigned int *count)
-{
-	if (t == &ip6t_standard_target || t == &ip6t_error_target)
-		return 0;
-	return print_name((char *)t, start_offset, buffer, length, pos, count);
-}
-
-static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&ip6t_tables, print_name, char *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&ip6t_mutex);
-
-	/* `start' hack - see fs/proc/generic.c line ~105 */
-	*start=(char *)((unsigned long)count-offset);
-	return pos;
-}
-
-static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&ip6t_mutex);
-
-	*start = (char *)((unsigned long)count - offset);
-	return pos;
-}
-
-static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	unsigned int count = 0;
-
-	if (down_interruptible(&ip6t_mutex) != 0)
-		return 0;
-
-	LIST_FIND(&ip6t_match, print_name, char *,
-		  offset, buffer, length, &pos, &count);
-
-	up(&ip6t_mutex);
-
-	*start = (char *)((unsigned long)count - offset);
-	return pos;
-}
-
-static const struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
-{ { "ip6_tables_names", ip6t_get_tables },
-  { "ip6_tables_targets", ip6t_get_targets },
-  { "ip6_tables_matches", ip6t_get_matches },
-  { NULL, NULL} };
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
 	int ret;
 
+	xt_proto_init(AF_INET6);
+
 	/* Noone else will be downing sem now, so we won't sleep */
-	down(&ip6t_mutex);
-	list_append(&ip6t_target, &ip6t_standard_target);
-	list_append(&ip6t_target, &ip6t_error_target);
-	list_append(&ip6t_match, &tcp_matchstruct);
-	list_append(&ip6t_match, &udp_matchstruct);
-	list_append(&ip6t_match, &icmp6_matchstruct);
-	up(&ip6t_mutex);
+	xt_register_target(AF_INET6, &ip6t_standard_target);
+	xt_register_target(AF_INET6, &ip6t_error_target);
+	xt_register_match(AF_INET6, &icmp6_matchstruct);
 
 	/* Register setsockopt */
 	ret = nf_register_sockopt(&ip6t_sockopts);
 	if (ret < 0) {
 		duprintf("Unable to register sockopts.\n");
+		xt_proto_fini(AF_INET6);
 		return ret;
 	}
 
-#ifdef CONFIG_PROC_FS
-	{
-		struct proc_dir_entry *proc;
-		int i;
-
-		for (i = 0; ip6t_proc_entry[i].name; i++) {
-			proc = proc_net_create(ip6t_proc_entry[i].name, 0,
-					       ip6t_proc_entry[i].get_info);
-			if (!proc) {
-				while (--i >= 0)
-				       proc_net_remove(ip6t_proc_entry[i].name);
-				nf_unregister_sockopt(&ip6t_sockopts);
-				return -ENOMEM;
-			}
-			proc->owner = THIS_MODULE;
-		}
-	}
-#endif
-
-	printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
+	printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
 	return 0;
 }
 
 static void __exit fini(void)
 {
 	nf_unregister_sockopt(&ip6t_sockopts);
-#ifdef CONFIG_PROC_FS
-	{
-		int i;
-		for (i = 0; ip6t_proc_entry[i].name; i++)
-			proc_net_remove(ip6t_proc_entry[i].name);
-	}
-#endif
+	xt_unregister_match(AF_INET6, &icmp6_matchstruct);
+	xt_unregister_target(AF_INET6, &ip6t_error_target);
+	xt_unregister_target(AF_INET6, &ip6t_standard_target);
+	xt_proto_fini(AF_INET6);
 }
 
 /*
@@ -2128,10 +1506,6 @@
 EXPORT_SYMBOL(ip6t_register_table);
 EXPORT_SYMBOL(ip6t_unregister_table);
 EXPORT_SYMBOL(ip6t_do_table);
-EXPORT_SYMBOL(ip6t_register_match);
-EXPORT_SYMBOL(ip6t_unregister_match);
-EXPORT_SYMBOL(ip6t_register_target);
-EXPORT_SYMBOL(ip6t_unregister_target);
 EXPORT_SYMBOL(ip6t_ext_hdr);
 EXPORT_SYMBOL(ipv6_find_hdr);
 EXPORT_SYMBOL(ip6_masked_addrcmp);
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index 8f5549b..306200c 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -62,7 +62,7 @@
 }
 
 static int ip6t_hl_checkentry(const char *tablename,
-		const struct ip6t_entry *e,
+		const void *entry,
 		void *targinfo,
 		unsigned int targinfosize,
 		unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index ae4653b..77c7258 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -63,9 +63,8 @@
 		return;
 	}
 
-	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
-	printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->saddr));
-	printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->daddr));
+	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
+	printk("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr));
 
 	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
 	printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
@@ -444,7 +443,7 @@
 
 
 static int ip6t_log_checkentry(const char *tablename,
-			       const struct ip6t_entry *e,
+			       const void *entry,
 			       void *targinfo,
 			       unsigned int targinfosize,
 			       unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c
deleted file mode 100644
index eab8fb8..0000000
--- a/net/ipv6/netfilter/ip6t_MARK.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This is a module which is used for setting the NFMARK field of an skb. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_MARK.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-	const struct ip6t_mark_target_info *markinfo = targinfo;
-
-	if((*pskb)->nfmark != markinfo->mark)
-		(*pskb)->nfmark = markinfo->mark;
-
-	return IP6T_CONTINUE;
-}
-
-static int
-checkentry(const char *tablename,
-	   const struct ip6t_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_mark_target_info))) {
-		printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IP6T_ALIGN(sizeof(struct ip6t_mark_target_info)));
-		return 0;
-	}
-
-	if (strcmp(tablename, "mangle") != 0) {
-		printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ip6t_target ip6t_mark_reg = { 
-	.name		= "MARK",
-	.target		= target,
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE
-};
-
-static int __init init(void)
-{
-	printk(KERN_DEBUG "registering ipv6 mark target\n");
-	if (ip6t_register_target(&ip6t_mark_reg))
-		return -EINVAL;
-
-	return 0;
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_target(&ip6t_mark_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_NFQUEUE.c b/net/ipv6/netfilter/ip6t_NFQUEUE.c
deleted file mode 100644
index c6e3730..0000000
--- a/net/ipv6/netfilter/ip6t_NFQUEUE.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ip6tables module for using new netfilter netlink queue
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as 
- * published by the Free Software Foundation.
- * 
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
-
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables NFQUEUE target");
-MODULE_LICENSE("GPL");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-	const struct ipt_NFQ_info *tinfo = targinfo;
-
-	return NF_QUEUE_NR(tinfo->queuenum);
-}
-
-static int
-checkentry(const char *tablename,
-	   const struct ip6t_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-	if (targinfosize != IP6T_ALIGN(sizeof(struct ipt_NFQ_info))) {
-		printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-		       targinfosize,
-		       IP6T_ALIGN(sizeof(struct ipt_NFQ_info)));
-		return 0;
-	}
-
-	return 1;
-}
-
-static struct ip6t_target ipt_NFQ_reg = {
-	.name		= "NFQUEUE",
-	.target		= target,
-	.checkentry	= checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_target(&ipt_NFQ_reg);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_target(&ipt_NFQ_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index b03e87a..c745717 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -218,12 +218,13 @@
 }
 
 static int check(const char *tablename,
-		 const struct ip6t_entry *e,
+		 const void *entry,
 		 void *targinfo,
 		 unsigned int targinfosize,
 		 unsigned int hook_mask)
 {
  	const struct ip6t_reject_info *rejinfo = targinfo;
+	const struct ip6t_entry *e = entry;
 
  	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
   		DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index f5c1a7ff..219a303 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -98,7 +98,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c
index 48cf5f9..80fe826 100644
--- a/net/ipv6/netfilter/ip6t_dst.c
+++ b/net/ipv6/netfilter/ip6t_dst.c
@@ -178,7 +178,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *info,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
index e1828f6..724285d 100644
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ b/net/ipv6/netfilter/ip6t_esp.c
@@ -76,7 +76,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-	   const struct ip6t_ip6 *ip,
+	   const void *ip,
 	   void *matchinfo,
 	   unsigned int matchinfosize,
 	   unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 616c2cb..ddf5f57 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -62,7 +62,7 @@
 
 static int
 ip6t_eui64_checkentry(const char *tablename,
-		   const struct ip6t_ip6 *ip,
+		   const void  *ip,
 		   void *matchinfo,
 		   unsigned int matchsize,
 		   unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index d1549b2..a9964b9 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -115,7 +115,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *ip,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index e3bc8e2..ed8ded1 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -178,7 +178,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 0beaff5..c5d9079 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -48,7 +48,7 @@
 	return 0;
 }
 
-static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
+static int checkentry(const char *tablename, const void *entry,
 		      void *matchinfo, unsigned int matchsize,
 		      unsigned int hook_mask)
 {
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 32e67f0..fda1cea 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -124,7 +124,7 @@
 
 static int
 ipv6header_checkentry(const char *tablename,
-		      const struct ip6t_ip6 *ip,
+		      const void *ip,
 		      void *matchinfo,
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_length.c b/net/ipv6/netfilter/ip6t_length.c
deleted file mode 100644
index e0537d3..0000000
--- a/net/ipv6/netfilter/ip6t_length.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Length Match - IPv6 Port */
-
-/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv6/ip6t_length.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
-MODULE_DESCRIPTION("IPv6 packet length match");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	const struct ip6t_length_info *info = matchinfo;
-	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
-	
-	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ip6t_match length_match = {
-	.name		= "length",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_match(&length_match);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&length_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_limit.c b/net/ipv6/netfilter/ip6t_limit.c
deleted file mode 100644
index fb782f6..0000000
--- a/net/ipv6/netfilter/ip6t_limit.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Kernel module to control the rate
- *
- * 2 September 1999: Changed from the target RATE to the match
- *                   `limit', removed logging.  Did I mention that
- *                   Alexey is a fucking genius?
- *                   Rusty Russell (rusty@rustcorp.com.au).  */
-
-/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
- * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_limit.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
-MODULE_DESCRIPTION("rate limiting within ip6tables");
-
-/* The algorithm used is the Simple Token Bucket Filter (TBF)
- * see net/sched/sch_tbf.c in the linux source tree
- */
-
-static DEFINE_SPINLOCK(limit_lock);
-
-/* Rusty: This is my (non-mathematically-inclined) understanding of
-   this algorithm.  The `average rate' in jiffies becomes your initial
-   amount of credit `credit' and the most credit you can ever have
-   `credit_cap'.  The `peak rate' becomes the cost of passing the
-   test, `cost'.
-
-   `prev' tracks the last packet hit: you gain one credit per jiffy.
-   If you get credit balance more than this, the extra credit is
-   discarded.  Every time the match passes, you lose `cost' credits;
-   if you don't have that many, the test fails.
-
-   See Alexey's formal explanation in net/sched/sch_tbf.c.
-
-   To avoid underflow, we multiply by 128 (ie. you get 128 credits per
-   jiffy).  Hence a cost of 2^32-1, means one pass per 32768 seconds
-   at 1024HZ (or one every 9 hours).  A cost of 1 means 12800 passes
-   per second at 100HZ.  */
-
-#define CREDITS_PER_JIFFY 128
-
-static int
-ip6t_limit_match(const struct sk_buff *skb,
-		const struct net_device *in,
-		const struct net_device *out,
-		const void *matchinfo,
-		int offset,
-		unsigned int protoff,
-		int *hotdrop)
-{
-	struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master;
-	unsigned long now = jiffies;
-
-	spin_lock_bh(&limit_lock);
-	r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
-	if (r->credit > r->credit_cap)
-		r->credit = r->credit_cap;
-
-	if (r->credit >= r->cost) {
-		/* We're not limited. */
-		r->credit -= r->cost;
-		spin_unlock_bh(&limit_lock);
-		return 1;
-	}
-
-       	spin_unlock_bh(&limit_lock);
-	return 0;
-}
-
-/* Precision saver. */
-static u_int32_t
-user2credits(u_int32_t user)
-{
-	/* If multiplying would overflow... */
-	if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
-		/* Divide first. */
-		return (user / IP6T_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
-
-	return (user * HZ * CREDITS_PER_JIFFY) / IP6T_LIMIT_SCALE;
-}
-
-static int
-ip6t_limit_checkentry(const char *tablename,
-		     const struct ip6t_ip6 *ip,
-		     void *matchinfo,
-		     unsigned int matchsize,
-		     unsigned int hook_mask)
-{
-	struct ip6t_rateinfo *r = matchinfo;
-
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rateinfo)))
-		return 0;
-
-	/* Check for overflow. */
-	if (r->burst == 0
-	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-		printk("Call rusty: overflow in ip6t_limit: %u/%u\n",
-		       r->avg, r->burst);
-		return 0;
-	}
-
-	/* User avg in seconds * IP6T_LIMIT_SCALE: convert to jiffies *
-	   128. */
-	r->prev = jiffies;
-	r->credit = user2credits(r->avg * r->burst);	 /* Credits full. */
-	r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
-	r->cost = user2credits(r->avg);
-
-	/* For SMP, we only want to use one set of counters. */
-	r->master = r;
-
-	return 1;
-}
-
-static struct ip6t_match ip6t_limit_reg = {
-	.name		= "limit",
-	.match		= ip6t_limit_match,
-	.checkentry	= ip6t_limit_checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	if (ip6t_register_match(&ip6t_limit_reg))
-		return -EINVAL;
-	return 0;
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&ip6t_limit_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_mac.c b/net/ipv6/netfilter/ip6t_mac.c
deleted file mode 100644
index c848152..0000000
--- a/net/ipv6/netfilter/ip6t_mac.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Kernel module to match MAC address parameters. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/etherdevice.h>
-
-#include <linux/netfilter_ipv6/ip6t_mac.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MAC address matching module for IPv6");
-MODULE_AUTHOR("Netfilter Core Teaam <coreteam@netfilter.org>");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-    const struct ip6t_mac_info *info = matchinfo;
-
-    /* Is mac pointer valid? */
-    return (skb->mac.raw >= skb->head
-	    && (skb->mac.raw + ETH_HLEN) <= skb->data
-	    /* If so, compare... */
-	    && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
-		^ info->invert));
-}
-
-static int
-ip6t_mac_checkentry(const char *tablename,
-		   const struct ip6t_ip6 *ip,
-		   void *matchinfo,
-		   unsigned int matchsize,
-		   unsigned int hook_mask)
-{
-	if (hook_mask
-	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN)
-		| (1 << NF_IP6_FORWARD))) {
-		printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or"
-		       " FORWARD\n");
-		return 0;
-	}
-
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mac_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ip6t_match mac_match = {
-	.name		= "mac",
-	.match		= &match,
-	.checkentry	= &ip6t_mac_checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_match(&mac_match);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&mac_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_mark.c b/net/ipv6/netfilter/ip6t_mark.c
deleted file mode 100644
index affc3de..0000000
--- a/net/ipv6/netfilter/ip6t_mark.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Kernel module to match NFMARK values. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter_ipv6/ip6t_mark.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables mark match");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	const struct ip6t_mark_info *info = matchinfo;
-
-	return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mark_info)))
-		return 0;
-
-	return 1;
-}
-
-static struct ip6t_match mark_match = {
-	.name		= "mark",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_match(&mark_match);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&mark_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c
index 6e32461..49f7829 100644
--- a/net/ipv6/netfilter/ip6t_multiport.c
+++ b/net/ipv6/netfilter/ip6t_multiport.c
@@ -84,11 +84,12 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-	   const struct ip6t_ip6 *ip,
+	   const void *info,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
+	const struct ip6t_ip6 *ip = info;
 	const struct ip6t_multiport *multiinfo = matchinfo;
 
 	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index 4de4cda..5409b37 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -53,7 +53,7 @@
 
 static int
 checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
+           const void  *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_physdev.c b/net/ipv6/netfilter/ip6t_physdev.c
deleted file mode 100644
index 71515c8..0000000
--- a/net/ipv6/netfilter/ip6t_physdev.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Kernel module to match the bridge port in and
- * out device for IP packets coming into contact with a bridge. */
-
-/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv6/ip6t_physdev.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_bridge.h>
-#define MATCH   1
-#define NOMATCH 0
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-MODULE_DESCRIPTION("iptables bridge physical device match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-	int i;
-	static const char nulldevname[IFNAMSIZ];
-	const struct ip6t_physdev_info *info = matchinfo;
-	unsigned int ret;
-	const char *indev, *outdev;
-	struct nf_bridge_info *nf_bridge;
-
-	/* Not a bridged IP packet or no info available yet:
-	 * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
-	 * the destination device will be a bridge. */
-	if (!(nf_bridge = skb->nf_bridge)) {
-		/* Return MATCH if the invert flags of the used options are on */
-		if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
-		    !(info->invert & IP6T_PHYSDEV_OP_BRIDGED))
-			return NOMATCH;
-		if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN) &&
-		    !(info->invert & IP6T_PHYSDEV_OP_ISIN))
-			return NOMATCH;
-		if ((info->bitmask & IP6T_PHYSDEV_OP_ISOUT) &&
-		    !(info->invert & IP6T_PHYSDEV_OP_ISOUT))
-			return NOMATCH;
-		if ((info->bitmask & IP6T_PHYSDEV_OP_IN) &&
-		    !(info->invert & IP6T_PHYSDEV_OP_IN))
-			return NOMATCH;
-		if ((info->bitmask & IP6T_PHYSDEV_OP_OUT) &&
-		    !(info->invert & IP6T_PHYSDEV_OP_OUT))
-			return NOMATCH;
-		return MATCH;
-	}
-
-	/* This only makes sense in the FORWARD and POSTROUTING chains */
-	if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
-	    (!!(nf_bridge->mask & BRNF_BRIDGED) ^
-	    !(info->invert & IP6T_PHYSDEV_OP_BRIDGED)))
-		return NOMATCH;
-
-	if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN &&
-	    (!nf_bridge->physindev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISIN))) ||
-	    (info->bitmask & IP6T_PHYSDEV_OP_ISOUT &&
-	    (!nf_bridge->physoutdev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISOUT))))
-		return NOMATCH;
-
-	if (!(info->bitmask & IP6T_PHYSDEV_OP_IN))
-		goto match_outdev;
-	indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
-	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-		ret |= (((const unsigned int *)indev)[i]
-			^ ((const unsigned int *)info->physindev)[i])
-			& ((const unsigned int *)info->in_mask)[i];
-	}
-
-	if ((ret == 0) ^ !(info->invert & IP6T_PHYSDEV_OP_IN))
-		return NOMATCH;
-
-match_outdev:
-	if (!(info->bitmask & IP6T_PHYSDEV_OP_OUT))
-		return MATCH;
-	outdev = nf_bridge->physoutdev ?
-		 nf_bridge->physoutdev->name : nulldevname;
-	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-		ret |= (((const unsigned int *)outdev)[i]
-			^ ((const unsigned int *)info->physoutdev)[i])
-			& ((const unsigned int *)info->out_mask)[i];
-	}
-
-	return (ret != 0) ^ !(info->invert & IP6T_PHYSDEV_OP_OUT);
-}
-
-static int
-checkentry(const char *tablename,
-		       const struct ip6t_ip6 *ip,
-		       void *matchinfo,
-		       unsigned int matchsize,
-		       unsigned int hook_mask)
-{
-	const struct ip6t_physdev_info *info = matchinfo;
-
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_physdev_info)))
-		return 0;
-	if (!(info->bitmask & IP6T_PHYSDEV_OP_MASK) ||
-	    info->bitmask & ~IP6T_PHYSDEV_OP_MASK)
-		return 0;
-	return 1;
-}
-
-static struct ip6t_match physdev_match = {
-	.name		= "physdev",
-	.match		= &match,
-	.checkentry	= &checkentry,
-	.me		= THIS_MODULE,
-};
-
-static int __init init(void)
-{
-	return ip6t_register_match(&physdev_match);
-}
-
-static void __exit fini(void)
-{
-	ip6t_unregister_match(&physdev_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index c1e770e..8465b43 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -183,7 +183,7 @@
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 4c00286..ce4a968 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -97,6 +97,7 @@
 	.valid_hooks	= FILTER_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
 	.me		= THIS_MODULE,
+	.af		= AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 85c1e6e..30a4627 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -127,6 +127,7 @@
 	.valid_hooks	= MANGLE_VALID_HOOKS,
 	.lock		= RW_LOCK_UNLOCKED,
 	.me		= THIS_MODULE,
+	.af		= AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index c2982ef..db28ba3 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -106,11 +106,12 @@
 	}
 };
 
-static struct ip6t_table packet_raw = { 
+static struct xt_table packet_raw = { 
 	.name = "raw", 
 	.valid_hooks = RAW_VALID_HOOKS, 
 	.lock = RW_LOCK_UNLOCKED, 
-	.me = THIS_MODULE
+	.me = THIS_MODULE,
+	.af = AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index e57d6fc..ac702a2 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -74,7 +74,7 @@
 static int ipv6_print_tuple(struct seq_file *s,
 			    const struct nf_conntrack_tuple *tuple)
 {
-	return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
+	return seq_printf(s, "src=" NIP6_FMT " dst=" NIP6_FMT " ",
 			  NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
 			  NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
 }
@@ -584,7 +584,7 @@
 
 static int __init init(void)
 {
-	need_nf_conntrack();
+	need_conntrack();
 	return init_or_cleanup(1);
 }
 
@@ -595,9 +595,3 @@
 
 module_init(init);
 module_exit(fini);
-
-void need_ip6_conntrack(void)
-{
-}
-
-EXPORT_SYMBOL(need_ip6_conntrack);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index f3e5ffb..84ef9a1 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -70,8 +70,8 @@
 
 struct nf_ct_frag6_queue
 {
-	struct nf_ct_frag6_queue	*next;
-	struct list_head lru_list;		/* lru list member	*/
+	struct hlist_node	list;
+	struct list_head	lru_list;	/* lru list member	*/
 
 	__u32			id;		/* fragment id		*/
 	struct in6_addr		saddr;
@@ -90,14 +90,13 @@
 #define FIRST_IN		2
 #define LAST_IN			1
 	__u16			nhoffset;
-	struct nf_ct_frag6_queue	**pprev;
 };
 
 /* Hash table. */
 
 #define FRAG6Q_HASHSZ	64
 
-static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ];
+static struct hlist_head nf_ct_frag6_hash[FRAG6Q_HASHSZ];
 static DEFINE_RWLOCK(nf_ct_frag6_lock);
 static u32 nf_ct_frag6_hash_rnd;
 static LIST_HEAD(nf_ct_frag6_lru_list);
@@ -105,9 +104,7 @@
 
 static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
 {
-	if (fq->next)
-		fq->next->pprev = fq->pprev;
-	*fq->pprev = fq->next;
+	hlist_del(&fq->list);
 	list_del(&fq->lru_list);
 	nf_ct_frag6_nqueues--;
 }
@@ -158,28 +155,18 @@
 	get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
 	for (i = 0; i < FRAG6Q_HASHSZ; i++) {
 		struct nf_ct_frag6_queue *q;
+		struct hlist_node *p, *n;
 
-		q = nf_ct_frag6_hash[i];
-		while (q) {
-			struct nf_ct_frag6_queue *next = q->next;
+		hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], list) {
 			unsigned int hval = ip6qhashfn(q->id,
 						       &q->saddr,
 						       &q->daddr);
-
 			if (hval != i) {
-				/* Unlink. */
-				if (q->next)
-					q->next->pprev = q->pprev;
-				*q->pprev = q->next;
-
+				hlist_del(&q->list);
 				/* Relink to new hash chain. */
-				if ((q->next = nf_ct_frag6_hash[hval]) != NULL)
-					q->next->pprev = &q->next;
-				nf_ct_frag6_hash[hval] = q;
-				q->pprev = &nf_ct_frag6_hash[hval];
+				hlist_add_head(&q->list,
+					       &nf_ct_frag6_hash[hval]);
 			}
-
-			q = next;
 		}
 	}
 	write_unlock(&nf_ct_frag6_lock);
@@ -314,15 +301,17 @@
 
 /* Creation primitives. */
 
-
 static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 					  struct nf_ct_frag6_queue *fq_in)
 {
 	struct nf_ct_frag6_queue *fq;
+#ifdef CONFIG_SMP
+	struct hlist_node *n;
+#endif
 
 	write_lock(&nf_ct_frag6_lock);
 #ifdef CONFIG_SMP
-	for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
 		if (fq->id == fq_in->id && 
 		    !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
 		    !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
@@ -340,10 +329,7 @@
 		atomic_inc(&fq->refcnt);
 
 	atomic_inc(&fq->refcnt);
-	if ((fq->next = nf_ct_frag6_hash[hash]) != NULL)
-		fq->next->pprev = &fq->next;
-	nf_ct_frag6_hash[hash] = fq;
-	fq->pprev = &nf_ct_frag6_hash[hash];
+	hlist_add_head(&fq->list, &nf_ct_frag6_hash[hash]);
 	INIT_LIST_HEAD(&fq->lru_list);
 	list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
 	nf_ct_frag6_nqueues++;
@@ -384,10 +370,11 @@
 fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
 {
 	struct nf_ct_frag6_queue *fq;
+	struct hlist_node *n;
 	unsigned int hash = ip6qhashfn(id, src, dst);
 
 	read_lock(&nf_ct_frag6_lock);
-	for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
 		if (fq->id == id && 
 		    !ipv6_addr_cmp(src, &fq->saddr) &&
 		    !ipv6_addr_cmp(dst, &fq->daddr)) {
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index bf0d0ab..a572302 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -15,6 +15,7 @@
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
 #include <net/ipv6.h>
+#include <net/addrconf.h>
 
 static struct xfrm_state_afinfo xfrm6_state_afinfo;
 
@@ -41,6 +42,22 @@
 	memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
 	if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
 		memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
+	if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
+		struct rt6_info *rt;
+		struct flowi fl_tunnel = {
+			.nl_u = {
+				.ip6_u = {
+					.daddr = *(struct in6_addr *)daddr,
+				}
+			}
+		};
+		if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+		                     &fl_tunnel, AF_INET6)) {
+			ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
+			               (struct in6_addr *)&x->props.saddr);
+			dst_release(&rt->u.dst);
+		}
+	}
 	x->props.mode = tmpl->mode;
 	x->props.reqid = tmpl->reqid;
 	x->props.family = AF_INET6;
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index da09ff2..8cfc58b 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -259,8 +259,7 @@
 	spi = 0;
 	goto out;
 alloc_spi:
-	X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for "
-			      "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 
+	X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for " NIP6_FMT "\n",
 			      __FUNCTION__, 
 			      NIP6(*(struct in6_addr *)saddr));
 	x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC);
@@ -323,9 +322,8 @@
 				  list_byaddr)
 	{
 		if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
-			X6TPRINTK3(KERN_DEBUG "%s(): x6spi object "
-					      "for %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-					      "found at %p\n",
+			X6TPRINTK3(KERN_DEBUG "%s(): x6spi object for " NIP6_FMT 
+					      " found at %p\n",
 				   __FUNCTION__, 
 				   NIP6(*(struct in6_addr *)saddr),
 				   x6spi);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 7d55f9c..99c0a0f 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -103,3 +103,261 @@
 	  This option enables support for a netlink-based userspace interface
 
 endmenu
+
+config NETFILTER_XTABLES
+	tristate "Netfilter Xtables support (required for ip_tables)"
+	help
+	  This is required if you intend to use any of ip_tables,
+	  ip6_tables or arp_tables.
+
+# alphabetically ordered list of targets
+
+config NETFILTER_XT_TARGET_CLASSIFY
+	tristate '"CLASSIFY" target support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option adds a `CLASSIFY' target, which enables the user to set
+	  the priority of a packet. Some qdiscs can use this value for
+	  classification, among these are:
+
+  	  atm, cbq, dsmark, pfifo_fast, htb, prio
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_CONNMARK
+	tristate  '"CONNMARK" target support'
+	depends on NETFILTER_XTABLES
+	depends on IP_NF_MANGLE || IP6_NF_MANGLE
+	depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
+	help
+	  This option adds a `CONNMARK' target, which allows one to manipulate
+	  the connection mark value.  Similar to the MARK target, but
+	  affects the connection mark value rather than the packet mark value.
+	
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  The module will be called
+	  ipt_CONNMARK.o.  If unsure, say `N'.
+
+config NETFILTER_XT_TARGET_MARK
+	tristate '"MARK" target support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option adds a `MARK' target, which allows you to create rules
+	  in the `mangle' table which alter the netfilter mark (nfmark) field
+	  associated with the packet prior to routing. This can change
+	  the routing method (see `Use netfilter MARK value as routing
+	  key') and can also be used by other subsystems to change their
+	  behavior.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_NFQUEUE
+	tristate '"NFQUEUE" target Support'
+	depends on NETFILTER_XTABLES
+	help
+	  This Target replaced the old obsolete QUEUE target.
+
+	  As opposed to QUEUE, it supports 65535 different queues,
+	  not just one.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_NOTRACK
+	tristate  '"NOTRACK" target support'
+	depends on NETFILTER_XTABLES
+	depends on IP_NF_RAW || IP6_NF_RAW
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	help
+	  The NOTRACK target allows a select rule to specify
+	  which packets *not* to enter the conntrack/NAT
+	  subsystem with all the consequences (no ICMP error tracking,
+	  no protocol helpers for the selected packets).
+	
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_COMMENT
+	tristate  '"comment" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option adds a `comment' dummy-match, which allows you to put
+	  comments in your iptables ruleset.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_CONNBYTES
+	tristate  '"connbytes" per-connection counter match support'
+	depends on NETFILTER_XTABLES
+	depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || NF_CT_ACCT
+	help
+	  This option adds a `connbytes' match, which allows you to match the
+	  number of bytes and/or packets for each direction within a connection.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_CONNMARK
+	tristate  '"connmark" connection mark match support'
+	depends on NETFILTER_XTABLES
+	depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || NF_CONNTRACK_MARK
+	help
+	  This option adds a `connmark' match, which allows you to match the
+	  connection mark value previously set for the session by `CONNMARK'. 
+	
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  The module will be called
+	  ipt_connmark.o.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_CONNTRACK
+	tristate '"conntrack" connection tracking match support'
+	depends on NETFILTER_XTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	help
+	  This is a general conntrack match module, a superset of the state match.
+
+	  It allows matching on additional conntrack information, which is
+	  useful in complex configurations, such as NAT gateways with multiple
+	  internet links or tunnels.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_DCCP
+	tristate  '"DCCP" protocol match support'
+	depends on NETFILTER_XTABLES
+	help
+	  With this option enabled, you will be able to use the iptables
+	  `dccp' match in order to match on DCCP source/destination ports
+	  and DCCP flags.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_HELPER
+	tristate '"helper" match support'
+	depends on NETFILTER_XTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	help
+	  Helper matching allows you to match packets in dynamic connections
+	  tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+	  To compile it as a module, choose M here.  If unsure, say Y.
+
+config NETFILTER_XT_MATCH_LENGTH
+	tristate '"length" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option allows you to match the length of a packet against a
+	  specific value or range of values.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_LIMIT
+	tristate '"limit" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  limit matching allows you to control the rate at which a rule can be
+	  matched: mainly useful in combination with the LOG target ("LOG
+	  target support", below) and to avoid some Denial of Service attacks.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_MAC
+	tristate '"mac" address match support'
+	depends on NETFILTER_XTABLES
+	help
+	  MAC matching allows you to match packets based on the source
+	  Ethernet address of the packet.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_MARK
+	tristate '"mark" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  Netfilter mark matching allows you to match packets based on the
+	  `nfmark' value in the packet.  This can be set by the MARK target
+	  (see below).
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_PHYSDEV
+	tristate '"physdev" match support'
+	depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
+	help
+	  Physdev packet matching matches against the physical bridge ports
+	  the IP packet arrived on or will leave by.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_PKTTYPE
+	tristate '"pkttype" packet type match support'
+	depends on NETFILTER_XTABLES
+	help
+	  Packet type matching allows you to match a packet by
+	  its "class", eg. BROADCAST, MULTICAST, ...
+
+	  Typical usage:
+	  iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_REALM
+	tristate  '"realm" match support'
+	depends on NETFILTER_XTABLES
+	select NET_CLS_ROUTE
+	help
+	  This option adds a `realm' match, which allows you to use the realm
+	  key from the routing subsystem inside iptables.
+	
+	  This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option 
+	  in tc world.
+	
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_SCTP
+	tristate  '"sctp" protocol match support'
+	depends on NETFILTER_XTABLES
+	help
+	  With this option enabled, you will be able to use the 
+	  `sctp' match in order to match on SCTP source/destination ports
+	  and SCTP chunk types.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config NETFILTER_XT_MATCH_STATE
+	tristate '"state" match support'
+	depends on NETFILTER_XTABLES
+	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	help
+	  Connection state matching allows you to match packets based on their
+	  relationship to a tracked connection (ie. previous packets).  This
+	  is a powerful tool for packet classification.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_STRING
+	tristate  '"string" match support'
+	depends on NETFILTER_XTABLES
+	select TEXTSEARCH
+	select TEXTSEARCH_KMP
+	select TEXTSEARCH_BM
+	select TEXTSEARCH_FSM
+	help
+	  This option adds a `string' match, which allows you to look for
+	  pattern matchings in packets.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_TCPMSS
+	tristate '"tcpmss" match support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option adds a `tcpmss' match, which allows you to examine the
+	  MSS value of TCP SYN packets, which control the maximum packet size
+	  for that connection.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index cb21831..746172e 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -1,4 +1,5 @@
 netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
+nf_conntrack-objs	:= nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
 
 obj-$(CONFIG_NETFILTER) = netfilter.o
 
@@ -6,13 +7,43 @@
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 
-nf_conntrack-objs	:= nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
-
+# connection tracking
 obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
-obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
 
 # SCTP protocol connection tracking
 obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
 
 # netlink interface for nf_conntrack
 obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
+
+# connection tracking helpers
+obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
+
+# generic X tables 
+obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+
+# targets
+obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
+
+# matches
+obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index d5a6eaf..ab0c920 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -545,11 +545,11 @@
                    different IP address.  Simply don't record it for
                    NAT. */
 		if (cmd.l3num == PF_INET) {
-                	DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
+                	DEBUGP("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT " != " NIPQUAD_FMT "\n",
 			       NIPQUAD(cmd.u3.ip),
 			       NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
 		} else {
-			DEBUGP("conntrack_ftp: NOT RECORDING: %x:%x:%x:%x:%x:%x:%x:%x != %x:%x:%x:%x:%x:%x:%x:%x\n",
+			DEBUGP("conntrack_ftp: NOT RECORDING: " NIP6_FMT " != " NIP6_FMT "\n",
 			       NIP6(*((struct in6_addr *)cmd.u3.ip6)),
 			       NIP6(*((struct in6_addr *)ct->tuplehash[dir]
 							.tuple.src.u3.ip6)));
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 3531d14..617599a 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -821,7 +821,7 @@
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
-void need_nf_conntrack(void)
+void need_conntrack(void)
 {
 }
 
@@ -841,7 +841,7 @@
 EXPORT_SYMBOL(nf_ct_invert_tuplepr);
 EXPORT_SYMBOL(nf_conntrack_alter_reply);
 EXPORT_SYMBOL(nf_conntrack_destroyed);
-EXPORT_SYMBOL(need_nf_conntrack);
+EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(nf_conntrack_helper_register);
 EXPORT_SYMBOL(nf_conntrack_helper_unregister);
 EXPORT_SYMBOL(nf_ct_iterate_cleanup);
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 95fdf04..f6063e8 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -212,7 +212,7 @@
 }
 
 /* Process one complete nfnetlink message. */
-static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
+static int nfnetlink_rcv_msg(struct sk_buff *skb,
 				    struct nlmsghdr *nlh, int *errp)
 {
 	struct nfnl_callback *nc;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
new file mode 100644
index 0000000..d7817af
--- /dev/null
+++ b/net/netfilter/x_tables.c
@@ -0,0 +1,624 @@
+/*
+ * x_tables core - Backend for {ip,ip6,arp}_tables
+ *
+ * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
+ *
+ * Based on existing ip_tables code which is
+ *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * 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/socket.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_arp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
+
+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
+
+struct xt_af {
+	struct semaphore mutex;
+	struct list_head match;
+	struct list_head target;
+	struct list_head tables;
+};
+
+static struct xt_af *xt;
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+enum {
+	TABLE,
+	TARGET,
+	MATCH,
+};
+
+/* Registration hooks for targets. */
+int
+xt_register_target(int af, struct xt_target *target)
+{
+	int ret;
+
+	ret = down_interruptible(&xt[af].mutex);
+	if (ret != 0)
+		return ret;
+	list_add(&target->list, &xt[af].target);
+	up(&xt[af].mutex);
+	return ret;
+}
+EXPORT_SYMBOL(xt_register_target);
+
+void
+xt_unregister_target(int af, struct xt_target *target)
+{
+	down(&xt[af].mutex);
+	LIST_DELETE(&xt[af].target, target);
+	up(&xt[af].mutex);
+}
+EXPORT_SYMBOL(xt_unregister_target);
+
+int
+xt_register_match(int af, struct xt_match *match)
+{
+	int ret;
+
+	ret = down_interruptible(&xt[af].mutex);
+	if (ret != 0)
+		return ret;
+
+	list_add(&match->list, &xt[af].match);
+	up(&xt[af].mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(xt_register_match);
+
+void
+xt_unregister_match(int af, struct xt_match *match)
+{
+	down(&xt[af].mutex);
+	LIST_DELETE(&xt[af].match, match);
+	up(&xt[af].mutex);
+}
+EXPORT_SYMBOL(xt_unregister_match);
+
+
+/*
+ * These are weird, but module loading must not be done with mutex
+ * held (since they will register), and we have to have a single
+ * function to use try_then_request_module().
+ */
+
+/* Find match, grabs ref.  Returns ERR_PTR() on error. */
+struct xt_match *xt_find_match(int af, const char *name, u8 revision)
+{
+	struct xt_match *m;
+	int err = 0;
+
+	if (down_interruptible(&xt[af].mutex) != 0)
+		return ERR_PTR(-EINTR);
+
+	list_for_each_entry(m, &xt[af].match, list) {
+		if (strcmp(m->name, name) == 0) {
+			if (m->revision == revision) {
+				if (try_module_get(m->me)) {
+					up(&xt[af].mutex);
+					return m;
+				}
+			} else
+				err = -EPROTOTYPE; /* Found something. */
+		}
+	}
+	up(&xt[af].mutex);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL(xt_find_match);
+
+/* Find target, grabs ref.  Returns ERR_PTR() on error. */
+struct xt_target *xt_find_target(int af, const char *name, u8 revision)
+{
+	struct xt_target *t;
+	int err = 0;
+
+	if (down_interruptible(&xt[af].mutex) != 0)
+		return ERR_PTR(-EINTR);
+
+	list_for_each_entry(t, &xt[af].target, list) {
+		if (strcmp(t->name, name) == 0) {
+			if (t->revision == revision) {
+				if (try_module_get(t->me)) {
+					up(&xt[af].mutex);
+					return t;
+				}
+			} else
+				err = -EPROTOTYPE; /* Found something. */
+		}
+	}
+	up(&xt[af].mutex);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL(xt_find_target);
+
+static const char *xt_prefix[NPROTO] = {
+	[AF_INET] 	= "ipt_%s",
+	[AF_INET6] 	= "ip6t_%s",
+	[NF_ARP]	= "arpt_%s",
+};
+
+struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
+{
+	struct xt_target *target;
+
+	target = try_then_request_module(xt_find_target(af, name, revision),
+					 xt_prefix[af], name);
+	if (IS_ERR(target) || !target)
+		return NULL;
+	return target;
+}
+EXPORT_SYMBOL_GPL(xt_request_find_target);
+
+static int match_revfn(int af, const char *name, u8 revision, int *bestp)
+{
+	struct xt_match *m;
+	int have_rev = 0;
+
+	list_for_each_entry(m, &xt[af].match, list) {
+		if (strcmp(m->name, name) == 0) {
+			if (m->revision > *bestp)
+				*bestp = m->revision;
+			if (m->revision == revision)
+				have_rev = 1;
+		}
+	}
+	return have_rev;
+}
+
+static int target_revfn(int af, const char *name, u8 revision, int *bestp)
+{
+	struct xt_target *t;
+	int have_rev = 0;
+
+	list_for_each_entry(t, &xt[af].target, list) {
+		if (strcmp(t->name, name) == 0) {
+			if (t->revision > *bestp)
+				*bestp = t->revision;
+			if (t->revision == revision)
+				have_rev = 1;
+		}
+	}
+	return have_rev;
+}
+
+/* Returns true or false (if no such extension at all) */
+int xt_find_revision(int af, const char *name, u8 revision, int target,
+		     int *err)
+{
+	int have_rev, best = -1;
+
+	if (down_interruptible(&xt[af].mutex) != 0) {
+		*err = -EINTR;
+		return 1;
+	}
+	if (target == 1)
+		have_rev = target_revfn(af, name, revision, &best);
+	else
+		have_rev = match_revfn(af, name, revision, &best);
+	up(&xt[af].mutex);
+
+	/* Nothing at all?  Return 0 to try loading module. */
+	if (best == -1) {
+		*err = -ENOENT;
+		return 0;
+	}
+
+	*err = best;
+	if (!have_rev)
+		*err = -EPROTONOSUPPORT;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(xt_find_revision);
+
+struct xt_table_info *xt_alloc_table_info(unsigned int size)
+{
+	struct xt_table_info *newinfo;
+	int cpu;
+
+	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
+	if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
+		return NULL;
+
+	newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
+	if (!newinfo)
+		return NULL;
+
+	newinfo->size = size;
+
+	for_each_cpu(cpu) {
+		if (size <= PAGE_SIZE)
+			newinfo->entries[cpu] = kmalloc_node(size,
+							GFP_KERNEL,
+							cpu_to_node(cpu));
+		else
+			newinfo->entries[cpu] = vmalloc_node(size,
+							cpu_to_node(cpu));
+
+		if (newinfo->entries[cpu] == NULL) {
+			xt_free_table_info(newinfo);
+			return NULL;
+		}
+	}
+
+	return newinfo;
+}
+EXPORT_SYMBOL(xt_alloc_table_info);
+
+void xt_free_table_info(struct xt_table_info *info)
+{
+	int cpu;
+
+	for_each_cpu(cpu) {
+		if (info->size <= PAGE_SIZE)
+			kfree(info->entries[cpu]);
+		else
+			vfree(info->entries[cpu]);
+	}
+	kfree(info);
+}
+EXPORT_SYMBOL(xt_free_table_info);
+
+/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
+struct xt_table *xt_find_table_lock(int af, const char *name)
+{
+	struct xt_table *t;
+
+	if (down_interruptible(&xt[af].mutex) != 0)
+		return ERR_PTR(-EINTR);
+
+	list_for_each_entry(t, &xt[af].tables, list)
+		if (strcmp(t->name, name) == 0 && try_module_get(t->me))
+			return t;
+	up(&xt[af].mutex);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(xt_find_table_lock);
+
+void xt_table_unlock(struct xt_table *table)
+{
+	up(&xt[table->af].mutex);
+}
+EXPORT_SYMBOL_GPL(xt_table_unlock);
+
+
+struct xt_table_info *
+xt_replace_table(struct xt_table *table,
+	      unsigned int num_counters,
+	      struct xt_table_info *newinfo,
+	      int *error)
+{
+	struct xt_table_info *oldinfo, *private;
+
+	/* Do the substitution. */
+	write_lock_bh(&table->lock);
+	private = table->private;
+	/* Check inside lock: is the old number correct? */
+	if (num_counters != private->number) {
+		duprintf("num_counters != table->private->number (%u/%u)\n",
+			 num_counters, private->number);
+		write_unlock_bh(&table->lock);
+		*error = -EAGAIN;
+		return NULL;
+	}
+	oldinfo = private;
+	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
+	write_unlock_bh(&table->lock);
+
+	return oldinfo;
+}
+EXPORT_SYMBOL_GPL(xt_replace_table);
+
+int xt_register_table(struct xt_table *table,
+		      struct xt_table_info *bootstrap,
+		      struct xt_table_info *newinfo)
+{
+	int ret;
+	struct xt_table_info *private;
+
+	ret = down_interruptible(&xt[table->af].mutex);
+	if (ret != 0)
+		return ret;
+
+	/* Don't autoload: we'd eat our tail... */
+	if (list_named_find(&xt[table->af].tables, table->name)) {
+		ret = -EEXIST;
+		goto unlock;
+	}
+
+	/* Simplifies replace_table code. */
+	table->private = bootstrap;
+	if (!xt_replace_table(table, 0, newinfo, &ret))
+		goto unlock;
+
+	private = table->private;
+	duprintf("table->private->number = %u\n", private->number);
+
+	/* save number of initial entries */
+	private->initial_entries = private->number;
+
+	rwlock_init(&table->lock);
+	list_prepend(&xt[table->af].tables, table);
+
+	ret = 0;
+ unlock:
+	up(&xt[table->af].mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xt_register_table);
+
+void *xt_unregister_table(struct xt_table *table)
+{
+	struct xt_table_info *private;
+
+	down(&xt[table->af].mutex);
+	private = table->private;
+	LIST_DELETE(&xt[table->af].tables, table);
+	up(&xt[table->af].mutex);
+
+	return private;
+}
+EXPORT_SYMBOL_GPL(xt_unregister_table);
+
+#ifdef CONFIG_PROC_FS
+static char *xt_proto_prefix[NPROTO] = {
+	[AF_INET]	= "ip",
+	[AF_INET6]	= "ip6",
+	[NF_ARP]	= "arp",
+};
+
+static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
+{
+	struct list_head *head = list->next;
+
+	if (!head || list_empty(list))
+		return NULL;
+
+	while (pos && (head = head->next)) {
+		if (head == list)
+			return NULL;
+		pos--;
+	}
+	return pos ? NULL : head;
+}
+
+static struct list_head *type2list(u_int16_t af, u_int16_t type)
+{
+	struct list_head *list;
+
+	switch (type) {
+	case TARGET:
+		list = &xt[af].target;
+		break;
+	case MATCH:
+		list = &xt[af].match;
+		break;
+	case TABLE:
+		list = &xt[af].tables;
+		break;
+	default:
+		list = NULL;
+		break;
+	}
+
+	return list;
+}
+
+static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
+	u_int16_t af = (unsigned long)pde->data & 0xffff;
+	u_int16_t type = (unsigned long)pde->data >> 16;
+	struct list_head *list;
+
+	if (af >= NPROTO)
+		return NULL;
+
+	list = type2list(af, type);
+	if (!list)
+		return NULL;
+
+	if (down_interruptible(&xt[af].mutex) != 0)
+		return NULL;
+	
+	return xt_get_idx(list, seq, *pos);
+}
+
+static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct proc_dir_entry *pde = seq->private;
+	u_int16_t af = (unsigned long)pde->data & 0xffff;
+	u_int16_t type = (unsigned long)pde->data >> 16;
+	struct list_head *list;
+
+	if (af >= NPROTO)
+		return NULL;
+	
+	list = type2list(af, type);
+	if (!list)
+		return NULL;
+
+	(*pos)++;
+	return xt_get_idx(list, seq, *pos);
+}
+
+static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
+{
+	struct proc_dir_entry *pde = seq->private;
+	u_int16_t af = (unsigned long)pde->data & 0xffff;
+
+	up(&xt[af].mutex);
+}
+
+static int xt_name_seq_show(struct seq_file *seq, void *v)
+{
+	char *name = (char *)v + sizeof(struct list_head);
+
+	if (strlen(name))
+		return seq_printf(seq, "%s\n", name);
+	else
+		return 0;
+}
+
+static struct seq_operations xt_tgt_seq_ops = {
+	.start	= xt_tgt_seq_start,
+	.next	= xt_tgt_seq_next,
+	.stop	= xt_tgt_seq_stop,
+	.show	= xt_name_seq_show,
+};
+
+static int xt_tgt_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	ret = seq_open(file, &xt_tgt_seq_ops);
+	if (!ret) {
+		struct seq_file *seq = file->private_data;
+		struct proc_dir_entry *pde = PDE(inode);
+
+		seq->private = pde;
+	}
+
+	return ret;
+}
+
+static struct file_operations xt_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = xt_tgt_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+};
+
+#define FORMAT_TABLES	"_tables_names"
+#define	FORMAT_MATCHES	"_tables_matches"
+#define FORMAT_TARGETS 	"_tables_targets"
+
+#endif /* CONFIG_PROC_FS */
+
+int xt_proto_init(int af)
+{
+#ifdef CONFIG_PROC_FS
+	char buf[XT_FUNCTION_MAXNAMELEN];
+	struct proc_dir_entry *proc;
+#endif
+
+	if (af >= NPROTO)
+		return -EINVAL;
+
+
+#ifdef CONFIG_PROC_FS
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+	if (!proc)
+		goto out;
+	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
+
+
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+	if (!proc)
+		goto out_remove_tables;
+	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
+
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+	if (!proc)
+		goto out_remove_matches;
+	proc->data = (void *) ((unsigned long) af | (TARGET << 16));
+#endif
+
+	return 0;
+
+#ifdef CONFIG_PROC_FS
+out_remove_matches:
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+	proc_net_remove(buf);
+
+out_remove_tables:
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+	proc_net_remove(buf);
+out:
+	return -1;
+#endif
+}
+EXPORT_SYMBOL_GPL(xt_proto_init);
+
+void xt_proto_fini(int af)
+{
+#ifdef CONFIG_PROC_FS
+	char buf[XT_FUNCTION_MAXNAMELEN];
+
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_TABLES, sizeof(buf));
+	proc_net_remove(buf);
+
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+	proc_net_remove(buf);
+
+	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+	proc_net_remove(buf);
+#endif /*CONFIG_PROC_FS*/
+}
+EXPORT_SYMBOL_GPL(xt_proto_fini);
+
+
+static int __init xt_init(void)
+{
+	int i;
+
+	xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
+	if (!xt)
+		return -ENOMEM;
+
+	for (i = 0; i < NPROTO; i++) {
+		init_MUTEX(&xt[i].mutex);
+		INIT_LIST_HEAD(&xt[i].target);
+		INIT_LIST_HEAD(&xt[i].match);
+		INIT_LIST_HEAD(&xt[i].tables);
+	}
+	return 0;
+}
+
+static void __exit xt_fini(void)
+{
+	kfree(xt);
+}
+
+module_init(xt_init);
+module_exit(xt_fini);
+
diff --git a/net/ipv4/netfilter/ipt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
similarity index 66%
rename from net/ipv4/netfilter/ipt_CLASSIFY.c
rename to net/netfilter/xt_CLASSIFY.c
index dab78d8..78ee266 100644
--- a/net/ipv4/netfilter/ipt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -15,12 +15,13 @@
 #include <linux/ip.h>
 #include <net/checksum.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_CLASSIFY.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CLASSIFY.h>
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("iptables qdisc classification target module");
+MODULE_ALIAS("ipt_CLASSIFY");
 
 static unsigned int
 target(struct sk_buff **pskb,
@@ -30,25 +31,25 @@
        const void *targinfo,
        void *userinfo)
 {
-	const struct ipt_classify_target_info *clinfo = targinfo;
+	const struct xt_classify_target_info *clinfo = targinfo;
 
-	if((*pskb)->priority != clinfo->priority) 
+	if ((*pskb)->priority != clinfo->priority)
 		(*pskb)->priority = clinfo->priority;
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_entry *e,
+           const void *e,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_classify_target_info))){
+	if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){
 		printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
 		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_classify_target_info)));
+		       XT_ALIGN(sizeof(struct xt_classify_target_info)));
 		return 0;
 	}
 	
@@ -69,21 +70,39 @@
 	return 1;
 }
 
-static struct ipt_target ipt_classify_reg = { 
+static struct xt_target classify_reg = { 
+	.name 		= "CLASSIFY", 
+	.target 	= target,
+	.checkentry	= checkentry,
+	.me 		= THIS_MODULE,
+};
+static struct xt_target classify6_reg = { 
 	.name 		= "CLASSIFY", 
 	.target 	= target,
 	.checkentry	= checkentry,
 	.me 		= THIS_MODULE,
 };
 
+
 static int __init init(void)
 {
-	return ipt_register_target(&ipt_classify_reg);
+	int ret;
+
+	ret = xt_register_target(AF_INET, &classify_reg);
+	if (ret)
+		return ret;
+
+	ret = xt_register_target(AF_INET6, &classify6_reg);
+	if (ret)
+		xt_unregister_target(AF_INET, &classify_reg);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_target(&ipt_classify_reg);
+	xt_unregister_target(AF_INET, &classify_reg);
+	xt_unregister_target(AF_INET6, &classify6_reg);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
similarity index 73%
rename from net/ipv4/netfilter/ipt_CONNMARK.c
rename to net/netfilter/xt_CONNMARK.c
index 8acac5a..22506e3 100644
--- a/net/ipv4/netfilter/ipt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -26,9 +26,10 @@
 MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
 MODULE_DESCRIPTION("IP tables CONNMARK matching module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_CONNMARK");
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CONNMARK.h>
 #include <net/netfilter/nf_conntrack_compat.h>
 
 static unsigned int
@@ -39,7 +40,7 @@
        const void *targinfo,
        void *userinfo)
 {
-	const struct ipt_connmark_target_info *markinfo = targinfo;
+	const struct xt_connmark_target_info *markinfo = targinfo;
 	u_int32_t diff;
 	u_int32_t nfmark;
 	u_int32_t newmark;
@@ -48,17 +49,17 @@
 
 	if (ctmark) {
 	    switch(markinfo->mode) {
-	    case IPT_CONNMARK_SET:
+	    case XT_CONNMARK_SET:
 		newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
 		if (newmark != *ctmark)
 		    *ctmark = newmark;
 		break;
-	    case IPT_CONNMARK_SAVE:
+	    case XT_CONNMARK_SAVE:
 		newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
 		if (*ctmark != newmark)
 		    *ctmark = newmark;
 		break;
-	    case IPT_CONNMARK_RESTORE:
+	    case XT_CONNMARK_RESTORE:
 		nfmark = (*pskb)->nfmark;
 		diff = (*ctmark ^ nfmark) & markinfo->mask;
 		if (diff != 0)
@@ -67,25 +68,25 @@
 	    }
 	}
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *entry,
 	   void *targinfo,
 	   unsigned int targinfosize,
 	   unsigned int hook_mask)
 {
-	struct ipt_connmark_target_info *matchinfo = targinfo;
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
+	struct xt_connmark_target_info *matchinfo = targinfo;
+	if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) {
 		printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
 		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
+		       XT_ALIGN(sizeof(struct xt_connmark_target_info)));
 		return 0;
 	}
 
-	if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
+	if (matchinfo->mode == XT_CONNMARK_RESTORE) {
 	    if (strcmp(tablename, "mangle") != 0) {
 		    printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
 		    return 0;
@@ -100,7 +101,13 @@
 	return 1;
 }
 
-static struct ipt_target ipt_connmark_reg = {
+static struct xt_target connmark_reg = {
+	.name = "CONNMARK",
+	.target = &target,
+	.checkentry = &checkentry,
+	.me = THIS_MODULE
+};
+static struct xt_target connmark6_reg = {
 	.name = "CONNMARK",
 	.target = &target,
 	.checkentry = &checkentry,
@@ -109,13 +116,25 @@
 
 static int __init init(void)
 {
-	need_ip_conntrack();
-	return ipt_register_target(&ipt_connmark_reg);
+	int ret;
+
+	need_conntrack();
+
+	ret = xt_register_target(AF_INET, &connmark_reg);
+	if (ret)
+		return ret;
+
+	ret = xt_register_target(AF_INET6, &connmark6_reg);
+	if (ret)
+		xt_unregister_target(AF_INET, &connmark_reg);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_target(&ipt_connmark_reg);
+	xt_unregister_target(AF_INET, &connmark_reg);
+	xt_unregister_target(AF_INET6, &connmark6_reg);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_MARK.c b/net/netfilter/xt_MARK.c
similarity index 61%
rename from net/ipv4/netfilter/ipt_MARK.c
rename to net/netfilter/xt_MARK.c
index 52b4f2c..0c11ee9 100644
--- a/net/ipv4/netfilter/ipt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -12,12 +12,14 @@
 #include <linux/ip.h>
 #include <net/checksum.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_MARK.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_MARK.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables MARK modification module");
+MODULE_DESCRIPTION("ip[6]tables MARK modification module");
+MODULE_ALIAS("ipt_MARK");
+MODULE_ALIAS("ip6t_MARK");
 
 static unsigned int
 target_v0(struct sk_buff **pskb,
@@ -27,12 +29,12 @@
 	  const void *targinfo,
 	  void *userinfo)
 {
-	const struct ipt_mark_target_info *markinfo = targinfo;
+	const struct xt_mark_target_info *markinfo = targinfo;
 
 	if((*pskb)->nfmark != markinfo->mark)
 		(*pskb)->nfmark = markinfo->mark;
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static unsigned int
@@ -43,19 +45,19 @@
 	  const void *targinfo,
 	  void *userinfo)
 {
-	const struct ipt_mark_target_info_v1 *markinfo = targinfo;
+	const struct xt_mark_target_info_v1 *markinfo = targinfo;
 	int mark = 0;
 
 	switch (markinfo->mode) {
-	case IPT_MARK_SET:
+	case XT_MARK_SET:
 		mark = markinfo->mark;
 		break;
 		
-	case IPT_MARK_AND:
+	case XT_MARK_AND:
 		mark = (*pskb)->nfmark & markinfo->mark;
 		break;
 		
-	case IPT_MARK_OR:
+	case XT_MARK_OR:
 		mark = (*pskb)->nfmark | markinfo->mark;
 		break;
 	}
@@ -63,23 +65,23 @@
 	if((*pskb)->nfmark != mark)
 		(*pskb)->nfmark = mark;
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 
 static int
 checkentry_v0(const char *tablename,
-	      const struct ipt_entry *e,
+	      const void *entry,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
 {
-	struct ipt_mark_target_info *markinfo = targinfo;
+	struct xt_mark_target_info *markinfo = targinfo;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info))) {
+	if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
 		printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
 		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_mark_target_info)));
+		       XT_ALIGN(sizeof(struct xt_mark_target_info)));
 		return 0;
 	}
 
@@ -98,17 +100,17 @@
 
 static int
 checkentry_v1(const char *tablename,
-	      const struct ipt_entry *e,
+	      const void *entry,
 	      void *targinfo,
 	      unsigned int targinfosize,
 	      unsigned int hook_mask)
 {
-	struct ipt_mark_target_info_v1 *markinfo = targinfo;
+	struct xt_mark_target_info_v1 *markinfo = targinfo;
 
-	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1))){
+	if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
 		printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
 		       targinfosize,
-		       IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)));
+		       XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
 		return 0;
 	}
 
@@ -117,9 +119,9 @@
 		return 0;
 	}
 
-	if (markinfo->mode != IPT_MARK_SET
-	    && markinfo->mode != IPT_MARK_AND
-	    && markinfo->mode != IPT_MARK_OR) {
+	if (markinfo->mode != XT_MARK_SET
+	    && markinfo->mode != XT_MARK_AND
+	    && markinfo->mode != XT_MARK_OR) {
 		printk(KERN_WARNING "MARK: unknown mode %u\n",
 		       markinfo->mode);
 		return 0;
@@ -133,7 +135,7 @@
 	return 1;
 }
 
-static struct ipt_target ipt_mark_reg_v0 = {
+static struct xt_target ipt_mark_reg_v0 = {
 	.name		= "MARK",
 	.target		= target_v0,
 	.checkentry	= checkentry_v0,
@@ -141,7 +143,7 @@
 	.revision	= 0,
 };
 
-static struct ipt_target ipt_mark_reg_v1 = {
+static struct xt_target ipt_mark_reg_v1 = {
 	.name		= "MARK",
 	.target		= target_v1,
 	.checkentry	= checkentry_v1,
@@ -149,23 +151,40 @@
 	.revision	= 1,
 };
 
+static struct xt_target ip6t_mark_reg_v0 = {
+	.name		= "MARK",
+	.target		= target_v0,
+	.checkentry	= checkentry_v0,
+	.me		= THIS_MODULE,
+	.revision	= 0,
+};
+
 static int __init init(void)
 {
 	int err;
 
-	err = ipt_register_target(&ipt_mark_reg_v0);
-	if (!err) {
-		err = ipt_register_target(&ipt_mark_reg_v1);
-		if (err)
-			ipt_unregister_target(&ipt_mark_reg_v0);
+	err = xt_register_target(AF_INET, &ipt_mark_reg_v0);
+	if (err)
+		return err;
+
+	err = xt_register_target(AF_INET, &ipt_mark_reg_v1);
+	if (err)
+		xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+
+	err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0);
+	if (err) {
+		xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+		xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
 	}
+
 	return err;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_target(&ipt_mark_reg_v0);
-	ipt_unregister_target(&ipt_mark_reg_v1);
+	xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+	xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
+	xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0);
 }
 
 module_init(init);
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
new file mode 100644
index 0000000..8b76b6f
--- /dev/null
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -0,0 +1,107 @@
+/* iptables module for using new netfilter netlink queue
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as 
+ * published by the Free Software Foundation.
+ * 
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_NFQUEUE.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("[ip,ip6,arp]_tables NFQUEUE target");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_NFQUEUE");
+MODULE_ALIAS("ip6t_NFQUEUE");
+MODULE_ALIAS("arpt_NFQUEUE");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+	const struct xt_NFQ_info *tinfo = targinfo;
+
+	return NF_QUEUE_NR(tinfo->queuenum);
+}
+
+static int
+checkentry(const char *tablename,
+	   const void *entry,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+	if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) {
+		printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
+		       targinfosize,
+		       XT_ALIGN(sizeof(struct xt_NFQ_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct xt_target ipt_NFQ_reg = {
+	.name		= "NFQUEUE",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_target ip6t_NFQ_reg = {
+	.name		= "NFQUEUE",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_target arpt_NFQ_reg = {
+	.name		= "NFQUEUE",
+	.target		= target,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+	ret = xt_register_target(AF_INET, &ipt_NFQ_reg);
+	if (ret)
+		return ret;
+	ret = xt_register_target(AF_INET6, &ip6t_NFQ_reg);
+	if (ret)
+		goto out_ip;
+	ret = xt_register_target(NF_ARP, &arpt_NFQ_reg);
+	if (ret)
+		goto out_ip6;
+
+	return ret;
+out_ip6:
+	xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
+out_ip:
+	xt_unregister_target(AF_INET, &ipt_NFQ_reg);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_target(NF_ARP, &arpt_NFQ_reg);
+	xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
+	xt_unregister_target(AF_INET, &ipt_NFQ_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
similarity index 69%
rename from net/ipv4/netfilter/ipt_NOTRACK.c
rename to net/netfilter/xt_NOTRACK.c
index e3c69d0..24d477a 100644
--- a/net/ipv4/netfilter/ipt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -4,9 +4,12 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/x_tables.h>
 #include <net/netfilter/nf_conntrack_compat.h>
 
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_NOTRACK");
+
 static unsigned int
 target(struct sk_buff **pskb,
        const struct net_device *in,
@@ -17,7 +20,7 @@
 {
 	/* Previously seen (loopback)? Ignore. */
 	if ((*pskb)->nfct != NULL)
-		return IPT_CONTINUE;
+		return XT_CONTINUE;
 
 	/* Attach fake conntrack entry. 
 	   If there is a real ct entry correspondig to this packet, 
@@ -27,12 +30,12 @@
 	(*pskb)->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get((*pskb)->nfct);
 
-	return IPT_CONTINUE;
+	return XT_CONTINUE;
 }
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_entry *e,
+	   const void *entry,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
@@ -51,26 +54,39 @@
 	return 1;
 }
 
-static struct ipt_target ipt_notrack_reg = { 
+static struct xt_target notrack_reg = { 
 	.name = "NOTRACK", 
 	.target = target, 
 	.checkentry = checkentry,
-	.me = THIS_MODULE 
+	.me = THIS_MODULE,
+};
+static struct xt_target notrack6_reg = { 
+	.name = "NOTRACK", 
+	.target = target, 
+	.checkentry = checkentry,
+	.me = THIS_MODULE,
 };
 
 static int __init init(void)
 {
-	if (ipt_register_target(&ipt_notrack_reg))
-		return -EINVAL;
+	int ret;
 
-	return 0;
+	ret = xt_register_target(AF_INET, &notrack_reg);
+	if (ret)
+		return ret;
+
+	ret = xt_register_target(AF_INET6, &notrack6_reg);
+	if (ret)
+		xt_unregister_target(AF_INET, &notrack_reg);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_target(&ipt_notrack_reg);
+	xt_unregister_target(AF_INET6, &notrack6_reg);
+	xt_unregister_target(AF_INET, &notrack_reg);
 }
 
 module_init(init);
 module_exit(fini);
-MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
new file mode 100644
index 0000000..4ba6fd6
--- /dev/null
+++ b/net/netfilter/xt_comment.c
@@ -0,0 +1,80 @@
+/*
+ * Implements a dummy match to allow attaching comments to rules
+ *
+ * 2003-05-13 Brad Fisher (brad@info-link.net)
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_comment.h>
+
+MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
+MODULE_DESCRIPTION("iptables comment match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_comment");
+MODULE_ALIAS("ip6t_comment");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protooff,
+      int *hotdrop)
+{
+	/* We always match */
+	return 1;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	/* Check the size */
+	if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info)))
+		return 0;
+	return 1;
+}
+
+static struct xt_match comment_match = {
+	.name		= "comment",
+	.match		= match,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
+};
+
+static struct xt_match comment6_match = {
+	.name		= "comment",
+	.match		= match,
+	.checkentry	= checkentry,
+	.me		= THIS_MODULE
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	ret = xt_register_match(AF_INET, &comment_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &comment6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &comment_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET, &comment_match);
+	xt_unregister_match(AF_INET6, &comment6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/netfilter/xt_connbytes.c
similarity index 66%
rename from net/ipv4/netfilter/ipt_connbytes.c
rename to net/netfilter/xt_connbytes.c
index d68a048b..150d2a4 100644
--- a/net/ipv4/netfilter/ipt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -6,13 +6,15 @@
  * 	- add functionality to match number of packets
  * 	- add functionality to match average packet size
  * 	- add support to match directions seperately
+ * 2005-10-16 Harald Welte <laforge@netfilter.org>
+ * 	- Port to x_tables
  *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <net/netfilter/nf_conntrack_compat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_connbytes.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connbytes.h>
 
 #include <asm/div64.h>
 #include <asm/bitops.h>
@@ -20,6 +22,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
+MODULE_ALIAS("ipt_connbytes");
 
 /* 64bit divisor, dividend and result. dynamic precision */
 static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
@@ -43,9 +46,10 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_connbytes_info *sinfo = matchinfo;
+	const struct xt_connbytes_info *sinfo = matchinfo;
 	u_int64_t what = 0;	/* initialize to make gcc happy */
 	const struct ip_conntrack_counter *counters;
 
@@ -53,45 +57,45 @@
 		return 0; /* no match */
 
 	switch (sinfo->what) {
-	case IPT_CONNBYTES_PKTS:
+	case XT_CONNBYTES_PKTS:
 		switch (sinfo->direction) {
-		case IPT_CONNBYTES_DIR_ORIGINAL:
+		case XT_CONNBYTES_DIR_ORIGINAL:
 			what = counters[IP_CT_DIR_ORIGINAL].packets;
 			break;
-		case IPT_CONNBYTES_DIR_REPLY:
+		case XT_CONNBYTES_DIR_REPLY:
 			what = counters[IP_CT_DIR_REPLY].packets;
 			break;
-		case IPT_CONNBYTES_DIR_BOTH:
+		case XT_CONNBYTES_DIR_BOTH:
 			what = counters[IP_CT_DIR_ORIGINAL].packets;
 			what += counters[IP_CT_DIR_REPLY].packets;
 			break;
 		}
 		break;
-	case IPT_CONNBYTES_BYTES:
+	case XT_CONNBYTES_BYTES:
 		switch (sinfo->direction) {
-		case IPT_CONNBYTES_DIR_ORIGINAL:
+		case XT_CONNBYTES_DIR_ORIGINAL:
 			what = counters[IP_CT_DIR_ORIGINAL].bytes;
 			break;
-		case IPT_CONNBYTES_DIR_REPLY:
+		case XT_CONNBYTES_DIR_REPLY:
 			what = counters[IP_CT_DIR_REPLY].bytes;
 			break;
-		case IPT_CONNBYTES_DIR_BOTH:
+		case XT_CONNBYTES_DIR_BOTH:
 			what = counters[IP_CT_DIR_ORIGINAL].bytes;
 			what += counters[IP_CT_DIR_REPLY].bytes;
 			break;
 		}
 		break;
-	case IPT_CONNBYTES_AVGPKT:
+	case XT_CONNBYTES_AVGPKT:
 		switch (sinfo->direction) {
-		case IPT_CONNBYTES_DIR_ORIGINAL:
+		case XT_CONNBYTES_DIR_ORIGINAL:
 			what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
 					counters[IP_CT_DIR_ORIGINAL].packets);
 			break;
-		case IPT_CONNBYTES_DIR_REPLY:
+		case XT_CONNBYTES_DIR_REPLY:
 			what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
 					counters[IP_CT_DIR_REPLY].packets);
 			break;
-		case IPT_CONNBYTES_DIR_BOTH:
+		case XT_CONNBYTES_DIR_BOTH:
 			{
 				u_int64_t bytes;
 				u_int64_t pkts;
@@ -117,30 +121,36 @@
 }
 
 static int check(const char *tablename,
-		 const struct ipt_ip *ip,
+		 const void *ip,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
 {
-	const struct ipt_connbytes_info *sinfo = matchinfo;
+	const struct xt_connbytes_info *sinfo = matchinfo;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info)))
 		return 0;
 
-	if (sinfo->what != IPT_CONNBYTES_PKTS &&
-	    sinfo->what != IPT_CONNBYTES_BYTES &&
-	    sinfo->what != IPT_CONNBYTES_AVGPKT)
+	if (sinfo->what != XT_CONNBYTES_PKTS &&
+	    sinfo->what != XT_CONNBYTES_BYTES &&
+	    sinfo->what != XT_CONNBYTES_AVGPKT)
 		return 0;
 
-	if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
-	    sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
-	    sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
+	if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
+	    sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
+	    sinfo->direction != XT_CONNBYTES_DIR_BOTH)
 		return 0;
 
 	return 1;
 }
 
-static struct ipt_match state_match = {
+static struct xt_match connbytes_match = {
+	.name		= "connbytes",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE
+};
+static struct xt_match connbytes6_match = {
 	.name		= "connbytes",
 	.match		= &match,
 	.checkentry	= &check,
@@ -149,12 +159,21 @@
 
 static int __init init(void)
 {
-	return ipt_register_match(&state_match);
+	int ret;
+	ret = xt_register_match(AF_INET, &connbytes_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &connbytes6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &connbytes_match);
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&state_match);
+	xt_unregister_match(AF_INET, &connbytes_match);
+	xt_unregister_match(AF_INET6, &connbytes6_match);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/netfilter/xt_connmark.c
similarity index 70%
rename from net/ipv4/netfilter/ipt_connmark.c
rename to net/netfilter/xt_connmark.c
index 5306ef2..d06e925 100644
--- a/net/ipv4/netfilter/ipt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -25,9 +25,10 @@
 MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
 MODULE_DESCRIPTION("IP tables connmark match module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_connmark");
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_connmark.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connmark.h>
 #include <net/netfilter/nf_conntrack_compat.h>
 
 static int
@@ -36,9 +37,10 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_connmark_info *info = matchinfo;
+	const struct xt_connmark_info *info = matchinfo;
 	u_int32_t ctinfo;
 	const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
 	if (!ctmark)
@@ -49,14 +51,14 @@
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *ip,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	struct ipt_connmark_info *cm = 
-				(struct ipt_connmark_info *)matchinfo;
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
+	struct xt_connmark_info *cm = 
+				(struct xt_connmark_info *)matchinfo;
+	if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info)))
 		return 0;
 
 	if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
@@ -67,21 +69,40 @@
 	return 1;
 }
 
-static struct ipt_match connmark_match = {
+static struct xt_match connmark_match = {
+	.name = "connmark",
+	.match = &match,
+	.checkentry = &checkentry,
+	.me = THIS_MODULE
+};
+static struct xt_match connmark6_match = {
 	.name = "connmark",
 	.match = &match,
 	.checkentry = &checkentry,
 	.me = THIS_MODULE
 };
 
+
 static int __init init(void)
 {
-	return ipt_register_match(&connmark_match);
+	int ret;
+
+	need_conntrack();
+
+	ret = xt_register_match(AF_INET, &connmark_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &connmark6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &connmark_match);
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&connmark_match);
+	xt_unregister_match(AF_INET6, &connmark6_match);
+	xt_unregister_match(AF_INET, &connmark_match);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_conntrack.c b/net/netfilter/xt_conntrack.c
similarity index 63%
rename from net/ipv4/netfilter/ipt_conntrack.c
rename to net/netfilter/xt_conntrack.c
index c8d1870..ffdebc9 100644
--- a/net/ipv4/netfilter/ipt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -18,12 +18,13 @@
 #include <net/netfilter/nf_conntrack.h>
 #endif
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_conntrack.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_conntrack.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables connection tracking match module");
+MODULE_ALIAS("ipt_conntrack");
 
 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
 
@@ -33,9 +34,10 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_conntrack_info *sinfo = matchinfo;
+	const struct xt_conntrack_info *sinfo = matchinfo;
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
@@ -45,58 +47,58 @@
 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
 
 	if (ct == &ip_conntrack_untracked)
-		statebit = IPT_CONNTRACK_STATE_UNTRACKED;
+		statebit = XT_CONNTRACK_STATE_UNTRACKED;
 	else if (ct)
- 		statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
+ 		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  	else
- 		statebit = IPT_CONNTRACK_STATE_INVALID;
+ 		statebit = XT_CONNTRACK_STATE_INVALID;
  
-	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+	if(sinfo->flags & XT_CONNTRACK_STATE) {
 		if (ct) {
 			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
 			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
-				statebit |= IPT_CONNTRACK_STATE_SNAT;
+				statebit |= XT_CONNTRACK_STATE_SNAT;
 
 			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
 			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
-				statebit |= IPT_CONNTRACK_STATE_DNAT;
+				statebit |= XT_CONNTRACK_STATE_DNAT;
 		}
 
-		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+		if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
-		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+	if(sinfo->flags & XT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
                 	return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+	if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+	if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+	if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+	if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
-		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+	if(sinfo->flags & XT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+	if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
 		unsigned long expires;
 
 		if(!ct)
@@ -104,7 +106,7 @@
 
 		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
 
-		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
 			return 0;
 	}
 
@@ -118,9 +120,10 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_conntrack_info *sinfo = matchinfo;
+	const struct xt_conntrack_info *sinfo = matchinfo;
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	unsigned int statebit;
@@ -130,58 +133,58 @@
 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
 
 	if (ct == &nf_conntrack_untracked)
-		statebit = IPT_CONNTRACK_STATE_UNTRACKED;
+		statebit = XT_CONNTRACK_STATE_UNTRACKED;
 	else if (ct)
- 		statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
+ 		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  	else
- 		statebit = IPT_CONNTRACK_STATE_INVALID;
+ 		statebit = XT_CONNTRACK_STATE_INVALID;
  
-	if(sinfo->flags & IPT_CONNTRACK_STATE) {
+	if(sinfo->flags & XT_CONNTRACK_STATE) {
 		if (ct) {
 			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
 			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
-				statebit |= IPT_CONNTRACK_STATE_SNAT;
+				statebit |= XT_CONNTRACK_STATE_SNAT;
 
 			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
 			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
-				statebit |= IPT_CONNTRACK_STATE_DNAT;
+				statebit |= XT_CONNTRACK_STATE_DNAT;
 		}
 
-		if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
+		if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_PROTO) {
-		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
+	if(sinfo->flags & XT_CONNTRACK_PROTO) {
+		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
                 	return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
+	if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
+	if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
+	if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
-		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
+	if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_STATUS) {
-		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
+	if(sinfo->flags & XT_CONNTRACK_STATUS) {
+		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
 			return 0;
 	}
 
-	if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
+	if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
 		unsigned long expires;
 
 		if(!ct)
@@ -189,7 +192,7 @@
 
 		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
 
-		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
+		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
 			return 0;
 	}
 
@@ -199,18 +202,18 @@
 #endif /* CONFIG_NF_IP_CONNTRACK */
 
 static int check(const char *tablename,
-		 const struct ipt_ip *ip,
+		 const void *ip,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
 {
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info)))
 		return 0;
 
 	return 1;
 }
 
-static struct ipt_match conntrack_match = {
+static struct xt_match conntrack_match = {
 	.name		= "conntrack",
 	.match		= &match,
 	.checkentry	= &check,
@@ -219,13 +222,16 @@
 
 static int __init init(void)
 {
-	need_ip_conntrack();
-	return ipt_register_match(&conntrack_match);
+	int ret;
+	need_conntrack();
+	ret = xt_register_match(AF_INET, &conntrack_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&conntrack_match);
+	xt_unregister_match(AF_INET, &conntrack_match);
 }
 
 module_init(init);
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
new file mode 100644
index 0000000..779f42f
--- /dev/null
+++ b/net/netfilter/xt_dccp.c
@@ -0,0 +1,221 @@
+/*
+ * iptables module for DCCP protocol header matching
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <net/ip.h>
+#include <linux/dccp.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_dccp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("Match for DCCP protocol packets");
+MODULE_ALIAS("ipt_dccp");
+
+#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
+		                  || (!!((invflag) & (option)) ^ (cond)))
+
+static unsigned char *dccp_optbuf;
+static DEFINE_SPINLOCK(dccp_buflock);
+
+static inline int
+dccp_find_option(u_int8_t option,
+		 const struct sk_buff *skb,
+		 unsigned int protoff,
+		 const struct dccp_hdr *dh,
+		 int *hotdrop)
+{
+	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+	unsigned char *op;
+	unsigned int optoff = __dccp_hdr_len(dh);
+	unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
+	unsigned int i;
+
+	if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
+		*hotdrop = 1;
+		return 0;
+	}
+
+	if (!optlen)
+		return 0;
+
+	spin_lock_bh(&dccp_buflock);
+	op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
+	if (op == NULL) {
+		/* If we don't have the whole header, drop packet. */
+		spin_unlock_bh(&dccp_buflock);
+		*hotdrop = 1;
+		return 0;
+	}
+
+	for (i = 0; i < optlen; ) {
+		if (op[i] == option) {
+			spin_unlock_bh(&dccp_buflock);
+			return 1;
+		}
+
+		if (op[i] < 2) 
+			i++;
+		else 
+			i += op[i+1]?:1;
+	}
+
+	spin_unlock_bh(&dccp_buflock);
+	return 0;
+}
+
+
+static inline int
+match_types(const struct dccp_hdr *dh, u_int16_t typemask)
+{
+	return (typemask & (1 << dh->dccph_type));
+}
+
+static inline int
+match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
+	     const struct dccp_hdr *dh, int *hotdrop)
+{
+	return dccp_find_option(option, skb, protoff, dh, hotdrop);
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	const struct xt_dccp_info *info = 
+				(const struct xt_dccp_info *)matchinfo;
+	struct dccp_hdr _dh, *dh;
+
+	if (offset)
+		return 0;
+	
+	dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
+	if (dh == NULL) {
+		*hotdrop = 1;
+		return 0;
+       	}
+
+	return  DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) 
+			&& (ntohs(dh->dccph_sport) <= info->spts[1])), 
+		   	XT_DCCP_SRC_PORTS, info->flags, info->invflags)
+		&& DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) 
+			&& (ntohs(dh->dccph_dport) <= info->dpts[1])), 
+			XT_DCCP_DEST_PORTS, info->flags, info->invflags)
+		&& DCCHECK(match_types(dh, info->typemask),
+			   XT_DCCP_TYPE, info->flags, info->invflags)
+		&& DCCHECK(match_option(info->option, skb, protoff, dh,
+					hotdrop),
+			   XT_DCCP_OPTION, info->flags, info->invflags);
+}
+
+static int
+checkentry(const char *tablename,
+	   const void *inf,
+	   void *matchinfo,
+	   unsigned int matchsize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = inf;
+	const struct xt_dccp_info *info;
+
+	info = (const struct xt_dccp_info *)matchinfo;
+
+	return ip->proto == IPPROTO_DCCP
+		&& !(ip->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
+		&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
+		&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
+		&& !(info->invflags & ~info->flags);
+}
+
+static int
+checkentry6(const char *tablename,
+	   const void *inf,
+	   void *matchinfo,
+	   unsigned int matchsize,
+	   unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ip = inf;
+	const struct xt_dccp_info *info;
+
+	info = (const struct xt_dccp_info *)matchinfo;
+
+	return ip->proto == IPPROTO_DCCP
+		&& !(ip->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
+		&& !(info->flags & ~XT_DCCP_VALID_FLAGS)
+		&& !(info->invflags & ~XT_DCCP_VALID_FLAGS)
+		&& !(info->invflags & ~info->flags);
+}
+
+
+static struct xt_match dccp_match = 
+{ 
+	.name 		= "dccp",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me 		= THIS_MODULE,
+};
+static struct xt_match dccp6_match = 
+{ 
+	.name 		= "dccp",
+	.match		= &match,
+	.checkentry	= &checkentry6,
+	.me 		= THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+	int ret;
+
+	/* doff is 8 bits, so the maximum option size is (4*256).  Don't put
+	 * this in BSS since DaveM is worried about locked TLB's for kernel
+	 * BSS. */
+	dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
+	if (!dccp_optbuf)
+		return -ENOMEM;
+	ret = xt_register_match(AF_INET, &dccp_match);
+	if (ret)
+		goto out_kfree;
+	ret = xt_register_match(AF_INET6, &dccp6_match);
+	if (ret)
+		goto out_unreg;
+
+	return ret;
+
+out_unreg:
+	xt_unregister_match(AF_INET, &dccp_match);
+out_kfree:
+	kfree(dccp_optbuf);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET6, &dccp6_match);
+	xt_unregister_match(AF_INET, &dccp_match);
+	kfree(dccp_optbuf);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/netfilter/xt_helper.c
similarity index 72%
rename from net/ipv4/netfilter/ipt_helper.c
rename to net/netfilter/xt_helper.c
index aef649e..38b6715 100644
--- a/net/ipv4/netfilter/ipt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
-#include <linux/interrupt.h>
 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
@@ -23,12 +22,14 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #endif
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_helper.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_helper.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
 MODULE_DESCRIPTION("iptables helper match module");
+MODULE_ALIAS("ipt_helper");
+MODULE_ALIAS("ip6t_helper");
 
 #if 0
 #define DEBUGP printk
@@ -43,27 +44,28 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_helper_info *info = matchinfo;
+	const struct xt_helper_info *info = matchinfo;
 	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
 	int ret = info->invert;
 	
 	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
 	if (!ct) {
-		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		DEBUGP("xt_helper: Eek! invalid conntrack?\n");
 		return ret;
 	}
 
 	if (!ct->master) {
-		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		DEBUGP("xt_helper: conntrack %p has no master\n", ct);
 		return ret;
 	}
 
 	read_lock_bh(&ip_conntrack_lock);
 	if (!ct->master->helper) {
-		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+		DEBUGP("xt_helper: master ct %p has no helper\n", 
 			exp->expectant);
 		goto out_unlock;
 	}
@@ -89,27 +91,28 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_helper_info *info = matchinfo;
+	const struct xt_helper_info *info = matchinfo;
 	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	int ret = info->invert;
 	
 	ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
 	if (!ct) {
-		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+		DEBUGP("xt_helper: Eek! invalid conntrack?\n");
 		return ret;
 	}
 
 	if (!ct->master) {
-		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+		DEBUGP("xt_helper: conntrack %p has no master\n", ct);
 		return ret;
 	}
 
 	read_lock_bh(&nf_conntrack_lock);
 	if (!ct->master->helper) {
-		DEBUGP("ipt_helper: master ct %p has no helper\n", 
+		DEBUGP("xt_helper: master ct %p has no helper\n", 
 			exp->expectant);
 		goto out_unlock;
 	}
@@ -129,23 +132,29 @@
 #endif
 
 static int check(const char *tablename,
-		 const struct ipt_ip *ip,
+		 const void *inf,
 		 void *matchinfo,
 		 unsigned int matchsize,
 		 unsigned int hook_mask)
 {
-	struct ipt_helper_info *info = matchinfo;
+	struct xt_helper_info *info = matchinfo;
 
 	info->name[29] = '\0';
 
 	/* verify size */
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
 		return 0;
 
 	return 1;
 }
 
-static struct ipt_match helper_match = {
+static struct xt_match helper_match = {
+	.name		= "helper",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
+static struct xt_match helper6_match = {
 	.name		= "helper",
 	.match		= &match,
 	.checkentry	= &check,
@@ -154,13 +163,24 @@
 
 static int __init init(void)
 {
-	need_ip_conntrack();
-	return ipt_register_match(&helper_match);
+	int ret;
+	need_conntrack();
+
+	ret = xt_register_match(AF_INET, &helper_match);
+	if (ret < 0)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &helper6_match);
+	if (ret < 0)
+		xt_unregister_match(AF_INET, &helper_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&helper_match);
+	xt_unregister_match(AF_INET, &helper_match);
+	xt_unregister_match(AF_INET6, &helper6_match);
 }
 
 module_init(init);
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
new file mode 100644
index 0000000..39c8fae
--- /dev/null
+++ b/net/netfilter/xt_length.c
@@ -0,0 +1,99 @@
+/* Kernel module to match packet length. */
+/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+
+#include <linux/netfilter/xt_length.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
+MODULE_DESCRIPTION("IP tables packet length matching module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_length");
+MODULE_ALIAS("ip6t_length");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	const struct xt_length_info *info = matchinfo;
+	u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
+	
+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+match6(const struct sk_buff *skb,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *matchinfo,
+       int offset,
+       unsigned int protoff,
+       int *hotdrop)
+{
+	const struct xt_length_info *info = matchinfo;
+	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+	
+	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	if (matchsize != XT_ALIGN(sizeof(struct xt_length_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct xt_match length_match = {
+	.name		= "length",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match length6_match = {
+	.name		= "length",
+	.match		= &match6,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+	ret = xt_register_match(AF_INET, &length_match);
+	if (ret)
+		return ret;
+	ret = xt_register_match(AF_INET6, &length6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &length_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET, &length_match);
+	xt_unregister_match(AF_INET6, &length6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_limit.c b/net/netfilter/xt_limit.c
similarity index 78%
rename from net/ipv4/netfilter/ipt_limit.c
rename to net/netfilter/xt_limit.c
index 0c24dcc..15e4050 100644
--- a/net/ipv4/netfilter/ipt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -18,12 +18,14 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_limit.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_limit.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
 MODULE_DESCRIPTION("iptables rate limit match");
+MODULE_ALIAS("ipt_limit");
+MODULE_ALIAS("ip6t_limit");
 
 /* The algorithm used is the Simple Token Bucket Filter (TBF)
  * see net/sched/sch_tbf.c in the linux source tree
@@ -68,9 +70,10 @@
 		const struct net_device *out,
 		const void *matchinfo,
 		int offset,
+		unsigned int protoff,
 		int *hotdrop)
 {
-	struct ipt_rateinfo *r = ((struct ipt_rateinfo *)matchinfo)->master;
+	struct xt_rateinfo *r = ((struct xt_rateinfo *)matchinfo)->master;
 	unsigned long now = jiffies;
 
 	spin_lock_bh(&limit_lock);
@@ -96,32 +99,32 @@
 	/* If multiplying would overflow... */
 	if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
 		/* Divide first. */
-		return (user / IPT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
+		return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
 
-	return (user * HZ * CREDITS_PER_JIFFY) / IPT_LIMIT_SCALE;
+	return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
 }
 
 static int
 ipt_limit_checkentry(const char *tablename,
-		     const struct ipt_ip *ip,
+		     const void *inf,
 		     void *matchinfo,
 		     unsigned int matchsize,
 		     unsigned int hook_mask)
 {
-	struct ipt_rateinfo *r = matchinfo;
+	struct xt_rateinfo *r = matchinfo;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_rateinfo)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo)))
 		return 0;
 
 	/* Check for overflow. */
 	if (r->burst == 0
 	    || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-		printk("Overflow in ipt_limit, try lower: %u/%u\n",
+		printk("Overflow in xt_limit, try lower: %u/%u\n",
 		       r->avg, r->burst);
 		return 0;
 	}
 
-	/* User avg in seconds * IPT_LIMIT_SCALE: convert to jiffies *
+	/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
 	   128. */
 	r->prev = jiffies;
 	r->credit = user2credits(r->avg * r->burst);	 /* Credits full. */
@@ -134,7 +137,13 @@
 	return 1;
 }
 
-static struct ipt_match ipt_limit_reg = {
+static struct xt_match ipt_limit_reg = {
+	.name		= "limit",
+	.match		= ipt_limit_match,
+	.checkentry	= ipt_limit_checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match limit6_reg = {
 	.name		= "limit",
 	.match		= ipt_limit_match,
 	.checkentry	= ipt_limit_checkentry,
@@ -143,14 +152,23 @@
 
 static int __init init(void)
 {
-	if (ipt_register_match(&ipt_limit_reg))
-		return -EINVAL;
-	return 0;
+	int ret;
+	
+	ret = xt_register_match(AF_INET, &ipt_limit_reg);
+	if (ret)
+		return ret;
+	
+	ret = xt_register_match(AF_INET6, &limit6_reg);
+	if (ret)
+		xt_unregister_match(AF_INET, &ipt_limit_reg);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&ipt_limit_reg);
+	xt_unregister_match(AF_INET, &ipt_limit_reg);
+	xt_unregister_match(AF_INET6, &limit6_reg);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_mac.c b/net/netfilter/xt_mac.c
similarity index 65%
rename from net/ipv4/netfilter/ipt_mac.c
rename to net/netfilter/xt_mac.c
index 1b9bb45..0461dcb 100644
--- a/net/ipv4/netfilter/ipt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -13,12 +13,15 @@
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 
-#include <linux/netfilter_ipv4/ipt_mac.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/xt_mac.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 MODULE_DESCRIPTION("iptables mac matching module");
+MODULE_ALIAS("ipt_mac");
+MODULE_ALIAS("ip6t_mac");
 
 static int
 match(const struct sk_buff *skb,
@@ -26,9 +29,10 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-    const struct ipt_mac_info *info = matchinfo;
+    const struct xt_mac_info *info = matchinfo;
 
     /* Is mac pointer valid? */
     return (skb->mac.raw >= skb->head
@@ -40,7 +44,7 @@
 
 static int
 ipt_mac_checkentry(const char *tablename,
-		   const struct ipt_ip *ip,
+		   const void *inf,
 		   void *matchinfo,
 		   unsigned int matchsize,
 		   unsigned int hook_mask)
@@ -49,17 +53,23 @@
 	if (hook_mask
 	    & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
 		| (1 << NF_IP_FORWARD))) {
-		printk("ipt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+		printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
 		return 0;
 	}
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_mac_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info)))
 		return 0;
 
 	return 1;
 }
 
-static struct ipt_match mac_match = {
+static struct xt_match mac_match = {
+	.name		= "mac",
+	.match		= &match,
+	.checkentry	= &ipt_mac_checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match mac6_match = {
 	.name		= "mac",
 	.match		= &match,
 	.checkentry	= &ipt_mac_checkentry,
@@ -68,12 +78,22 @@
 
 static int __init init(void)
 {
-	return ipt_register_match(&mac_match);
+	int ret;
+	ret = xt_register_match(AF_INET, &mac_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &mac6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &mac_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&mac_match);
+	xt_unregister_match(AF_INET, &mac_match);
+	xt_unregister_match(AF_INET6, &mac6_match);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_mark.c b/net/netfilter/xt_mark.c
similarity index 60%
rename from net/ipv4/netfilter/ipt_mark.c
rename to net/netfilter/xt_mark.c
index 00bef6c..2a0ac62 100644
--- a/net/ipv4/netfilter/ipt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -10,12 +10,14 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
-#include <linux/netfilter_ipv4/ipt_mark.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/xt_mark.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables mark matching module");
+MODULE_ALIAS("ipt_mark");
+MODULE_ALIAS("ip6t_mark");
 
 static int
 match(const struct sk_buff *skb,
@@ -23,23 +25,24 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_mark_info *info = matchinfo;
+	const struct xt_mark_info *info = matchinfo;
 
 	return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
 }
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *entry,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
 {
-	struct ipt_mark_info *minfo = (struct ipt_mark_info *) matchinfo;
+	struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_mark_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info)))
 		return 0;
 
 	if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
@@ -50,7 +53,14 @@
 	return 1;
 }
 
-static struct ipt_match mark_match = {
+static struct xt_match mark_match = {
+	.name		= "mark",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match mark6_match = {
 	.name		= "mark",
 	.match		= &match,
 	.checkentry	= &checkentry,
@@ -59,12 +69,22 @@
 
 static int __init init(void)
 {
-	return ipt_register_match(&mark_match);
+	int ret;
+	ret = xt_register_match(AF_INET, &mark_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &mark6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &mark_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&mark_match);
+	xt_unregister_match(AF_INET, &mark_match);
+	xt_unregister_match(AF_INET6, &mark6_match);
 }
 
 module_init(init);
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
new file mode 100644
index 0000000..19bb57c
--- /dev/null
+++ b/net/netfilter/xt_physdev.c
@@ -0,0 +1,155 @@
+/* Kernel module to match the bridge port in and
+ * out device for IP packets coming into contact with a bridge. */
+
+/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/xt_physdev.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge.h>
+#define MATCH   1
+#define NOMATCH 0
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
+MODULE_DESCRIPTION("iptables bridge physical device match module");
+MODULE_ALIAS("ipt_physdev");
+MODULE_ALIAS("ip6t_physdev");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	int i;
+	static const char nulldevname[IFNAMSIZ];
+	const struct xt_physdev_info *info = matchinfo;
+	unsigned int ret;
+	const char *indev, *outdev;
+	struct nf_bridge_info *nf_bridge;
+
+	/* Not a bridged IP packet or no info available yet:
+	 * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
+	 * the destination device will be a bridge. */
+	if (!(nf_bridge = skb->nf_bridge)) {
+		/* Return MATCH if the invert flags of the used options are on */
+		if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
+		    !(info->invert & XT_PHYSDEV_OP_BRIDGED))
+			return NOMATCH;
+		if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
+		    !(info->invert & XT_PHYSDEV_OP_ISIN))
+			return NOMATCH;
+		if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
+		    !(info->invert & XT_PHYSDEV_OP_ISOUT))
+			return NOMATCH;
+		if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
+		    !(info->invert & XT_PHYSDEV_OP_IN))
+			return NOMATCH;
+		if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
+		    !(info->invert & XT_PHYSDEV_OP_OUT))
+			return NOMATCH;
+		return MATCH;
+	}
+
+	/* This only makes sense in the FORWARD and POSTROUTING chains */
+	if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
+	    (!!(nf_bridge->mask & BRNF_BRIDGED) ^
+	    !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
+		return NOMATCH;
+
+	if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
+	    (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
+	    (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
+	    (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
+		return NOMATCH;
+
+	if (!(info->bitmask & XT_PHYSDEV_OP_IN))
+		goto match_outdev;
+	indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
+	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+		ret |= (((const unsigned int *)indev)[i]
+			^ ((const unsigned int *)info->physindev)[i])
+			& ((const unsigned int *)info->in_mask)[i];
+	}
+
+	if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN))
+		return NOMATCH;
+
+match_outdev:
+	if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
+		return MATCH;
+	outdev = nf_bridge->physoutdev ?
+		 nf_bridge->physoutdev->name : nulldevname;
+	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+		ret |= (((const unsigned int *)outdev)[i]
+			^ ((const unsigned int *)info->physoutdev)[i])
+			& ((const unsigned int *)info->out_mask)[i];
+	}
+
+	return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT);
+}
+
+static int
+checkentry(const char *tablename,
+		       const void *ip,
+		       void *matchinfo,
+		       unsigned int matchsize,
+		       unsigned int hook_mask)
+{
+	const struct xt_physdev_info *info = matchinfo;
+
+	if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info)))
+		return 0;
+	if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
+	    info->bitmask & ~XT_PHYSDEV_OP_MASK)
+		return 0;
+	return 1;
+}
+
+static struct xt_match physdev_match = {
+	.name		= "physdev",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match physdev6_match = {
+	.name		= "physdev",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	ret = xt_register_match(AF_INET, &physdev_match);
+	if (ret < 0)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &physdev6_match);
+	if (ret < 0)
+		xt_unregister_match(AF_INET, &physdev_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET, &physdev_match);
+	xt_unregister_match(AF_INET6, &physdev6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
new file mode 100644
index 0000000..ab1b263
--- /dev/null
+++ b/net/netfilter/xt_pkttype.c
@@ -0,0 +1,82 @@
+/* (C) 1999-2001 Michal Ludvig <michal@logix.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <linux/netfilter/xt_pkttype.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>");
+MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
+MODULE_ALIAS("ipt_pkttype");
+MODULE_ALIAS("ip6t_pkttype");
+
+static int match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	const struct xt_pkttype_info *info = matchinfo;
+
+	return (skb->pkt_type == info->pkttype) ^ info->invert;
+}
+
+static int checkentry(const char *tablename,
+		   const void *ip,
+		   void *matchinfo,
+		   unsigned int matchsize,
+		   unsigned int hook_mask)
+{
+	if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct xt_match pkttype_match = {
+	.name		= "pkttype",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match pkttype6_match = {
+	.name		= "pkttype",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+	int ret;
+	ret = xt_register_match(AF_INET, &pkttype_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &pkttype6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &pkttype_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET, &pkttype_match);
+	xt_unregister_match(AF_INET6, &pkttype6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_realm.c b/net/netfilter/xt_realm.c
similarity index 70%
rename from net/ipv4/netfilter/ipt_realm.c
rename to net/netfilter/xt_realm.c
index 54a6897..2b7e178 100644
--- a/net/ipv4/netfilter/ipt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -14,12 +14,14 @@
 #include <linux/netdevice.h>
 #include <net/route.h>
 
-#include <linux/netfilter_ipv4/ipt_realm.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/xt_realm.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("iptables realm match");
+MODULE_DESCRIPTION("X_tables realm match");
+MODULE_ALIAS("ipt_realm");
 
 static int
 match(const struct sk_buff *skb,
@@ -27,16 +29,17 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_realm_info *info = matchinfo;
+	const struct xt_realm_info *info = matchinfo;
 	struct dst_entry *dst = skb->dst;
     
 	return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
 }
 
 static int check(const char *tablename,
-                 const struct ipt_ip *ip,
+                 const void *ip,
                  void *matchinfo,
                  unsigned int matchsize,
                  unsigned int hook_mask)
@@ -44,18 +47,18 @@
 	if (hook_mask
 	    & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
 	        (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
-		printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
+		printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
 		       "LOCAL_IN or FORWARD.\n");
 		return 0;
 	}
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) {
-		printk("ipt_realm: invalid matchsize.\n");
+	if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) {
+		printk("xt_realm: invalid matchsize.\n");
 		return 0;
 	}
 	return 1;
 }
 
-static struct ipt_match realm_match = {
+static struct xt_match realm_match = {
 	.name		= "realm",
 	.match		= match, 
 	.checkentry	= check,
@@ -64,12 +67,12 @@
 
 static int __init init(void)
 {
-	return ipt_register_match(&realm_match);
+	return xt_register_match(AF_INET, &realm_match);
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&realm_match);
+	xt_unregister_match(AF_INET, &realm_match);
 }
 
 module_init(init);
diff --git a/net/ipv4/netfilter/ipt_sctp.c b/net/netfilter/xt_sctp.c
similarity index 62%
rename from net/ipv4/netfilter/ipt_sctp.c
rename to net/netfilter/xt_sctp.c
index fe2b327..10fbfc5 100644
--- a/net/ipv4/netfilter/ipt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -1,10 +1,18 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 #include <linux/sctp.h>
 
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_sctp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_sctp.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kiran Kumar Immidi");
+MODULE_DESCRIPTION("Match for SCTP protocol packets");
+MODULE_ALIAS("ipt_sctp");
 
 #ifdef DEBUG_SCTP
 #define duprintf(format, args...) printk(format , ## args)
@@ -16,7 +24,7 @@
 					      || (!!((invflag) & (option)) ^ (cond)))
 
 static int
-match_flags(const struct ipt_sctp_flag_info *flag_info,
+match_flags(const struct xt_sctp_flag_info *flag_info,
 	    const int flag_count,
 	    u_int8_t chunktype,
 	    u_int8_t chunkflags)
@@ -32,15 +40,15 @@
 	return 1;
 }
 
-static int
+static inline int
 match_packet(const struct sk_buff *skb,
+	     unsigned int offset,
 	     const u_int32_t *chunkmap,
 	     int chunk_match_type,
-	     const struct ipt_sctp_flag_info *flag_info,
+	     const struct xt_sctp_flag_info *flag_info,
 	     const int flag_count,
 	     int *hotdrop)
 {
-	int offset;
 	u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
 	sctp_chunkhdr_t _sch, *sch;
 
@@ -52,7 +60,6 @@
 		SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
 	}
 
-	offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
 	do {
 		sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
 		if (sch == NULL) {
@@ -118,19 +125,20 @@
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
-	const struct ipt_sctp_info *info;
+	const struct xt_sctp_info *info;
 	sctp_sctphdr_t _sh, *sh;
 
-	info = (const struct ipt_sctp_info *)matchinfo;
+	info = (const struct xt_sctp_info *)matchinfo;
 
 	if (offset) {
 		duprintf("Dropping non-first fragment.. FIXME\n");
 		return 0;
 	}
 	
-	sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
+	sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh);
 	if (sh == NULL) {
 		duprintf("Dropping evil TCP offset=0 tinygram.\n");
 		*hotdrop = 1;
@@ -140,64 +148,103 @@
 
 	return  SCCHECK(((ntohs(sh->source) >= info->spts[0]) 
 			&& (ntohs(sh->source) <= info->spts[1])), 
-		   	IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
+		   	XT_SCTP_SRC_PORTS, info->flags, info->invflags)
 		&& SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) 
 			&& (ntohs(sh->dest) <= info->dpts[1])), 
-			IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
-		&& SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
+			XT_SCTP_DEST_PORTS, info->flags, info->invflags)
+		&& SCCHECK(match_packet(skb, protoff,
+					info->chunkmap, info->chunk_match_type,
  					info->flag_info, info->flag_count, 
 					hotdrop),
-			   IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
+			   XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
 }
 
 static int
 checkentry(const char *tablename,
-	   const struct ipt_ip *ip,
+	   const void *inf,
 	   void *matchinfo,
 	   unsigned int matchsize,
 	   unsigned int hook_mask)
 {
-	const struct ipt_sctp_info *info;
+	const struct xt_sctp_info *info;
+	const struct ipt_ip *ip = inf;
 
-	info = (const struct ipt_sctp_info *)matchinfo;
+	info = (const struct xt_sctp_info *)matchinfo;
 
 	return ip->proto == IPPROTO_SCTP
-		&& !(ip->invflags & IPT_INV_PROTO)
-		&& matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
-		&& !(info->flags & ~IPT_SCTP_VALID_FLAGS)
-		&& !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
+		&& !(ip->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
+		&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
+		&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
 		&& !(info->invflags & ~info->flags)
-		&& ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
+		&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
 			(info->chunk_match_type &
 				(SCTP_CHUNK_MATCH_ALL 
 				| SCTP_CHUNK_MATCH_ANY
 				| SCTP_CHUNK_MATCH_ONLY)));
 }
 
-static struct ipt_match sctp_match = 
+static int
+checkentry6(const char *tablename,
+	   const void *inf,
+	   void *matchinfo,
+	   unsigned int matchsize,
+	   unsigned int hook_mask)
+{
+	const struct xt_sctp_info *info;
+	const struct ip6t_ip6 *ip = inf;
+
+	info = (const struct xt_sctp_info *)matchinfo;
+
+	return ip->proto == IPPROTO_SCTP
+		&& !(ip->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
+		&& !(info->flags & ~XT_SCTP_VALID_FLAGS)
+		&& !(info->invflags & ~XT_SCTP_VALID_FLAGS)
+		&& !(info->invflags & ~info->flags)
+		&& ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
+			(info->chunk_match_type &
+				(SCTP_CHUNK_MATCH_ALL 
+				| SCTP_CHUNK_MATCH_ANY
+				| SCTP_CHUNK_MATCH_ONLY)));
+}
+
+
+static struct xt_match sctp_match = 
 { 
-	.list = { NULL, NULL},
 	.name = "sctp",
 	.match = &match,
 	.checkentry = &checkentry,
-	.destroy = NULL,
+	.me = THIS_MODULE
+};
+static struct xt_match sctp6_match = 
+{ 
+	.name = "sctp",
+	.match = &match,
+	.checkentry = &checkentry6,
 	.me = THIS_MODULE
 };
 
+
 static int __init init(void)
 {
-	return ipt_register_match(&sctp_match);
+	int ret;
+	ret = xt_register_match(AF_INET, &sctp_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &sctp6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &sctp_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&sctp_match);
+	xt_unregister_match(AF_INET6, &sctp6_match);
+	xt_unregister_match(AF_INET, &sctp_match);
 }
 
 module_init(init);
 module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kiran Kumar Immidi");
-MODULE_DESCRIPTION("Match for SCTP protocol packets");
-
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
new file mode 100644
index 0000000..39ce808
--- /dev/null
+++ b/net/netfilter/xt_state.c
@@ -0,0 +1,96 @@
+/* Kernel module to match connection tracking information. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_state.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
+MODULE_DESCRIPTION("ip[6]_tables connection tracking state match module");
+MODULE_ALIAS("ipt_state");
+MODULE_ALIAS("ip6t_state");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	const struct xt_state_info *sinfo = matchinfo;
+	enum ip_conntrack_info ctinfo;
+	unsigned int statebit;
+
+	if (nf_ct_is_untracked(skb))
+		statebit = XT_STATE_UNTRACKED;
+	else if (!nf_ct_get_ctinfo(skb, &ctinfo))
+		statebit = XT_STATE_INVALID;
+	else
+		statebit = XT_STATE_BIT(ctinfo);
+
+	return (sinfo->statemask & statebit);
+}
+
+static int check(const char *tablename,
+		 const void *ip,
+		 void *matchinfo,
+		 unsigned int matchsize,
+		 unsigned int hook_mask)
+{
+	if (matchsize != XT_ALIGN(sizeof(struct xt_state_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct xt_match state_match = {
+	.name		= "state",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match state6_match = {
+	.name		= "state",
+	.match		= &match,
+	.checkentry	= &check,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	need_conntrack();
+
+	ret = xt_register_match(AF_INET, &state_match);
+	if (ret < 0)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &state6_match);
+	if (ret < 0)
+		xt_unregister_match(AF_INET,&state_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET, &state_match);
+	xt_unregister_match(AF_INET6, &state6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_string.c b/net/netfilter/xt_string.c
similarity index 66%
rename from net/ipv4/netfilter/ipt_string.c
rename to net/netfilter/xt_string.c
index b5def20..7c7d5c8 100644
--- a/net/ipv4/netfilter/ipt_string.c
+++ b/net/netfilter/xt_string.c
@@ -11,23 +11,26 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_string.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_string.h>
 #include <linux/textsearch.h>
 
 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
 MODULE_DESCRIPTION("IP tables string match module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_string");
+MODULE_ALIAS("ip6t_string");
 
 static int match(const struct sk_buff *skb,
 		 const struct net_device *in,
 		 const struct net_device *out,
 		 const void *matchinfo,
 		 int offset,
+		 unsigned int protoff,
 		 int *hotdrop)
 {
 	struct ts_state state;
-	struct ipt_string_info *conf = (struct ipt_string_info *) matchinfo;
+	struct xt_string_info *conf = (struct xt_string_info *) matchinfo;
 
 	memset(&state, 0, sizeof(struct ts_state));
 
@@ -36,18 +39,18 @@
 			     != UINT_MAX) && !conf->invert;
 }
 
-#define STRING_TEXT_PRIV(m) ((struct ipt_string_info *) m)
+#define STRING_TEXT_PRIV(m) ((struct xt_string_info *) m)
 
 static int checkentry(const char *tablename,
-		      const struct ipt_ip *ip,
+		      const void *ip,
 		      void *matchinfo,
 		      unsigned int matchsize,
 		      unsigned int hook_mask)
 {
-	struct ipt_string_info *conf = matchinfo;
+	struct xt_string_info *conf = matchinfo;
 	struct ts_config *ts_conf;
 
-	if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
+	if (matchsize != XT_ALIGN(sizeof(struct xt_string_info)))
 		return 0;
 
 	/* Damn, can't handle this case properly with iptables... */
@@ -69,7 +72,14 @@
 	textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
 }
 
-static struct ipt_match string_match = {
+static struct xt_match string_match = {
+	.name 		= "string",
+	.match 		= match,
+	.checkentry	= checkentry,
+	.destroy 	= destroy,
+	.me 		= THIS_MODULE
+};
+static struct xt_match string6_match = {
 	.name 		= "string",
 	.match 		= match,
 	.checkentry	= checkentry,
@@ -79,12 +89,22 @@
 
 static int __init init(void)
 {
-	return ipt_register_match(&string_match);
+	int ret;
+
+	ret = xt_register_match(AF_INET, &string_match);
+	if (ret)
+		return ret;
+	ret = xt_register_match(AF_INET6, &string6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &string_match);
+
+	return ret;
 }
 
 static void __exit fini(void)
 {
-	ipt_unregister_match(&string_match);
+	xt_unregister_match(AF_INET, &string_match);
+	xt_unregister_match(AF_INET6, &string6_match);
 }
 
 module_init(init);
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
new file mode 100644
index 0000000..acf7f53
--- /dev/null
+++ b/net/netfilter/xt_tcpmss.c
@@ -0,0 +1,172 @@
+/* Kernel module to match TCP MSS values. */
+
+/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ * Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter/xt_tcpmss.h>
+#include <linux/netfilter/x_tables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define TH_SYN 0x02
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("iptables TCP MSS match module");
+MODULE_ALIAS("ipt_tcpmss");
+
+/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
+static inline int
+mssoption_match(u_int16_t min, u_int16_t max,
+		const struct sk_buff *skb,
+		unsigned int protoff,
+		int invert,
+		int *hotdrop)
+{
+	struct tcphdr _tcph, *th;
+	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+	u8 _opt[15 * 4 - sizeof(_tcph)], *op;
+	unsigned int i, optlen;
+
+	/* If we don't have the whole header, drop packet. */
+	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+	if (th == NULL)
+		goto dropit;
+
+	/* Malformed. */
+	if (th->doff*4 < sizeof(*th))
+		goto dropit;
+
+	optlen = th->doff*4 - sizeof(*th);
+	if (!optlen)
+		goto out;
+
+	/* Truncated options. */
+	op = skb_header_pointer(skb, protoff + sizeof(*th), optlen, _opt);
+	if (op == NULL)
+		goto dropit;
+
+	for (i = 0; i < optlen; ) {
+		if (op[i] == TCPOPT_MSS
+		    && (optlen - i) >= TCPOLEN_MSS
+		    && op[i+1] == TCPOLEN_MSS) {
+			u_int16_t mssval;
+
+			mssval = (op[i+2] << 8) | op[i+3];
+			
+			return (mssval >= min && mssval <= max) ^ invert;
+		}
+		if (op[i] < 2) i++;
+		else i += op[i+1]?:1;
+	}
+out:
+	return invert;
+
+ dropit:
+	*hotdrop = 1;
+	return 0;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+	const struct xt_tcpmss_match_info *info = matchinfo;
+
+	return mssoption_match(info->mss_min, info->mss_max, skb, protoff,
+			       info->invert, hotdrop);
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ipinfo,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = ipinfo;
+	if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
+		return 0;
+
+	/* Must specify -p tcp */
+	if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
+		printk("tcpmss: Only works on TCP packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+checkentry6(const char *tablename,
+	   const void *ipinfo,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ip = ipinfo;
+
+	if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
+		return 0;
+
+	/* Must specify -p tcp */
+	if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) {
+		printk("tcpmss: Only works on TCP packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct xt_match tcpmss_match = {
+	.name		= "tcpmss",
+	.match		= &match,
+	.checkentry	= &checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match tcpmss6_match = {
+	.name		= "tcpmss",
+	.match		= &match,
+	.checkentry	= &checkentry6,
+	.me		= THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+	int ret;
+	ret = xt_register_match(AF_INET, &tcpmss_match);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &tcpmss6_match);
+	if (ret)
+		xt_unregister_match(AF_INET, &tcpmss_match);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET6, &tcpmss6_match);
+	xt_unregister_match(AF_INET, &tcpmss_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
new file mode 100644
index 0000000..669c811
--- /dev/null
+++ b/net/netfilter/xt_tcpudp.c
@@ -0,0 +1,334 @@
+#include <linux/types.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xt_tcp");
+MODULE_ALIAS("xt_udp");
+MODULE_ALIAS("ipt_udp");
+MODULE_ALIAS("ipt_tcp");
+MODULE_ALIAS("ip6t_udp");
+MODULE_ALIAS("ip6t_tcp");
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+
+/* Returns 1 if the port is matched by the range, 0 otherwise */
+static inline int
+port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
+{
+	int ret;
+
+	ret = (port >= min && port <= max) ^ invert;
+	return ret;
+}
+
+static int
+tcp_find_option(u_int8_t option,
+		const struct sk_buff *skb,
+		unsigned int protoff,
+		unsigned int optlen,
+		int invert,
+		int *hotdrop)
+{
+	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+	u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
+	unsigned int i;
+
+	duprintf("tcp_match: finding option\n");
+
+	if (!optlen)
+		return invert;
+
+	/* If we don't have the whole header, drop packet. */
+	op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
+				optlen, _opt);
+	if (op == NULL) {
+		*hotdrop = 1;
+		return 0;
+	}
+
+	for (i = 0; i < optlen; ) {
+		if (op[i] == option) return !invert;
+		if (op[i] < 2) i++;
+		else i += op[i+1]?:1;
+	}
+
+	return invert;
+}
+
+static int
+tcp_match(const struct sk_buff *skb,
+	  const struct net_device *in,
+	  const struct net_device *out,
+	  const void *matchinfo,
+	  int offset,
+	  unsigned int protoff,
+	  int *hotdrop)
+{
+	struct tcphdr _tcph, *th;
+	const struct xt_tcp *tcpinfo = matchinfo;
+
+	if (offset) {
+		/* To quote Alan:
+
+		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
+		   causes this. Its a cracker trying to break in by doing a
+		   flag overwrite to pass the direction checks.
+		*/
+		if (offset == 1) {
+			duprintf("Dropping evil TCP offset=1 frag.\n");
+			*hotdrop = 1;
+		}
+		/* Must not be a fragment. */
+		return 0;
+	}
+
+#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
+
+	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+	if (th == NULL) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil TCP offset=0 tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
+			ntohs(th->source),
+			!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
+		return 0;
+	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
+			ntohs(th->dest),
+			!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
+		return 0;
+	if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
+		      == tcpinfo->flg_cmp,
+		      XT_TCP_INV_FLAGS))
+		return 0;
+	if (tcpinfo->option) {
+		if (th->doff * 4 < sizeof(_tcph)) {
+			*hotdrop = 1;
+			return 0;
+		}
+		if (!tcp_find_option(tcpinfo->option, skb, protoff,
+				     th->doff*4 - sizeof(_tcph),
+				     tcpinfo->invflags & XT_TCP_INV_OPTION,
+				     hotdrop))
+			return 0;
+	}
+	return 1;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+tcp_checkentry(const char *tablename,
+	       const void *info,
+	       void *matchinfo,
+	       unsigned int matchsize,
+	       unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = info;
+	const struct xt_tcp *tcpinfo = matchinfo;
+
+	/* Must specify proto == TCP, and no unknown invflags */
+	return ip->proto == IPPROTO_TCP
+		&& !(ip->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
+		&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+tcp6_checkentry(const char *tablename,
+	       const void *entry,
+	       void *matchinfo,
+	       unsigned int matchsize,
+	       unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ipv6 = entry;
+	const struct xt_tcp *tcpinfo = matchinfo;
+
+	/* Must specify proto == TCP, and no unknown invflags */
+	return ipv6->proto == IPPROTO_TCP
+		&& !(ipv6->invflags & XT_INV_PROTO)
+		&& matchsize == XT_ALIGN(sizeof(struct xt_tcp))
+		&& !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+}
+
+
+static int
+udp_match(const struct sk_buff *skb,
+	  const struct net_device *in,
+	  const struct net_device *out,
+	  const void *matchinfo,
+	  int offset,
+	  unsigned int protoff,
+	  int *hotdrop)
+{
+	struct udphdr _udph, *uh;
+	const struct xt_udp *udpinfo = matchinfo;
+
+	/* Must not be a fragment. */
+	if (offset)
+		return 0;
+
+	uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
+	if (uh == NULL) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil UDP tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	return port_match(udpinfo->spts[0], udpinfo->spts[1],
+			  ntohs(uh->source),
+			  !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
+		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
+			      ntohs(uh->dest),
+			      !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+udp_checkentry(const char *tablename,
+	       const void *info,
+	       void *matchinfo,
+	       unsigned int matchinfosize,
+	       unsigned int hook_mask)
+{
+	const struct ipt_ip *ip = info;
+	const struct xt_udp *udpinfo = matchinfo;
+
+	/* Must specify proto == UDP, and no unknown invflags */
+	if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) {
+		duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_UDP);
+		return 0;
+	}
+	if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
+		duprintf("ipt_udp: matchsize %u != %u\n",
+			 matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
+		return 0;
+	}
+	if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
+		duprintf("ipt_udp: unknown flags %X\n",
+			 udpinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+udp6_checkentry(const char *tablename,
+	       const void *entry,
+	       void *matchinfo,
+	       unsigned int matchinfosize,
+	       unsigned int hook_mask)
+{
+	const struct ip6t_ip6 *ipv6 = entry;
+	const struct xt_udp *udpinfo = matchinfo;
+
+	/* Must specify proto == UDP, and no unknown invflags */
+	if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) {
+		duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
+			 IPPROTO_UDP);
+		return 0;
+	}
+	if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
+		duprintf("ip6t_udp: matchsize %u != %u\n",
+			 matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
+		return 0;
+	}
+	if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
+		duprintf("ip6t_udp: unknown flags %X\n",
+			 udpinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct xt_match tcp_matchstruct = {
+	.name		= "tcp",
+	.match		= &tcp_match,
+	.checkentry	= &tcp_checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match tcp6_matchstruct = {
+	.name		= "tcp",
+	.match		= &tcp_match,
+	.checkentry	= &tcp6_checkentry,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_match udp_matchstruct = {
+	.name		= "udp",
+	.match		= &udp_match,
+	.checkentry	= &udp_checkentry,
+	.me		= THIS_MODULE,
+};
+static struct xt_match udp6_matchstruct = {
+	.name		= "udp",
+	.match		= &udp_match,
+	.checkentry	= &udp6_checkentry,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int ret;
+	ret = xt_register_match(AF_INET, &tcp_matchstruct);
+	if (ret)
+		return ret;
+
+	ret = xt_register_match(AF_INET6, &tcp6_matchstruct);
+	if (ret)
+		goto out_unreg_tcp;
+
+	ret = xt_register_match(AF_INET, &udp_matchstruct);
+	if (ret)
+		goto out_unreg_tcp6;
+	
+	ret = xt_register_match(AF_INET6, &udp6_matchstruct);
+	if (ret)
+		goto out_unreg_udp;
+
+	return ret;
+
+out_unreg_udp:
+	xt_unregister_match(AF_INET, &tcp_matchstruct);
+out_unreg_tcp6:
+	xt_unregister_match(AF_INET6, &tcp6_matchstruct);
+out_unreg_tcp:
+	xt_unregister_match(AF_INET, &tcp_matchstruct);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	xt_unregister_match(AF_INET6, &udp6_matchstruct);
+	xt_unregister_match(AF_INET, &udp_matchstruct);
+	xt_unregister_match(AF_INET6, &tcp6_matchstruct);
+	xt_unregister_match(AF_INET, &tcp_matchstruct);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 3b13784..4ae1538 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -222,11 +222,6 @@
 		goto errout_locked;
 	}
 
-	if (!try_module_get(family->owner)) {
-		err = -EBUSY;
-		goto errout_locked;
-	}
-
 	if (family->id == GENL_ID_GENERATE) {
 		u16 newid = genl_generate_id();
 
@@ -283,7 +278,6 @@
 		INIT_LIST_HEAD(&family->ops_list);
 		genl_unlock();
 
-		module_put(family->owner);
 		kfree(family->attrbuf);
 		genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
 		return 0;
@@ -535,7 +529,6 @@
 	.name = "nlctrl",
 	.version = 0x1,
 	.maxattr = CTRL_ATTR_MAX,
-	.owner = THIS_MODULE,
 };
 
 static int __init genl_init(void)
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 8a260d4..778b1e5 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -44,7 +44,7 @@
 
 choice
 	prompt "Packet scheduler clock source"
-	default NET_SCH_CLK_JIFFIES
+	default NET_SCH_CLK_GETTIMEOFDAY
 	---help---
 	  Packet schedulers need a monotonic clock that increments at a static
 	  rate. The kernel provides several suitable interfaces, each with
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index b500193..39a22a3 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -62,7 +62,7 @@
 	struct ipt_target *target;
 	int ret = 0;
 
-	target = ipt_find_target(t->u.user.name, t->u.user.revision);
+	target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision);
 	if (!target)
 		return -ENOENT;
 
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 04c7fab..2e26612 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -180,8 +180,7 @@
 	}
 
 	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-			  "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-			  "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			  "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
 			  __FUNCTION__, skb, skb->len,
 			  NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
 
@@ -206,13 +205,13 @@
 		fl.oif = daddr->v6.sin6_scope_id;
 	
 
-	SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+	SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
 			  __FUNCTION__, NIP6(fl.fl6_dst));
 
 	if (saddr) {
 		ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
 		SCTP_DEBUG_PRINTK(
-			"SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
+			"SRC=" NIP6_FMT " - ",
 			NIP6(fl.fl6_src));
 	}
 
@@ -221,8 +220,7 @@
 		struct rt6_info *rt;
 		rt = (struct rt6_info *)dst;
 		SCTP_DEBUG_PRINTK(
-			"rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-			"rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			"rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
 			NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
 	} else {
 		SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -271,13 +269,12 @@
 	__u8 bmatchlen;
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
-			  "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+			  "daddr:" NIP6_FMT " ",
 			  __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
 		ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
-		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
-				  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
 				  NIP6(saddr->v6.sin6_addr));
 		return;
 	}
@@ -305,13 +302,11 @@
 
 	if (baddr) {
 		memcpy(saddr, baddr, sizeof(union sctp_addr));
-		SCTP_DEBUG_PRINTK("saddr: "
-				  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
 				  NIP6(saddr->v6.sin6_addr));
 	} else {
 		printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
-		       "address for the "
-		       "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		       "address for the dest:" NIP6_FMT "\n",
 		       __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
 	}
 
@@ -675,8 +670,7 @@
 /* Dump the v6 addr to the seq file. */
 static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
 {
-	seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
-		   NIP6(addr->v6.sin6_addr));
+	seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
 }
 
 /* Initialize a PF_INET6 socket msg_name. */
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 557a7d9..477d7f8 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1036,14 +1036,14 @@
 		if (from_addr.sa.sa_family == AF_INET6) {
 			printk(KERN_WARNING
 			       "%s association %p could not find address "
-			       "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			       NIP6_FMT "\n",
 			       __FUNCTION__,
 			       asoc,
 			       NIP6(from_addr.v6.sin6_addr));
 		} else {
 			printk(KERN_WARNING
 			       "%s association %p could not find address "
-			       "%u.%u.%u.%u\n",
+			       NIPQUAD_FMT "\n",
 			       __FUNCTION__,
 			       asoc,
 			       NIPQUAD(from_addr.v4.sin_addr.s_addr));
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
new file mode 100644
index 0000000..05ab18e
--- /dev/null
+++ b/net/tipc/Kconfig
@@ -0,0 +1,112 @@
+#
+# TIPC configuration
+#
+
+menu "TIPC Configuration (EXPERIMENTAL)"
+	depends on INET && EXPERIMENTAL
+
+config TIPC
+	tristate "The TIPC Protocol (EXPERIMENTAL)"
+	---help---
+	  TBD.
+
+	  This protocol support is also available as a module ( = code which
+	  can be inserted in and removed from the running kernel whenever you
+	  want). The module will be called tipc. If you want to compile it
+	  as a module, say M here and read <file:Documentation/modules.txt>.
+
+	  If in doubt, say N.
+
+config TIPC_ADVANCED
+	bool "TIPC: Advanced configuration"
+	depends on TIPC
+	default n
+	help
+	  Saying Y here will open some advanced configuration
+          for TIPC. Most users do not need to bother, so if
+          unsure, just say N.
+
+config TIPC_ZONES
+	int "Maximum number of zones in network"
+	depends on TIPC && TIPC_ADVANCED
+	default "3"
+	help
+	 Max number of zones inside TIPC network. Max supported value 
+         is 255 zones, minimum is 1
+
+	 Default is 3 zones in a network; setting this to higher
+	 allows more zones but might use more memory.
+
+config TIPC_CLUSTERS
+	int "Maximum number of clusters in a zone"
+	depends on TIPC && TIPC_ADVANCED
+	default "1"
+	help
+          ***Only 1 (one cluster in a zone) is supported by current code.
+          Any value set here will be overridden.***
+
+          (Max number of clusters inside TIPC zone. Max supported 
+          value is 4095 clusters, minimum is 1.
+
+	  Default is 1; setting this to smaller value might save 
+          some memory, setting it to higher
+	  allows more clusters and might consume more memory.)
+
+config TIPC_NODES
+	int "Maximum number of nodes in cluster"
+	depends on TIPC && TIPC_ADVANCED
+	default "255"
+	help
+	  Maximum number of nodes inside a TIPC cluster. Maximum 
+          supported value is 2047 nodes, minimum is 8. 
+
+	  Setting this to a smaller value saves some memory, 
+	  setting it to higher allows more nodes.
+
+config TIPC_SLAVE_NODES
+	int "Maximum number of slave nodes in cluster"
+	depends on TIPC && TIPC_ADVANCED
+	default "0"
+	help
+          ***This capability is not supported by current code.***
+	  
+	  Maximum number of slave nodes inside a TIPC cluster. Maximum 
+          supported value is 2047 nodes, minimum is 0. 
+
+	  Setting this to a smaller value saves some memory, 
+	  setting it to higher allows more nodes.
+
+config TIPC_PORTS
+	int "Maximum number of ports in a node"
+	depends on TIPC && TIPC_ADVANCED
+	default "8191"
+	help
+	  Maximum number of ports within a node. Maximum 
+          supported value is 64535 nodes, minimum is 127. 
+
+	  Setting this to a smaller value saves some memory, 
+	  setting it to higher allows more ports.
+
+config TIPC_LOG
+	int "Size of log buffer"
+	depends on TIPC && TIPC_ADVANCED
+	default 0
+	help
+ 	  Size (in bytes) of TIPC's internal log buffer, which records the
+	  occurrence of significant events.  Maximum supported value
+	  is 32768 bytes, minimum is 0.
+
+	  There is no need to enable the log buffer unless the node will be
+	  managed remotely via TIPC.
+
+config TIPC_DEBUG
+	bool "Enable debugging support"
+	depends on TIPC
+	default n
+	help
+ 	  This will enable debugging of TIPC.
+
+	  Only say Y here if you are having trouble with TIPC.  It will
+	  enable the display of detailed information about what is going on.
+
+endmenu
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
new file mode 100644
index 0000000..dceb702
--- /dev/null
+++ b/net/tipc/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the Linux TIPC layer
+#
+
+obj-$(CONFIG_TIPC) := tipc.o
+
+tipc-y	+= addr.o bcast.o bearer.o config.o cluster.o \
+	   core.o handler.o link.o discover.o msg.o  \
+	   name_distr.o  subscr.o name_table.o net.o  \
+	   netlink.o node.o node_subscr.o port.o ref.o  \
+	   socket.o user_reg.o zone.o dbg.o eth_media.o
+
+# End of file
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
new file mode 100644
index 0000000..eca2226
--- /dev/null
+++ b/net/tipc/addr.c
@@ -0,0 +1,94 @@
+/*
+ * net/tipc/addr.c: TIPC address utility routines
+ *     
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "addr.h"
+#include "zone.h"
+#include "cluster.h"
+#include "net.h"
+
+u32 tipc_get_addr(void)
+{
+	return tipc_own_addr;
+}
+
+/**
+ * addr_domain_valid - validates a network domain address
+ * 
+ * Accepts <Z.C.N>, <Z.C.0>, <Z.0.0>, and <0.0.0>, 
+ * where Z, C, and N are non-zero and do not exceed the configured limits.
+ * 
+ * Returns 1 if domain address is valid, otherwise 0
+ */
+
+int addr_domain_valid(u32 addr)
+{
+	u32 n = tipc_node(addr);
+	u32 c = tipc_cluster(addr);
+	u32 z = tipc_zone(addr);
+	u32 max_nodes = tipc_max_nodes;
+
+	if (is_slave(addr))
+		max_nodes = LOWEST_SLAVE + tipc_max_slaves;
+	if (n > max_nodes)
+		return 0;
+	if (c > tipc_max_clusters)
+		return 0;
+	if (z > tipc_max_zones)
+		return 0;
+
+	if (n && (!z || !c))
+		return 0;
+	if (c && !z)
+		return 0;
+	return 1;
+}
+
+/**
+ * addr_node_valid - validates a proposed network address for this node
+ * 
+ * Accepts <Z.C.N>, where Z, C, and N are non-zero and do not exceed 
+ * the configured limits.
+ * 
+ * Returns 1 if address can be used, otherwise 0
+ */
+
+int addr_node_valid(u32 addr)
+{
+	return (addr_domain_valid(addr) && tipc_node(addr));
+}
+
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
new file mode 100644
index 0000000..02ca717
--- /dev/null
+++ b/net/tipc/addr.h
@@ -0,0 +1,128 @@
+/*
+ * net/tipc/addr.h: Include file for TIPC address utility routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_ADDR_H
+#define _TIPC_ADDR_H
+
+static inline u32 own_node(void)
+{
+	return tipc_node(tipc_own_addr);
+}
+
+static inline u32 own_cluster(void)
+{
+	return tipc_cluster(tipc_own_addr);
+}
+
+static inline u32 own_zone(void)
+{
+	return tipc_zone(tipc_own_addr);
+}
+
+static inline int in_own_cluster(u32 addr)
+{
+	return !((addr ^ tipc_own_addr) >> 12);
+}
+
+static inline int in_own_zone(u32 addr)
+{
+	return !((addr ^ tipc_own_addr) >> 24);
+}
+
+static inline int is_slave(u32 addr)
+{
+	return addr & 0x800;
+}
+
+static inline int may_route(u32 addr)
+{
+	return(addr ^ tipc_own_addr) >> 11;
+}
+
+static inline int in_scope(u32 domain, u32 addr)
+{
+	if (!domain || (domain == addr))
+		return 1;
+	if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
+		return 1;
+	if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
+		return 1;
+	return 0;
+}
+
+/**
+ * addr_scope - convert message lookup domain to equivalent 2-bit scope value
+ */
+
+static inline int addr_scope(u32 domain)
+{
+	if (likely(!domain))
+		return TIPC_ZONE_SCOPE;
+	if (tipc_node(domain))
+		return TIPC_NODE_SCOPE;
+	if (tipc_cluster(domain))
+		return TIPC_CLUSTER_SCOPE;
+	return TIPC_ZONE_SCOPE;
+}
+
+/**
+ * addr_domain - convert 2-bit scope value to equivalent message lookup domain
+ *  
+ * Needed when address of a named message must be looked up a second time 
+ * after a network hop.
+ */
+
+static inline int addr_domain(int sc)
+{
+	if (likely(sc == TIPC_NODE_SCOPE))
+		return tipc_own_addr;
+	if (sc == TIPC_CLUSTER_SCOPE)
+		return tipc_addr(tipc_zone(tipc_own_addr),
+				 tipc_cluster(tipc_own_addr), 0);
+	return tipc_addr(tipc_zone(tipc_own_addr), 0, 0);
+}
+
+static inline char *addr_string_fill(char *string, u32 addr)
+{
+	snprintf(string, 16, "<%u.%u.%u>",
+		 tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
+	return string;
+}
+
+int addr_domain_valid(u32);
+int addr_node_valid(u32 addr);
+
+#endif
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
new file mode 100644
index 0000000..9713d62
--- /dev/null
+++ b/net/tipc/bcast.c
@@ -0,0 +1,806 @@
+/*
+ * net/tipc/bcast.c: TIPC broadcast code
+ *     
+ * Copyright (c) 2004-2006, Ericsson AB
+ * Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "msg.h"
+#include "dbg.h"
+#include "link.h"
+#include "net.h"
+#include "node.h"
+#include "port.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "name_distr.h"
+#include "bearer.h"
+#include "name_table.h"
+#include "bcast.h"
+
+
+#define MAX_PKT_DEFAULT_MCAST 1500	/* bcast link max packet size (fixed) */
+
+#define BCLINK_WIN_DEFAULT 20		/* bcast link window size (default) */
+
+#define BCLINK_LOG_BUF_SIZE 0
+
+/**
+ * struct bcbearer_pair - a pair of bearers used by broadcast link
+ * @primary: pointer to primary bearer
+ * @secondary: pointer to secondary bearer
+ * 
+ * Bearers must have same priority and same set of reachable destinations 
+ * to be paired.
+ */
+
+struct bcbearer_pair {
+	struct bearer *primary;
+	struct bearer *secondary;
+};
+
+/**
+ * struct bcbearer - bearer used by broadcast link
+ * @bearer: (non-standard) broadcast bearer structure
+ * @media: (non-standard) broadcast media structure
+ * @bpairs: array of bearer pairs
+ * @bpairs_temp: array of bearer pairs used during creation of "bpairs"
+ */
+
+struct bcbearer {
+	struct bearer bearer;
+	struct media media;
+	struct bcbearer_pair bpairs[MAX_BEARERS];
+	struct bcbearer_pair bpairs_temp[TIPC_NUM_LINK_PRI];
+};
+
+/**
+ * struct bclink - link used for broadcast messages
+ * @link: (non-standard) broadcast link structure
+ * @node: (non-standard) node structure representing b'cast link's peer node
+ * 
+ * Handles sequence numbering, fragmentation, bundling, etc.
+ */
+
+struct bclink {
+	struct link link;
+	struct node node;
+};
+
+
+static struct bcbearer *bcbearer = NULL;
+static struct bclink *bclink = NULL;
+static struct link *bcl = NULL;
+static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
+
+char bc_link_name[] = "multicast-link";
+
+
+static inline u32 buf_seqno(struct sk_buff *buf)
+{
+	return msg_seqno(buf_msg(buf));
+} 
+
+static inline u32 bcbuf_acks(struct sk_buff *buf)
+{
+	return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle;
+}
+
+static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
+{
+	TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks;
+}
+
+static inline void bcbuf_decr_acks(struct sk_buff *buf)
+{
+	bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
+}
+
+
+/** 
+ * bclink_set_gap - set gap according to contents of current deferred pkt queue
+ * 
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static inline void bclink_set_gap(struct node *n_ptr)
+{
+	struct sk_buff *buf = n_ptr->bclink.deferred_head;
+
+	n_ptr->bclink.gap_after = n_ptr->bclink.gap_to =
+		mod(n_ptr->bclink.last_in);
+	if (unlikely(buf != NULL))
+		n_ptr->bclink.gap_to = mod(buf_seqno(buf) - 1);
+}
+
+/** 
+ * bclink_ack_allowed - test if ACK or NACK message can be sent at this moment
+ * 
+ * This mechanism endeavours to prevent all nodes in network from trying
+ * to ACK or NACK at the same time.
+ * 
+ * Note: TIPC uses a different trigger to distribute ACKs than it does to
+ *       distribute NACKs, but tries to use the same spacing (divide by 16). 
+ */
+
+static inline int bclink_ack_allowed(u32 n)
+{
+	return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
+}
+
+
+/** 
+ * bclink_retransmit_pkt - retransmit broadcast packets
+ * @after: sequence number of last packet to *not* retransmit
+ * @to: sequence number of last packet to retransmit
+ * 
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static void bclink_retransmit_pkt(u32 after, u32 to)
+{
+	struct sk_buff *buf;
+
+	spin_lock_bh(&bc_lock);
+	buf = bcl->first_out;
+	while (buf && less_eq(buf_seqno(buf), after)) {
+		buf = buf->next;                
+	}
+	if (buf != NULL)
+		link_retransmit(bcl, buf, mod(to - after));
+	spin_unlock_bh(&bc_lock);              
+}
+
+/** 
+ * bclink_acknowledge - handle acknowledgement of broadcast packets
+ * @n_ptr: node that sent acknowledgement info
+ * @acked: broadcast sequence # that has been acknowledged
+ * 
+ * Node is locked, bc_lock unlocked.
+ */
+
+void bclink_acknowledge(struct node *n_ptr, u32 acked)
+{
+	struct sk_buff *crs;
+	struct sk_buff *next;
+	unsigned int released = 0;
+
+	if (less_eq(acked, n_ptr->bclink.acked))
+		return;
+
+	spin_lock_bh(&bc_lock);
+
+	/* Skip over packets that node has previously acknowledged */
+
+	crs = bcl->first_out;
+	while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) {
+		crs = crs->next;
+	}
+
+	/* Update packets that node is now acknowledging */
+
+	while (crs && less_eq(buf_seqno(crs), acked)) {
+		next = crs->next;
+		bcbuf_decr_acks(crs);
+		if (bcbuf_acks(crs) == 0) {
+			bcl->first_out = next;
+			bcl->out_queue_size--;
+			buf_discard(crs);
+			released = 1;
+		}
+		crs = next;
+	}
+	n_ptr->bclink.acked = acked;
+
+	/* Try resolving broadcast link congestion, if necessary */
+
+	if (unlikely(bcl->next_out))
+		link_push_queue(bcl);
+	if (unlikely(released && !list_empty(&bcl->waiting_ports)))
+		link_wakeup_ports(bcl, 0);
+	spin_unlock_bh(&bc_lock);
+}
+
+/** 
+ * bclink_send_ack - unicast an ACK msg
+ * 
+ * net_lock and node lock set
+ */
+
+static void bclink_send_ack(struct node *n_ptr)
+{
+	struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
+
+	if (l_ptr != NULL)
+		link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+}
+
+/** 
+ * bclink_send_nack- broadcast a NACK msg
+ * 
+ * net_lock and node lock set
+ */
+
+static void bclink_send_nack(struct node *n_ptr)
+{
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+
+	if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to))
+		return;
+
+	buf = buf_acquire(INT_H_SIZE);
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
+			 TIPC_OK, INT_H_SIZE, n_ptr->addr);
+		msg_set_mc_netid(msg, tipc_net_id);
+		msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); 
+		msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
+		msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
+		msg_set_bcast_tag(msg, tipc_own_tag);
+
+		if (bearer_send(&bcbearer->bearer, buf, 0)) {
+			bcl->stats.sent_nacks++;
+			buf_discard(buf);
+		} else {
+			bearer_schedule(bcl->b_ptr, bcl);
+			bcl->proto_msg_queue = buf;
+			bcl->stats.bearer_congs++;
+		}
+
+		/* 
+		 * Ensure we doesn't send another NACK msg to the node
+		 * until 16 more deferred messages arrive from it
+		 * (i.e. helps prevent all nodes from NACK'ing at same time)
+		 */
+		
+		n_ptr->bclink.nack_sync = tipc_own_tag;
+	}
+}
+
+/** 
+ * bclink_check_gap - send a NACK if a sequence gap exists
+ *
+ * net_lock and node lock set
+ */
+
+void bclink_check_gap(struct node *n_ptr, u32 last_sent)
+{
+	if (!n_ptr->bclink.supported ||
+	    less_eq(last_sent, mod(n_ptr->bclink.last_in)))
+		return;
+
+	bclink_set_gap(n_ptr);
+	if (n_ptr->bclink.gap_after == n_ptr->bclink.gap_to)
+		n_ptr->bclink.gap_to = last_sent;
+	bclink_send_nack(n_ptr);
+}
+
+/** 
+ * bclink_peek_nack - process a NACK msg meant for another node
+ * 
+ * Only net_lock set.
+ */
+
+void bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
+{
+	struct node *n_ptr = node_find(dest);
+	u32 my_after, my_to;
+
+	if (unlikely(!n_ptr || !node_is_up(n_ptr)))
+		return;
+	node_lock(n_ptr);
+	/*
+	 * Modify gap to suppress unnecessary NACKs from this node
+	 */
+	my_after = n_ptr->bclink.gap_after;
+	my_to = n_ptr->bclink.gap_to;
+
+	if (less_eq(gap_after, my_after)) {
+		if (less(my_after, gap_to) && less(gap_to, my_to))
+			n_ptr->bclink.gap_after = gap_to;
+		else if (less_eq(my_to, gap_to))
+			n_ptr->bclink.gap_to = n_ptr->bclink.gap_after;
+	} else if (less_eq(gap_after, my_to)) {
+		if (less_eq(my_to, gap_to))
+			n_ptr->bclink.gap_to = gap_after;
+	} else {
+		/* 
+		 * Expand gap if missing bufs not in deferred queue:
+		 */
+		struct sk_buff *buf = n_ptr->bclink.deferred_head;
+		u32 prev = n_ptr->bclink.gap_to;
+
+		for (; buf; buf = buf->next) {
+			u32 seqno = buf_seqno(buf);
+
+			if (mod(seqno - prev) != 1)
+				buf = NULL;
+			if (seqno == gap_after)
+				break;
+			prev = seqno;
+		}
+		if (buf == NULL)
+			n_ptr->bclink.gap_to = gap_after;
+	}
+	/*
+	 * Some nodes may send a complementary NACK now:
+	 */ 
+	if (bclink_ack_allowed(sender_tag + 1)) {
+		if (n_ptr->bclink.gap_to != n_ptr->bclink.gap_after) {
+			bclink_send_nack(n_ptr);
+			bclink_set_gap(n_ptr);
+		}
+	}
+	node_unlock(n_ptr);
+}
+
+/**
+ * bclink_send_msg - broadcast a packet to all nodes in cluster
+ */
+
+int bclink_send_msg(struct sk_buff *buf)
+{
+	int res;
+
+	spin_lock_bh(&bc_lock);
+
+	res = link_send_buf(bcl, buf);
+	if (unlikely(res == -ELINKCONG))
+		buf_discard(buf);
+	else
+		bcl->stats.sent_info++;
+
+	if (bcl->out_queue_size > bcl->stats.max_queue_sz)
+		bcl->stats.max_queue_sz = bcl->out_queue_size;
+	bcl->stats.queue_sz_counts++;
+	bcl->stats.accu_queue_sz += bcl->out_queue_size;
+
+	spin_unlock_bh(&bc_lock);
+	return res;
+}
+
+/**
+ * bclink_recv_pkt - receive a broadcast packet, and deliver upwards
+ * 
+ * net_lock is read_locked, no other locks set
+ */
+
+void bclink_recv_pkt(struct sk_buff *buf)
+{        
+	struct tipc_msg *msg = buf_msg(buf);
+	struct node* node = node_find(msg_prevnode(msg));
+	u32 next_in;
+	u32 seqno;
+	struct sk_buff *deferred;
+
+	msg_dbg(msg, "<BC<<<");
+
+	if (unlikely(!node || !node_is_up(node) || !node->bclink.supported || 
+		     (msg_mc_netid(msg) != tipc_net_id))) {
+		buf_discard(buf);
+		return;
+	}
+
+	if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
+		msg_dbg(msg, "<BCNACK<<<");
+		if (msg_destnode(msg) == tipc_own_addr) {
+			node_lock(node);
+			bclink_acknowledge(node, msg_bcast_ack(msg));
+			node_unlock(node);
+			bcl->stats.recv_nacks++;
+			bclink_retransmit_pkt(msg_bcgap_after(msg),
+					      msg_bcgap_to(msg));
+		} else {
+			bclink_peek_nack(msg_destnode(msg),
+					 msg_bcast_tag(msg),
+					 msg_bcgap_after(msg),
+					 msg_bcgap_to(msg));
+		}
+		buf_discard(buf);
+		return;
+	}
+
+	node_lock(node);
+receive:
+	deferred = node->bclink.deferred_head;
+	next_in = mod(node->bclink.last_in + 1);
+	seqno = msg_seqno(msg);
+
+	if (likely(seqno == next_in)) {
+		bcl->stats.recv_info++;
+		node->bclink.last_in++;
+		bclink_set_gap(node);
+		if (unlikely(bclink_ack_allowed(seqno))) {
+			bclink_send_ack(node);
+			bcl->stats.sent_acks++;
+		}
+		if (likely(msg_isdata(msg))) {
+			node_unlock(node);
+			port_recv_mcast(buf, NULL);
+		} else if (msg_user(msg) == MSG_BUNDLER) {
+			bcl->stats.recv_bundles++;
+			bcl->stats.recv_bundled += msg_msgcnt(msg);
+			node_unlock(node);
+			link_recv_bundle(buf);
+		} else if (msg_user(msg) == MSG_FRAGMENTER) {
+			bcl->stats.recv_fragments++;
+			if (link_recv_fragment(&node->bclink.defragm,
+					       &buf, &msg))
+				bcl->stats.recv_fragmented++;
+			node_unlock(node);
+			net_route_msg(buf);
+		} else {
+			node_unlock(node);
+			net_route_msg(buf);
+		}
+		if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
+			node_lock(node);
+			buf = deferred;
+			msg = buf_msg(buf);
+			node->bclink.deferred_head = deferred->next;
+			goto receive;
+		}
+		return;
+	} else if (less(next_in, seqno)) {
+		u32 gap_after = node->bclink.gap_after;
+		u32 gap_to = node->bclink.gap_to;
+
+		if (link_defer_pkt(&node->bclink.deferred_head,
+				   &node->bclink.deferred_tail,
+				   buf)) {
+			node->bclink.nack_sync++;
+			bcl->stats.deferred_recv++;
+			if (seqno == mod(gap_after + 1))
+				node->bclink.gap_after = seqno;
+			else if (less(gap_after, seqno) && less(seqno, gap_to))
+				node->bclink.gap_to = seqno;
+		}
+		if (bclink_ack_allowed(node->bclink.nack_sync)) {
+			if (gap_to != gap_after)
+				bclink_send_nack(node);
+			bclink_set_gap(node);
+		}
+	} else {
+		bcl->stats.duplicates++;
+		buf_discard(buf);
+	}
+	node_unlock(node);
+}
+
+u32 bclink_get_last_sent(void)
+{
+	u32 last_sent = mod(bcl->next_out_no - 1);
+
+	if (bcl->next_out)
+		last_sent = mod(buf_seqno(bcl->next_out) - 1);
+	return last_sent;
+}
+
+u32 bclink_acks_missing(struct node *n_ptr)
+{
+	return (n_ptr->bclink.supported &&
+		(bclink_get_last_sent() != n_ptr->bclink.acked));
+}
+
+
+/**
+ * bcbearer_send - send a packet through the broadcast pseudo-bearer
+ * 
+ * Send through as many bearers as necessary to reach all nodes
+ * that support TIPC multicasting.
+ * 
+ * Returns 0 if packet sent successfully, non-zero if not
+ */
+
+int bcbearer_send(struct sk_buff *buf,
+		  struct tipc_bearer *unused1,
+		  struct tipc_media_addr *unused2)
+{
+	static int send_count = 0;
+
+	struct node_map remains;
+	struct node_map remains_new;
+	int bp_index;
+	int swap_time;
+
+	/* Prepare buffer for broadcasting (if first time trying to send it) */
+
+	if (likely(!msg_non_seq(buf_msg(buf)))) {
+		struct tipc_msg *msg;
+
+		assert(cluster_bcast_nodes.count != 0);
+		bcbuf_set_acks(buf, cluster_bcast_nodes.count);
+		msg = buf_msg(buf);
+		msg_set_non_seq(msg);
+		msg_set_mc_netid(msg, tipc_net_id);
+	}
+
+	/* Determine if bearer pairs should be swapped following this attempt */
+
+	if ((swap_time = (++send_count >= 10)))
+		send_count = 0;
+
+	/* Send buffer over bearers until all targets reached */
+	
+	remains = cluster_bcast_nodes;
+
+	for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
+		struct bearer *p = bcbearer->bpairs[bp_index].primary;
+		struct bearer *s = bcbearer->bpairs[bp_index].secondary;
+
+		if (!p)
+			break;	/* no more bearers to try */
+
+		nmap_diff(&remains, &p->nodes, &remains_new);
+		if (remains_new.count == remains.count)
+			continue;	/* bearer pair doesn't add anything */
+
+		if (!p->publ.blocked &&
+		    !p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
+			if (swap_time && s && !s->publ.blocked)
+				goto swap;
+			else
+				goto update;
+		}
+
+		if (!s || s->publ.blocked ||
+		    s->media->send_msg(buf, &s->publ, &s->media->bcast_addr))
+			continue;	/* unable to send using bearer pair */
+swap:
+		bcbearer->bpairs[bp_index].primary = s;
+		bcbearer->bpairs[bp_index].secondary = p;
+update:
+		if (remains_new.count == 0)
+			return TIPC_OK;
+
+		remains = remains_new;
+	}
+	
+	/* Unable to reach all targets */
+
+	bcbearer->bearer.publ.blocked = 1;
+	bcl->stats.bearer_congs++;
+	return ~TIPC_OK;
+}
+
+/**
+ * bcbearer_sort - create sets of bearer pairs used by broadcast bearer
+ */
+
+void bcbearer_sort(void)
+{
+	struct bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
+	struct bcbearer_pair *bp_curr;
+	int b_index;
+	int pri;
+
+	spin_lock_bh(&bc_lock);
+
+	/* Group bearers by priority (can assume max of two per priority) */
+
+	memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
+
+	for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
+		struct bearer *b = &bearers[b_index];
+
+		if (!b->active || !b->nodes.count)
+			continue;
+
+		if (!bp_temp[b->priority].primary)
+			bp_temp[b->priority].primary = b;
+		else
+			bp_temp[b->priority].secondary = b;
+	}
+
+	/* Create array of bearer pairs for broadcasting */
+
+	bp_curr = bcbearer->bpairs;
+	memset(bcbearer->bpairs, 0, sizeof(bcbearer->bpairs));
+
+	for (pri = (TIPC_NUM_LINK_PRI - 1); pri >= 0; pri--) {
+
+		if (!bp_temp[pri].primary)
+			continue;
+
+		bp_curr->primary = bp_temp[pri].primary;
+
+		if (bp_temp[pri].secondary) {
+			if (nmap_equal(&bp_temp[pri].primary->nodes,
+				       &bp_temp[pri].secondary->nodes)) {
+				bp_curr->secondary = bp_temp[pri].secondary;
+			} else {
+				bp_curr++;
+				bp_curr->primary = bp_temp[pri].secondary;
+			}
+		}
+
+		bp_curr++;
+	}
+
+	spin_unlock_bh(&bc_lock);
+}
+
+/**
+ * bcbearer_push - resolve bearer congestion
+ * 
+ * Forces bclink to push out any unsent packets, until all packets are gone
+ * or congestion reoccurs.
+ * No locks set when function called
+ */
+
+void bcbearer_push(void)
+{
+	struct bearer *b_ptr;
+
+	spin_lock_bh(&bc_lock);
+	b_ptr = &bcbearer->bearer;
+	if (b_ptr->publ.blocked) {
+		b_ptr->publ.blocked = 0;
+		bearer_lock_push(b_ptr);
+	}
+	spin_unlock_bh(&bc_lock);
+}
+
+
+int bclink_stats(char *buf, const u32 buf_size)
+{
+	struct print_buf pb;
+
+	if (!bcl)
+		return 0;
+
+	printbuf_init(&pb, buf, buf_size);
+
+	spin_lock_bh(&bc_lock);
+
+	tipc_printf(&pb, "Link <%s>\n"
+		         "  Window:%u packets\n", 
+		    bcl->name, bcl->queue_limit[0]);
+	tipc_printf(&pb, "  RX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+		    bcl->stats.recv_info,
+		    bcl->stats.recv_fragments,
+		    bcl->stats.recv_fragmented,
+		    bcl->stats.recv_bundles,
+		    bcl->stats.recv_bundled);
+	tipc_printf(&pb, "  TX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+		    bcl->stats.sent_info,
+		    bcl->stats.sent_fragments,
+		    bcl->stats.sent_fragmented, 
+		    bcl->stats.sent_bundles,
+		    bcl->stats.sent_bundled);
+	tipc_printf(&pb, "  RX naks:%u defs:%u dups:%u\n", 
+		    bcl->stats.recv_nacks,
+		    bcl->stats.deferred_recv, 
+		    bcl->stats.duplicates);
+	tipc_printf(&pb, "  TX naks:%u acks:%u dups:%u\n", 
+		    bcl->stats.sent_nacks, 
+		    bcl->stats.sent_acks, 
+		    bcl->stats.retransmitted);
+	tipc_printf(&pb, "  Congestion bearer:%u link:%u  Send queue max:%u avg:%u\n",
+		    bcl->stats.bearer_congs,
+		    bcl->stats.link_congs,
+		    bcl->stats.max_queue_sz,
+		    bcl->stats.queue_sz_counts
+		    ? (bcl->stats.accu_queue_sz / bcl->stats.queue_sz_counts)
+		    : 0);
+
+	spin_unlock_bh(&bc_lock);
+	return printbuf_validate(&pb);
+}
+
+int bclink_reset_stats(void)
+{
+	if (!bcl)
+		return -ENOPROTOOPT;
+
+	spin_lock_bh(&bc_lock);
+	memset(&bcl->stats, 0, sizeof(bcl->stats));
+	spin_unlock_bh(&bc_lock);
+	return TIPC_OK;
+}
+
+int bclink_set_queue_limits(u32 limit)
+{
+	if (!bcl)
+		return -ENOPROTOOPT;
+	if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
+		return -EINVAL;
+
+	spin_lock_bh(&bc_lock);
+	link_set_queue_limits(bcl, limit);
+	spin_unlock_bh(&bc_lock);
+	return TIPC_OK;
+}
+
+int bclink_init(void)
+{
+	bcbearer = kmalloc(sizeof(*bcbearer), GFP_ATOMIC);
+	bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC);
+	if (!bcbearer || !bclink) {
+ nomem:
+	 	warn("Memory squeeze; Failed to create multicast link\n");
+		kfree(bcbearer);
+		bcbearer = NULL;
+		kfree(bclink);
+		bclink = NULL;
+		return -ENOMEM;
+	}
+
+	memset(bcbearer, 0, sizeof(struct bcbearer));
+	INIT_LIST_HEAD(&bcbearer->bearer.cong_links);
+	bcbearer->bearer.media = &bcbearer->media;
+	bcbearer->media.send_msg = bcbearer_send;
+	sprintf(bcbearer->media.name, "tipc-multicast");
+
+	bcl = &bclink->link;
+	memset(bclink, 0, sizeof(struct bclink));
+	INIT_LIST_HEAD(&bcl->waiting_ports);
+	bcl->next_out_no = 1;
+	bclink->node.lock =  SPIN_LOCK_UNLOCKED;        
+	bcl->owner = &bclink->node;
+        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
+	link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
+	bcl->b_ptr = &bcbearer->bearer;
+	bcl->state = WORKING_WORKING;
+	sprintf(bcl->name, bc_link_name);
+
+	if (BCLINK_LOG_BUF_SIZE) {
+		char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC);
+
+		if (!pb)
+			goto nomem;
+		printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE);
+	}
+
+	return TIPC_OK;
+}
+
+void bclink_stop(void)
+{
+	spin_lock_bh(&bc_lock);
+	if (bcbearer) {
+		link_stop(bcl);
+		if (BCLINK_LOG_BUF_SIZE)
+			kfree(bcl->print_buf.buf);
+		bcl = NULL;
+		kfree(bclink);
+		bclink = NULL;
+		kfree(bcbearer);
+		bcbearer = NULL;
+	}
+	spin_unlock_bh(&bc_lock);
+}
+
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
new file mode 100644
index 0000000..5430e52
--- /dev/null
+++ b/net/tipc/bcast.h
@@ -0,0 +1,223 @@
+/*
+ * net/tipc/bcast.h: Include file for TIPC broadcast code
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_BCAST_H
+#define _TIPC_BCAST_H
+
+#define MAX_NODES 4096
+#define WSIZE 32
+
+/**
+ * struct node_map - set of node identifiers
+ * @count: # of nodes in set
+ * @map: bitmap of node identifiers that are in the set
+ */
+
+struct node_map {
+	u32 count;
+	u32 map[MAX_NODES / WSIZE];
+};
+
+
+#define PLSIZE 32
+
+/**
+ * struct port_list - set of node local destination ports
+ * @count: # of ports in set (only valid for first entry in list)
+ * @next: pointer to next entry in list
+ * @ports: array of port references
+ */
+
+struct port_list {
+	int count;
+	struct port_list *next;
+	u32 ports[PLSIZE];
+};
+
+
+struct node;
+
+extern char bc_link_name[];
+
+
+/**
+ * nmap_get - determine if node exists in a node map
+ */
+
+static inline int nmap_get(struct node_map *nm_ptr, u32 node)
+{
+	int n = tipc_node(node);
+	int w = n / WSIZE;
+	int b = n % WSIZE;
+
+	return nm_ptr->map[w] & (1 << b);
+}
+
+/**
+ * nmap_add - add a node to a node map
+ */
+
+static inline void nmap_add(struct node_map *nm_ptr, u32 node)
+{
+	int n = tipc_node(node);
+	int w = n / WSIZE;
+	u32 mask = (1 << (n % WSIZE));
+
+	if ((nm_ptr->map[w] & mask) == 0) {
+		nm_ptr->count++;
+		nm_ptr->map[w] |= mask;
+	}
+}
+
+/** 
+ * nmap_remove - remove a node from a node map
+ */
+
+static inline void nmap_remove(struct node_map *nm_ptr, u32 node)
+{
+	int n = tipc_node(node);
+	int w = n / WSIZE;
+	u32 mask = (1 << (n % WSIZE));
+
+	if ((nm_ptr->map[w] & mask) != 0) {
+		nm_ptr->map[w] &= ~mask;
+		nm_ptr->count--;
+	}
+}
+
+/**
+ * nmap_equal - test for equality of node maps
+ */
+
+static inline int nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
+{
+	return !memcmp(nm_a, nm_b, sizeof(*nm_a));
+}
+
+/**
+ * nmap_diff - find differences between node maps
+ * @nm_a: input node map A
+ * @nm_b: input node map B
+ * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
+ */
+
+static inline void nmap_diff(struct node_map *nm_a, struct node_map *nm_b,
+			     struct node_map *nm_diff)
+{
+	int stop = sizeof(nm_a->map) / sizeof(u32);
+	int w;
+	int b;
+	u32 map;
+
+	memset(nm_diff, 0, sizeof(*nm_diff));
+	for (w = 0; w < stop; w++) {
+		map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
+		nm_diff->map[w] = map;
+		if (map != 0) {
+			for (b = 0 ; b < WSIZE; b++) {
+				if (map & (1 << b))
+					nm_diff->count++;
+			}
+		}
+	}
+}
+
+/**
+ * port_list_add - add a port to a port list, ensuring no duplicates
+ */
+
+static inline void port_list_add(struct port_list *pl_ptr, u32 port)
+{
+	struct port_list *item = pl_ptr;
+	int i;
+	int item_sz = PLSIZE;
+	int cnt = pl_ptr->count;
+
+	for (; ; cnt -= item_sz, item = item->next) {
+		if (cnt < PLSIZE)
+			item_sz = cnt;
+		for (i = 0; i < item_sz; i++)
+			if (item->ports[i] == port)
+				return;
+		if (i < PLSIZE) {
+			item->ports[i] = port;
+			pl_ptr->count++;
+			return;
+		}
+		if (!item->next) {
+			item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
+			if (!item->next) {
+				warn("Memory squeeze: multicast destination port list is incomplete\n");
+				return;
+			}
+			item->next->next = NULL;
+		}
+	}
+}
+
+/**
+ * port_list_free - free dynamically created entries in port_list chain
+ * 
+ * Note: First item is on stack, so it doesn't need to be released
+ */
+
+static inline void port_list_free(struct port_list *pl_ptr)
+{
+	struct port_list *item;
+	struct port_list *next;
+
+	for (item = pl_ptr->next; item; item = next) {
+		next = item->next;
+		kfree(item);
+	}
+}
+
+
+int  bclink_init(void);
+void bclink_stop(void);
+void bclink_acknowledge(struct node *n_ptr, u32 acked);
+int  bclink_send_msg(struct sk_buff *buf);
+void bclink_recv_pkt(struct sk_buff *buf);
+u32  bclink_get_last_sent(void);
+u32  bclink_acks_missing(struct node *n_ptr);
+void bclink_check_gap(struct node *n_ptr, u32 seqno);
+int  bclink_stats(char *stats_buf, const u32 buf_size);
+int  bclink_reset_stats(void);
+int  bclink_set_queue_limits(u32 limit);
+void bcbearer_sort(void);
+void bcbearer_push(void);
+
+#endif
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
new file mode 100644
index 0000000..3dd19fd
--- /dev/null
+++ b/net/tipc/bearer.c
@@ -0,0 +1,692 @@
+/*
+ * net/tipc/bearer.c: TIPC bearer code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "bearer.h"
+#include "link.h"
+#include "port.h"
+#include "discover.h"
+#include "bcast.h"
+
+#define MAX_ADDR_STR 32
+
+static struct media *media_list = 0;
+static u32 media_count = 0;
+
+struct bearer *bearers = 0;
+
+/**
+ * media_name_valid - validate media name
+ * 
+ * Returns 1 if media name is valid, otherwise 0.
+ */
+
+static int media_name_valid(const char *name)
+{
+	u32 len;
+
+	len = strlen(name);
+	if ((len + 1) > TIPC_MAX_MEDIA_NAME)
+		return 0;
+	return (strspn(name, tipc_alphabet) == len);
+}
+
+/**
+ * media_find - locates specified media object by name
+ */
+
+static struct media *media_find(const char *name)
+{
+	struct media *m_ptr;
+	u32 i;
+
+	for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+		if (!strcmp(m_ptr->name, name))
+			return m_ptr;
+	}
+	return 0;
+}
+
+/**
+ * tipc_register_media - register a media type
+ * 
+ * Bearers for this media type must be activated separately at a later stage.
+ */
+
+int  tipc_register_media(u32 media_type,
+			 char *name, 
+			 int (*enable)(struct tipc_bearer *), 
+			 void (*disable)(struct tipc_bearer *), 
+			 int (*send_msg)(struct sk_buff *, 
+					 struct tipc_bearer *,
+					 struct tipc_media_addr *), 
+			 char *(*addr2str)(struct tipc_media_addr *a,
+					   char *str_buf, int str_size),
+			 struct tipc_media_addr *bcast_addr,
+			 const u32 bearer_priority,
+			 const u32 link_tolerance,  /* [ms] */
+			 const u32 send_window_limit)
+{
+	struct media *m_ptr;
+	u32 media_id;
+	u32 i;
+	int res = -EINVAL;
+
+	write_lock_bh(&net_lock);
+	if (!media_list)
+		goto exit;
+
+	if (!media_name_valid(name)) {
+		warn("Media registration error: illegal name <%s>\n", name);
+		goto exit;
+	}
+	if (!bcast_addr) {
+		warn("Media registration error: no broadcast address supplied\n");
+		goto exit;
+	}
+	if (bearer_priority >= TIPC_NUM_LINK_PRI) {
+		warn("Media registration error: priority %u\n", bearer_priority);
+		goto exit;
+	}
+	if ((link_tolerance < TIPC_MIN_LINK_TOL) || 
+	    (link_tolerance > TIPC_MAX_LINK_TOL)) {
+		warn("Media registration error: tolerance %u\n", link_tolerance);
+		goto exit;
+	}
+
+	media_id = media_count++;
+	if (media_id >= MAX_MEDIA) {
+		warn("Attempt to register more than %u media\n", MAX_MEDIA);
+		media_count--;
+		goto exit;
+	}
+	for (i = 0; i < media_id; i++) {
+		if (media_list[i].type_id == media_type) {
+			warn("Attempt to register second media with type %u\n", 
+			     media_type);
+			media_count--;
+			goto exit;
+		}
+		if (!strcmp(name, media_list[i].name)) {
+			warn("Attempt to re-register media name <%s>\n", name);
+			media_count--;
+			goto exit;
+		}
+	}
+
+	m_ptr = &media_list[media_id];
+	m_ptr->type_id = media_type;
+	m_ptr->send_msg = send_msg;
+	m_ptr->enable_bearer = enable;
+	m_ptr->disable_bearer = disable;
+	m_ptr->addr2str = addr2str;
+	memcpy(&m_ptr->bcast_addr, bcast_addr, sizeof(*bcast_addr));
+	m_ptr->bcast = 1;
+	strcpy(m_ptr->name, name);
+	m_ptr->priority = bearer_priority;
+	m_ptr->tolerance = link_tolerance;
+	m_ptr->window = send_window_limit;
+	dbg("Media <%s> registered\n", name);
+	res = 0;
+exit:
+	write_unlock_bh(&net_lock);
+	return res;
+}
+
+/**
+ * media_addr_printf - record media address in print buffer
+ */
+
+void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
+{
+	struct media *m_ptr;
+	u32 media_type;
+	u32 i;
+
+	media_type = ntohl(a->type);
+	for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+		if (m_ptr->type_id == media_type)
+			break;
+	}
+
+	if ((i < media_count) && (m_ptr->addr2str != NULL)) {
+		char addr_str[MAX_ADDR_STR];
+
+		tipc_printf(pb, "%s(%s) ", m_ptr->name, 
+			    m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
+	} else {
+		unchar *addr = (unchar *)&a->dev_addr;
+
+		tipc_printf(pb, "UNKNOWN(%u):", media_type);
+		for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
+			tipc_printf(pb, "%02x ", addr[i]);
+		}
+	}
+}
+
+/**
+ * media_get_names - record names of registered media in buffer
+ */
+
+struct sk_buff *media_get_names(void)
+{
+	struct sk_buff *buf;
+	struct media *m_ptr;
+	int i;
+
+	buf = cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
+	if (!buf)
+		return NULL;
+
+	read_lock_bh(&net_lock);
+	for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+		cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, m_ptr->name, 
+			       strlen(m_ptr->name) + 1);
+	}
+	read_unlock_bh(&net_lock);
+	return buf;
+}
+
+/**
+ * bearer_name_validate - validate & (optionally) deconstruct bearer name
+ * @name - ptr to bearer name string
+ * @name_parts - ptr to area for bearer name components (or NULL if not needed)
+ * 
+ * Returns 1 if bearer name is valid, otherwise 0.
+ */
+
+static int bearer_name_validate(const char *name, 
+				struct bearer_name *name_parts)
+{
+	char name_copy[TIPC_MAX_BEARER_NAME];
+	char *media_name;
+	char *if_name;
+	u32 media_len;
+	u32 if_len;
+
+	/* copy bearer name & ensure length is OK */
+
+	name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
+	/* need above in case non-Posix strncpy() doesn't pad with nulls */
+	strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
+	if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
+		return 0;
+
+	/* ensure all component parts of bearer name are present */
+
+	media_name = name_copy;
+	if ((if_name = strchr(media_name, ':')) == NULL)
+		return 0;
+	*(if_name++) = 0;
+	media_len = if_name - media_name;
+	if_len = strlen(if_name) + 1;
+
+	/* validate component parts of bearer name */
+
+	if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) || 
+	    (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) || 
+	    (strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
+	    (strspn(if_name, tipc_alphabet) != (if_len - 1)))
+		return 0;
+
+	/* return bearer name components, if necessary */
+
+	if (name_parts) {
+		strcpy(name_parts->media_name, media_name);
+		strcpy(name_parts->if_name, if_name);
+	}
+	return 1;
+}
+
+/**
+ * bearer_find - locates bearer object with matching bearer name
+ */
+
+static struct bearer *bearer_find(const char *name)
+{
+	struct bearer *b_ptr;
+	u32 i;
+
+	for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
+		if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
+			return b_ptr;
+	}
+	return 0;
+}
+
+/**
+ * bearer_find - locates bearer object with matching interface name
+ */
+
+struct bearer *bearer_find_interface(const char *if_name)
+{
+	struct bearer *b_ptr;
+	char *b_if_name;
+	u32 i;
+
+	for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
+		if (!b_ptr->active)
+			continue;
+		b_if_name = strchr(b_ptr->publ.name, ':') + 1;
+		if (!strcmp(b_if_name, if_name))
+			return b_ptr;
+	}
+	return 0;
+}
+
+/**
+ * bearer_get_names - record names of bearers in buffer
+ */
+
+struct sk_buff *bearer_get_names(void)
+{
+	struct sk_buff *buf;
+	struct media *m_ptr;
+	struct bearer *b_ptr;
+	int i, j;
+
+	buf = cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
+	if (!buf)
+		return NULL;
+
+	read_lock_bh(&net_lock);
+	for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+		for (j = 0; j < MAX_BEARERS; j++) {
+			b_ptr = &bearers[j];
+			if (b_ptr->active && (b_ptr->media == m_ptr)) {
+				cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, 
+					       b_ptr->publ.name, 
+					       strlen(b_ptr->publ.name) + 1);
+			}
+		}
+	}
+	read_unlock_bh(&net_lock);
+	return buf;
+}
+
+void bearer_add_dest(struct bearer *b_ptr, u32 dest)
+{
+	nmap_add(&b_ptr->nodes, dest);
+	disc_update_link_req(b_ptr->link_req);
+	bcbearer_sort();
+}
+
+void bearer_remove_dest(struct bearer *b_ptr, u32 dest)
+{
+	nmap_remove(&b_ptr->nodes, dest);
+	disc_update_link_req(b_ptr->link_req);
+	bcbearer_sort();
+}
+
+/*
+ * bearer_push(): Resolve bearer congestion. Force the waiting
+ * links to push out their unsent packets, one packet per link
+ * per iteration, until all packets are gone or congestion reoccurs.
+ * 'net_lock' is read_locked when this function is called
+ * bearer.lock must be taken before calling
+ * Returns binary true(1) ore false(0)
+ */
+static int bearer_push(struct bearer *b_ptr)
+{
+	u32 res = TIPC_OK;
+	struct link *ln, *tln;
+
+	if (b_ptr->publ.blocked)
+		return 0;
+
+	while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
+		list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
+			res = link_push_packet(ln);
+			if (res == PUSH_FAILED)
+				break;
+			if (res == PUSH_FINISHED)
+				list_move_tail(&ln->link_list, &b_ptr->links);
+		}
+	}
+	return list_empty(&b_ptr->cong_links);
+}
+
+void bearer_lock_push(struct bearer *b_ptr)
+{
+	int res;
+
+	spin_lock_bh(&b_ptr->publ.lock);
+	res = bearer_push(b_ptr);
+	spin_unlock_bh(&b_ptr->publ.lock);
+	if (res)
+		bcbearer_push();
+}
+
+
+/*
+ * Interrupt enabling new requests after bearer congestion or blocking:    
+ * See bearer_send().   
+ */
+void tipc_continue(struct tipc_bearer *tb_ptr)
+{
+	struct bearer *b_ptr = (struct bearer *)tb_ptr;
+
+	spin_lock_bh(&b_ptr->publ.lock);
+	b_ptr->continue_count++;
+	if (!list_empty(&b_ptr->cong_links))
+		k_signal((Handler)bearer_lock_push, (unsigned long)b_ptr);
+	b_ptr->publ.blocked = 0;
+	spin_unlock_bh(&b_ptr->publ.lock);
+}
+
+/*
+ * Schedule link for sending of messages after the bearer 
+ * has been deblocked by 'continue()'. This method is called 
+ * when somebody tries to send a message via this link while 
+ * the bearer is congested. 'net_lock' is in read_lock here
+ * bearer.lock is busy
+ */
+
+static void bearer_schedule_unlocked(struct bearer *b_ptr, struct link *l_ptr)
+{
+	list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
+}
+
+/*
+ * Schedule link for sending of messages after the bearer 
+ * has been deblocked by 'continue()'. This method is called 
+ * when somebody tries to send a message via this link while 
+ * the bearer is congested. 'net_lock' is in read_lock here,
+ * bearer.lock is free
+ */
+
+void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr)
+{
+	spin_lock_bh(&b_ptr->publ.lock);
+	bearer_schedule_unlocked(b_ptr, l_ptr);
+	spin_unlock_bh(&b_ptr->publ.lock);
+}
+
+
+/*
+ * bearer_resolve_congestion(): Check if there is bearer congestion,
+ * and if there is, try to resolve it before returning.
+ * 'net_lock' is read_locked when this function is called
+ */
+int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr)
+{
+	int res = 1;
+
+	if (list_empty(&b_ptr->cong_links))
+		return 1;
+	spin_lock_bh(&b_ptr->publ.lock);
+	if (!bearer_push(b_ptr)) {
+		bearer_schedule_unlocked(b_ptr, l_ptr);
+		res = 0;
+	}
+	spin_unlock_bh(&b_ptr->publ.lock);
+	return res;
+}
+
+
+/**
+ * tipc_enable_bearer - enable bearer with the given name
+ */              
+
+int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
+{
+	struct bearer *b_ptr;
+	struct media *m_ptr;
+	struct bearer_name b_name;
+	char addr_string[16];
+	u32 bearer_id;
+	u32 with_this_prio;
+	u32 i;
+	int res = -EINVAL;
+
+	if (tipc_mode != TIPC_NET_MODE)
+		return -ENOPROTOOPT;
+	if (!bearer_name_validate(name, &b_name) ||
+	    !addr_domain_valid(bcast_scope) ||
+	    !in_scope(bcast_scope, tipc_own_addr) ||
+	    (priority > TIPC_NUM_LINK_PRI))
+		return -EINVAL;
+
+	write_lock_bh(&net_lock);
+	if (!bearers)
+		goto failed;
+
+	m_ptr = media_find(b_name.media_name);
+	if (!m_ptr) {
+		warn("No media <%s>\n", b_name.media_name);
+		goto failed;
+	}
+	if (priority == TIPC_NUM_LINK_PRI)
+		priority = m_ptr->priority;
+
+restart:
+	bearer_id = MAX_BEARERS;
+	with_this_prio = 1;
+	for (i = MAX_BEARERS; i-- != 0; ) {
+		if (!bearers[i].active) {
+			bearer_id = i;
+			continue;
+		}
+		if (!strcmp(name, bearers[i].publ.name)) {
+			warn("Bearer <%s> already enabled\n", name);
+			goto failed;
+		}
+		if ((bearers[i].priority == priority) &&
+		    (++with_this_prio > 2)) {
+			if (priority-- == 0) {
+				warn("Third bearer <%s> with priority %u, unable to lower to %u\n",
+				     name, priority + 1, priority);
+				goto failed;
+			}
+			warn("Third bearer <%s> with priority %u, lowering to %u\n",
+			     name, priority + 1, priority);
+			goto restart;
+		}
+	}
+	if (bearer_id >= MAX_BEARERS) {
+		warn("Attempt to enable more than %d bearers\n", MAX_BEARERS);
+		goto failed;
+	}
+
+	b_ptr = &bearers[bearer_id];
+	memset(b_ptr, 0, sizeof(struct bearer));
+
+	strcpy(b_ptr->publ.name, name);
+	res = m_ptr->enable_bearer(&b_ptr->publ);
+	if (res) {
+		warn("Failed to enable bearer <%s>\n", name);
+		goto failed;
+	}
+
+	b_ptr->identity = bearer_id;
+	b_ptr->media = m_ptr;
+	b_ptr->net_plane = bearer_id + 'A';
+	b_ptr->active = 1;
+	b_ptr->detect_scope = bcast_scope;
+	b_ptr->priority = priority;
+	INIT_LIST_HEAD(&b_ptr->cong_links);
+	INIT_LIST_HEAD(&b_ptr->links);
+	if (m_ptr->bcast) {
+		b_ptr->link_req = disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
+						     bcast_scope, 2);
+	}
+	b_ptr->publ.lock = SPIN_LOCK_UNLOCKED;
+	write_unlock_bh(&net_lock);
+	info("Enabled bearer <%s>, discovery domain %s\n",
+	     name, addr_string_fill(addr_string, bcast_scope));
+	return 0;
+failed:
+	write_unlock_bh(&net_lock);
+	return res;
+}
+
+/**
+ * tipc_block_bearer(): Block the bearer with the given name,
+ *                      and reset all its links
+ */
+
+int tipc_block_bearer(const char *name)
+{
+	struct bearer *b_ptr = 0;
+	struct link *l_ptr;
+	struct link *temp_l_ptr;
+
+	if (tipc_mode != TIPC_NET_MODE)
+		return -ENOPROTOOPT;
+
+	read_lock_bh(&net_lock);
+	b_ptr = bearer_find(name);
+	if (!b_ptr) {
+		warn("Attempt to block unknown bearer <%s>\n", name);
+		read_unlock_bh(&net_lock);
+		return -EINVAL;
+	}
+
+	spin_lock_bh(&b_ptr->publ.lock);
+	b_ptr->publ.blocked = 1;
+	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
+		struct node *n_ptr = l_ptr->owner;
+
+		spin_lock_bh(&n_ptr->lock);
+		link_reset(l_ptr);
+		spin_unlock_bh(&n_ptr->lock);
+	}
+	spin_unlock_bh(&b_ptr->publ.lock);
+	read_unlock_bh(&net_lock);
+	info("Blocked bearer <%s>\n", name);
+	return TIPC_OK;
+}
+
+/**
+ * bearer_disable -
+ * 
+ * Note: This routine assumes caller holds net_lock.
+ */
+
+static int bearer_disable(const char *name)
+{
+	struct bearer *b_ptr;
+	struct link *l_ptr;
+	struct link *temp_l_ptr;
+
+	if (tipc_mode != TIPC_NET_MODE)
+		return -ENOPROTOOPT;
+
+	b_ptr = bearer_find(name);
+	if (!b_ptr) {
+		warn("Attempt to disable unknown bearer <%s>\n", name);
+		return -EINVAL;
+	}
+
+	disc_stop_link_req(b_ptr->link_req);
+	spin_lock_bh(&b_ptr->publ.lock);
+	b_ptr->link_req = NULL;
+	b_ptr->publ.blocked = 1;
+	if (b_ptr->media->disable_bearer) {
+		spin_unlock_bh(&b_ptr->publ.lock);
+		write_unlock_bh(&net_lock);
+		b_ptr->media->disable_bearer(&b_ptr->publ);
+		write_lock_bh(&net_lock);
+		spin_lock_bh(&b_ptr->publ.lock);
+	}
+	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
+		link_delete(l_ptr);
+	}
+	spin_unlock_bh(&b_ptr->publ.lock);
+	info("Disabled bearer <%s>\n", name);
+	memset(b_ptr, 0, sizeof(struct bearer));
+	return TIPC_OK;
+}
+
+int tipc_disable_bearer(const char *name)
+{
+	int res;
+
+	write_lock_bh(&net_lock);
+	res = bearer_disable(name);
+	write_unlock_bh(&net_lock);
+	return res;
+}
+
+
+
+int bearer_init(void)
+{
+	int res;
+
+	write_lock_bh(&net_lock);
+	bearers = kmalloc(MAX_BEARERS * sizeof(struct bearer), GFP_ATOMIC);
+	media_list = kmalloc(MAX_MEDIA * sizeof(struct media), GFP_ATOMIC);
+	if (bearers && media_list) {
+		memset(bearers, 0, MAX_BEARERS * sizeof(struct bearer));
+		memset(media_list, 0, MAX_MEDIA * sizeof(struct media));
+		res = TIPC_OK;
+	} else {
+		kfree(bearers);
+		kfree(media_list);
+		bearers = 0;
+		media_list = 0;
+		res = -ENOMEM;
+	}
+	write_unlock_bh(&net_lock);
+	return res;
+}
+
+void bearer_stop(void)
+{
+	u32 i;
+
+	if (!bearers)
+		return;
+
+	for (i = 0; i < MAX_BEARERS; i++) {
+		if (bearers[i].active)
+			bearers[i].publ.blocked = 1;
+	}
+	for (i = 0; i < MAX_BEARERS; i++) {
+		if (bearers[i].active)
+			bearer_disable(bearers[i].publ.name);
+	}
+	kfree(bearers);
+	kfree(media_list);
+	bearers = 0;
+	media_list = 0;
+	media_count = 0;
+}
+
+
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
new file mode 100644
index 0000000..21e63d3
--- /dev/null
+++ b/net/tipc/bearer.h
@@ -0,0 +1,172 @@
+/*
+ * net/tipc/bearer.h: Include file for TIPC bearer code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_BEARER_H
+#define _TIPC_BEARER_H
+
+#include <net/tipc/tipc_bearer.h>
+#include "bcast.h"
+
+#define MAX_BEARERS 8
+#define MAX_MEDIA 4
+
+
+/**
+ * struct media - TIPC media information available to internal users
+ * @send_msg: routine which handles buffer transmission
+ * @enable_bearer: routine which enables a bearer
+ * @disable_bearer: routine which disables a bearer
+ * @addr2str: routine which converts bearer's address to string form
+ * @bcast_addr: media address used in broadcasting
+ * @bcast: non-zero if media supports broadcasting [currently mandatory]
+ * @priority: default link (and bearer) priority
+ * @tolerance: default time (in ms) before declaring link failure
+ * @window: default window (in packets) before declaring link congestion
+ * @type_id: TIPC media identifier [defined in tipc_bearer.h]
+ * @name: media name
+ */
+ 
+struct media {
+	int (*send_msg)(struct sk_buff *buf, 
+			struct tipc_bearer *b_ptr,
+			struct tipc_media_addr *dest);
+	int (*enable_bearer)(struct tipc_bearer *b_ptr);
+	void (*disable_bearer)(struct tipc_bearer *b_ptr);
+	char *(*addr2str)(struct tipc_media_addr *a, 
+			  char *str_buf, int str_size);
+	struct tipc_media_addr bcast_addr;
+	int bcast;
+	u32 priority;
+	u32 tolerance;
+	u32 window;
+	u32 type_id;
+	char name[TIPC_MAX_MEDIA_NAME];
+};
+
+/**
+ * struct bearer - TIPC bearer information available to internal users
+ * @publ: bearer information available to privileged users
+ * @media: ptr to media structure associated with bearer
+ * @priority: default link priority for bearer
+ * @detect_scope: network address mask used during automatic link creation
+ * @identity: array index of this bearer within TIPC bearer array
+ * @link_req: ptr to (optional) structure making periodic link setup requests
+ * @links: list of non-congested links associated with bearer
+ * @cong_links: list of congested links associated with bearer
+ * @continue_count: # of times bearer has resumed after congestion or blocking
+ * @active: non-zero if bearer structure is represents a bearer
+ * @net_plane: network plane ('A' through 'H') currently associated with bearer
+ * @nodes: indicates which nodes in cluster can be reached through bearer
+ */
+ 
+struct bearer {
+	struct tipc_bearer publ;
+	struct media *media;
+	u32 priority;
+	u32 detect_scope;
+	u32 identity;
+	struct link_req *link_req;
+	struct list_head links;
+	struct list_head cong_links;
+	u32 continue_count;
+	int active;
+	char net_plane;
+	struct node_map nodes;
+};
+
+struct bearer_name {
+	char media_name[TIPC_MAX_MEDIA_NAME];
+	char if_name[TIPC_MAX_IF_NAME];
+};
+
+struct link;
+
+extern struct bearer *bearers;
+
+void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
+struct sk_buff *media_get_names(void);
+
+struct sk_buff *bearer_get_names(void);
+void bearer_add_dest(struct bearer *b_ptr, u32 dest);
+void bearer_remove_dest(struct bearer *b_ptr, u32 dest);
+void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr);
+struct bearer *bearer_find_interface(const char *if_name);
+int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr);
+int bearer_init(void);
+void bearer_stop(void);
+int bearer_broadcast(struct sk_buff *buf, struct tipc_bearer *b_ptr,
+		     struct tipc_media_addr *dest);
+void bearer_lock_push(struct bearer *b_ptr);
+
+
+/**
+ * bearer_send- sends buffer to destination over bearer 
+ * 
+ * Returns true (1) if successful, or false (0) if unable to send
+ * 
+ * IMPORTANT:
+ * The media send routine must not alter the buffer being passed in
+ * as it may be needed for later retransmission!
+ * 
+ * If the media send routine returns a non-zero value (indicating that 
+ * it was unable to send the buffer), it must:
+ *   1) mark the bearer as blocked,
+ *   2) call tipc_continue() once the bearer is able to send again.
+ * Media types that are unable to meet these two critera must ensure their
+ * send routine always returns success -- even if the buffer was not sent --
+ * and let TIPC's link code deal with the undelivered message. 
+ */
+
+static inline int bearer_send(struct bearer *b_ptr, struct sk_buff *buf,
+			      struct tipc_media_addr *dest)
+{
+	return !b_ptr->media->send_msg(buf, &b_ptr->publ, dest);
+}
+
+/**
+ * bearer_congested - determines if bearer is currently congested
+ */
+
+static inline int bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
+{
+	if (unlikely(b_ptr->publ.blocked))
+		return 1;
+	if (likely(list_empty(&b_ptr->cong_links)))
+		return 0;
+	return !bearer_resolve_congestion(b_ptr, l_ptr);
+}
+
+#endif
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
new file mode 100644
index 0000000..f0f7bac
--- /dev/null
+++ b/net/tipc/cluster.c
@@ -0,0 +1,576 @@
+/*
+ * net/tipc/cluster.c: TIPC cluster management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "cluster.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "link.h"
+#include "node.h"
+#include "net.h"
+#include "msg.h"
+#include "bearer.h"
+
+void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
+		       u32 lower, u32 upper);
+struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest);
+
+struct node **local_nodes = 0;
+struct node_map cluster_bcast_nodes = {0,{0,}};
+u32 highest_allowed_slave = 0;
+
+struct cluster *cluster_create(u32 addr)
+{
+	struct _zone *z_ptr;
+	struct cluster *c_ptr;
+	int max_nodes; 
+	int alloc;
+
+	c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
+	if (c_ptr == NULL)
+		return 0;
+	memset(c_ptr, 0, sizeof(*c_ptr));
+
+	c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
+	if (in_own_cluster(addr))
+		max_nodes = LOWEST_SLAVE + tipc_max_slaves;
+	else
+		max_nodes = tipc_max_nodes + 1;
+	alloc = sizeof(void *) * (max_nodes + 1);
+	c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
+	if (c_ptr->nodes == NULL) {
+		kfree(c_ptr);
+		return 0;
+	}
+	memset(c_ptr->nodes, 0, alloc);  
+	if (in_own_cluster(addr))
+		local_nodes = c_ptr->nodes;
+	c_ptr->highest_slave = LOWEST_SLAVE - 1;
+	c_ptr->highest_node = 0;
+	
+	z_ptr = zone_find(tipc_zone(addr));
+	if (z_ptr == NULL) {
+		z_ptr = zone_create(addr);
+	}
+	if (z_ptr != NULL) {
+		zone_attach_cluster(z_ptr, c_ptr);
+		c_ptr->owner = z_ptr;
+	}
+	else {
+		kfree(c_ptr);
+		c_ptr = 0;
+	}
+
+	return c_ptr;
+}
+
+void cluster_delete(struct cluster *c_ptr)
+{
+	u32 n_num;
+
+	if (!c_ptr)
+		return;
+	for (n_num = 1; n_num <= c_ptr->highest_node; n_num++) {
+		node_delete(c_ptr->nodes[n_num]);
+	}
+	for (n_num = LOWEST_SLAVE; n_num <= c_ptr->highest_slave; n_num++) {
+		node_delete(c_ptr->nodes[n_num]);
+	}
+	kfree(c_ptr->nodes);
+	kfree(c_ptr);
+}
+
+u32 cluster_next_node(struct cluster *c_ptr, u32 addr)
+{
+	struct node *n_ptr;
+	u32 n_num = tipc_node(addr) + 1;
+
+	if (!c_ptr)
+		return addr;
+	for (; n_num <= c_ptr->highest_node; n_num++) {
+		n_ptr = c_ptr->nodes[n_num];
+		if (n_ptr && node_has_active_links(n_ptr))
+			return n_ptr->addr;
+	}
+	for (n_num = 1; n_num < tipc_node(addr); n_num++) {
+		n_ptr = c_ptr->nodes[n_num];
+		if (n_ptr && node_has_active_links(n_ptr))
+			return n_ptr->addr;
+	}
+	return 0;
+}
+
+void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr)
+{
+	u32 n_num = tipc_node(n_ptr->addr);
+	u32 max_n_num = tipc_max_nodes;
+
+	if (in_own_cluster(n_ptr->addr))
+		max_n_num = highest_allowed_slave;
+	assert(n_num > 0);
+	assert(n_num <= max_n_num);
+	assert(c_ptr->nodes[n_num] == 0);
+	c_ptr->nodes[n_num] = n_ptr;
+	if (n_num > c_ptr->highest_node)
+		c_ptr->highest_node = n_num;
+}
+
+/**
+ * cluster_select_router - select router to a cluster
+ * 
+ * Uses deterministic and fair algorithm.
+ */
+
+u32 cluster_select_router(struct cluster *c_ptr, u32 ref)
+{
+	u32 n_num;
+	u32 ulim = c_ptr->highest_node;
+	u32 mask;
+	u32 tstart;
+
+	assert(!in_own_cluster(c_ptr->addr));
+	if (!ulim)
+		return 0;
+
+	/* Start entry must be random */
+	mask = tipc_max_nodes;
+	while (mask > ulim)
+		mask >>= 1;
+	tstart = ref & mask;
+	n_num = tstart;
+
+	/* Lookup upwards with wrap-around */
+	do {
+		if (node_is_up(c_ptr->nodes[n_num]))
+			break;
+	} while (++n_num <= ulim);
+	if (n_num > ulim) {
+		n_num = 1;
+		do {
+			if (node_is_up(c_ptr->nodes[n_num]))
+				break;
+		} while (++n_num < tstart);
+		if (n_num == tstart)
+			return 0;
+	}
+	assert(n_num <= ulim);
+	return node_select_router(c_ptr->nodes[n_num], ref);
+}
+
+/**
+ * cluster_select_node - select destination node within a remote cluster
+ * 
+ * Uses deterministic and fair algorithm.
+ */
+
+struct node *cluster_select_node(struct cluster *c_ptr, u32 selector)
+{
+	u32 n_num;
+	u32 mask = tipc_max_nodes;
+	u32 start_entry;
+
+	assert(!in_own_cluster(c_ptr->addr));
+	if (!c_ptr->highest_node)
+		return 0;
+
+	/* Start entry must be random */
+	while (mask > c_ptr->highest_node) {
+		mask >>= 1;
+	}
+	start_entry = (selector & mask) ? selector & mask : 1u;
+	assert(start_entry <= c_ptr->highest_node);
+
+	/* Lookup upwards with wrap-around */
+	for (n_num = start_entry; n_num <= c_ptr->highest_node; n_num++) {
+		if (node_has_active_links(c_ptr->nodes[n_num]))
+			return c_ptr->nodes[n_num];
+	}
+	for (n_num = 1; n_num < start_entry; n_num++) {
+		if (node_has_active_links(c_ptr->nodes[n_num]))
+			return c_ptr->nodes[n_num];
+	}
+	return 0;
+}
+
+/*
+ *    Routing table management: See description in node.c
+ */
+
+struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest)
+{
+	u32 size = INT_H_SIZE + data_size;
+	struct sk_buff *buf = buf_acquire(size);
+	struct tipc_msg *msg;
+
+	if (buf) {
+		msg = buf_msg(buf);
+		memset((char *)msg, 0, size);
+		msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
+	}
+	return buf;
+}
+
+void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest,
+			     u32 lower, u32 upper)
+{
+	struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
+	struct tipc_msg *msg;
+
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_set_remote_node(msg, dest);
+		msg_set_type(msg, ROUTE_ADDITION);
+		cluster_multicast(c_ptr, buf, lower, upper);
+	} else {
+		warn("Memory squeeze: broadcast of new route failed\n");
+	}
+}
+
+void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest,
+			      u32 lower, u32 upper)
+{
+	struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
+	struct tipc_msg *msg;
+
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_set_remote_node(msg, dest);
+		msg_set_type(msg, ROUTE_REMOVAL);
+		cluster_multicast(c_ptr, buf, lower, upper);
+	} else {
+		warn("Memory squeeze: broadcast of lost route failed\n");
+	}
+}
+
+void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest)
+{
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	u32 highest = c_ptr->highest_slave;
+	u32 n_num;
+	int send = 0;
+
+	assert(!is_slave(dest));
+	assert(in_own_cluster(dest));
+	assert(in_own_cluster(c_ptr->addr));
+	if (highest <= LOWEST_SLAVE)
+		return;
+	buf = cluster_prepare_routing_msg(highest - LOWEST_SLAVE + 1,
+					  c_ptr->addr);
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_set_remote_node(msg, c_ptr->addr);
+		msg_set_type(msg, SLAVE_ROUTING_TABLE);
+		for (n_num = LOWEST_SLAVE; n_num <= highest; n_num++) {
+			if (c_ptr->nodes[n_num] && 
+			    node_has_active_links(c_ptr->nodes[n_num])) {
+				send = 1;
+				msg_set_dataoctet(msg, n_num);
+			}
+		}
+		if (send)
+			link_send(buf, dest, dest);
+		else
+			buf_discard(buf);
+	} else {
+		warn("Memory squeeze: broadcast of lost route failed\n");
+	}
+}
+
+void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest)
+{
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	u32 highest = c_ptr->highest_node;
+	u32 n_num;
+	int send = 0;
+
+	if (in_own_cluster(c_ptr->addr))
+		return;
+	assert(!is_slave(dest));
+	assert(in_own_cluster(dest));
+	highest = c_ptr->highest_node;
+	buf = cluster_prepare_routing_msg(highest + 1, c_ptr->addr);
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_set_remote_node(msg, c_ptr->addr);
+		msg_set_type(msg, EXT_ROUTING_TABLE);
+		for (n_num = 1; n_num <= highest; n_num++) {
+			if (c_ptr->nodes[n_num] && 
+			    node_has_active_links(c_ptr->nodes[n_num])) {
+				send = 1;
+				msg_set_dataoctet(msg, n_num);
+			}
+		}
+		if (send)
+			link_send(buf, dest, dest);
+		else
+			buf_discard(buf);
+	} else {
+		warn("Memory squeeze: broadcast of external route failed\n");
+	}
+}
+
+void cluster_send_local_routes(struct cluster *c_ptr, u32 dest)
+{
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	u32 highest = c_ptr->highest_node;
+	u32 n_num;
+	int send = 0;
+
+	assert(is_slave(dest));
+	assert(in_own_cluster(c_ptr->addr));
+	buf = cluster_prepare_routing_msg(highest, c_ptr->addr);
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_set_remote_node(msg, c_ptr->addr);
+		msg_set_type(msg, LOCAL_ROUTING_TABLE);
+		for (n_num = 1; n_num <= highest; n_num++) {
+			if (c_ptr->nodes[n_num] && 
+			    node_has_active_links(c_ptr->nodes[n_num])) {
+				send = 1;
+				msg_set_dataoctet(msg, n_num);
+			}
+		}
+		if (send)
+			link_send(buf, dest, dest);
+		else
+			buf_discard(buf);
+	} else {
+		warn("Memory squeeze: broadcast of local route failed\n");
+	}
+}
+
+void cluster_recv_routing_table(struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	struct cluster *c_ptr;
+	struct node *n_ptr;
+	unchar *node_table;
+	u32 table_size;
+	u32 router;
+	u32 rem_node = msg_remote_node(msg);
+	u32 z_num;
+	u32 c_num;
+	u32 n_num;
+
+	c_ptr = cluster_find(rem_node);
+	if (!c_ptr) {
+		c_ptr = cluster_create(rem_node);
+		if (!c_ptr) {
+			buf_discard(buf);
+			return;
+		}
+	}
+
+	node_table = buf->data + msg_hdr_sz(msg);
+	table_size = msg_size(msg) - msg_hdr_sz(msg);
+	router = msg_prevnode(msg);
+	z_num = tipc_zone(rem_node);
+	c_num = tipc_cluster(rem_node);
+
+	switch (msg_type(msg)) {
+	case LOCAL_ROUTING_TABLE:
+		assert(is_slave(tipc_own_addr));
+	case EXT_ROUTING_TABLE:
+		for (n_num = 1; n_num < table_size; n_num++) {
+			if (node_table[n_num]) {
+				u32 addr = tipc_addr(z_num, c_num, n_num);
+				n_ptr = c_ptr->nodes[n_num];
+				if (!n_ptr) {
+					n_ptr = node_create(addr);
+				}
+				if (n_ptr)
+					node_add_router(n_ptr, router);
+			}
+		}
+		break;
+	case SLAVE_ROUTING_TABLE:
+		assert(!is_slave(tipc_own_addr));
+		assert(in_own_cluster(c_ptr->addr));
+		for (n_num = 1; n_num < table_size; n_num++) {
+			if (node_table[n_num]) {
+				u32 slave_num = n_num + LOWEST_SLAVE;
+				u32 addr = tipc_addr(z_num, c_num, slave_num);
+				n_ptr = c_ptr->nodes[slave_num];
+				if (!n_ptr) {
+					n_ptr = node_create(addr);
+				}
+				if (n_ptr)
+					node_add_router(n_ptr, router);
+			}
+		}
+		break;
+	case ROUTE_ADDITION:
+		if (!is_slave(tipc_own_addr)) {
+			assert(!in_own_cluster(c_ptr->addr)
+			       || is_slave(rem_node));
+		} else {
+			assert(in_own_cluster(c_ptr->addr)
+			       && !is_slave(rem_node));
+		}
+		n_ptr = c_ptr->nodes[tipc_node(rem_node)];
+		if (!n_ptr)
+			n_ptr = node_create(rem_node);
+		if (n_ptr)
+			node_add_router(n_ptr, router);
+		break;
+	case ROUTE_REMOVAL:
+		if (!is_slave(tipc_own_addr)) {
+			assert(!in_own_cluster(c_ptr->addr)
+			       || is_slave(rem_node));
+		} else {
+			assert(in_own_cluster(c_ptr->addr)
+			       && !is_slave(rem_node));
+		}
+		n_ptr = c_ptr->nodes[tipc_node(rem_node)];
+		if (n_ptr)
+			node_remove_router(n_ptr, router);
+		break;
+	default:
+		assert(!"Illegal routing manager message received\n");
+	}
+	buf_discard(buf);
+}
+
+void cluster_remove_as_router(struct cluster *c_ptr, u32 router)
+{
+	u32 start_entry;
+	u32 tstop;
+	u32 n_num;
+
+	if (is_slave(router))
+		return;	/* Slave nodes can not be routers */
+
+	if (in_own_cluster(c_ptr->addr)) {
+		start_entry = LOWEST_SLAVE;
+		tstop = c_ptr->highest_slave;
+	} else {
+		start_entry = 1;
+		tstop = c_ptr->highest_node;
+	}
+
+	for (n_num = start_entry; n_num <= tstop; n_num++) {
+		if (c_ptr->nodes[n_num]) {
+			node_remove_router(c_ptr->nodes[n_num], router);
+		}
+	}
+}
+
+/**
+ * cluster_multicast - multicast message to local nodes 
+ */
+
+void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
+		       u32 lower, u32 upper)
+{
+	struct sk_buff *buf_copy;
+	struct node *n_ptr;
+	u32 n_num;
+	u32 tstop;
+
+	assert(lower <= upper);
+	assert(((lower >= 1) && (lower <= tipc_max_nodes)) ||
+	       ((lower >= LOWEST_SLAVE) && (lower <= highest_allowed_slave)));
+	assert(((upper >= 1) && (upper <= tipc_max_nodes)) ||
+	       ((upper >= LOWEST_SLAVE) && (upper <= highest_allowed_slave)));
+	assert(in_own_cluster(c_ptr->addr));
+
+	tstop = is_slave(upper) ? c_ptr->highest_slave : c_ptr->highest_node;
+	if (tstop > upper)
+		tstop = upper;
+	for (n_num = lower; n_num <= tstop; n_num++) {
+		n_ptr = c_ptr->nodes[n_num];
+		if (n_ptr && node_has_active_links(n_ptr)) {
+			buf_copy = skb_copy(buf, GFP_ATOMIC);
+			if (buf_copy == NULL)
+				break;
+			msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
+			link_send(buf_copy, n_ptr->addr, n_ptr->addr);
+		}
+	}
+	buf_discard(buf);
+}
+
+/**
+ * cluster_broadcast - broadcast message to all nodes within cluster
+ */
+
+void cluster_broadcast(struct sk_buff *buf)
+{
+	struct sk_buff *buf_copy;
+	struct cluster *c_ptr;
+	struct node *n_ptr;
+	u32 n_num;
+	u32 tstart;
+	u32 tstop;
+	u32 node_type;
+
+	if (tipc_mode == TIPC_NET_MODE) {
+		c_ptr = cluster_find(tipc_own_addr);
+		assert(in_own_cluster(c_ptr->addr));	/* For now */
+
+		/* Send to standard nodes, then repeat loop sending to slaves */
+		tstart = 1;
+		tstop = c_ptr->highest_node;
+		for (node_type = 1; node_type <= 2; node_type++) {
+			for (n_num = tstart; n_num <= tstop; n_num++) {
+				n_ptr = c_ptr->nodes[n_num];
+				if (n_ptr && node_has_active_links(n_ptr)) {
+					buf_copy = skb_copy(buf, GFP_ATOMIC);
+					if (buf_copy == NULL)
+						goto exit;
+					msg_set_destnode(buf_msg(buf_copy), 
+							 n_ptr->addr);
+					link_send(buf_copy, n_ptr->addr, 
+						  n_ptr->addr);
+				}
+			}
+			tstart = LOWEST_SLAVE;
+			tstop = c_ptr->highest_slave;
+		}
+	}
+exit:
+	buf_discard(buf);
+}
+
+int cluster_init(void)
+{
+	highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves;
+	return cluster_create(tipc_own_addr) ? TIPC_OK : -ENOMEM;
+}
+
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h
new file mode 100644
index 0000000..1ffb095
--- /dev/null
+++ b/net/tipc/cluster.h
@@ -0,0 +1,92 @@
+/*
+ * net/tipc/cluster.h: Include file for TIPC cluster management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CLUSTER_H
+#define _TIPC_CLUSTER_H
+
+#include "addr.h"
+#include "zone.h"
+
+#define LOWEST_SLAVE  2048u
+
+/**
+ * struct cluster - TIPC cluster structure
+ * @addr: network address of cluster
+ * @owner: pointer to zone that cluster belongs to
+ * @nodes: array of pointers to all nodes within cluster
+ * @highest_node: id of highest numbered node within cluster
+ * @highest_slave: (used for secondary node support)
+ */
+ 
+struct cluster {
+	u32 addr;
+	struct _zone *owner;
+	struct node **nodes;
+	u32 highest_node;
+	u32 highest_slave;
+};
+
+
+extern struct node **local_nodes;
+extern u32 highest_allowed_slave;
+extern struct node_map cluster_bcast_nodes;
+
+void cluster_remove_as_router(struct cluster *c_ptr, u32 router);
+void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest);
+struct node *cluster_select_node(struct cluster *c_ptr, u32 selector);
+u32 cluster_select_router(struct cluster *c_ptr, u32 ref);
+void cluster_recv_routing_table(struct sk_buff *buf);
+struct cluster *cluster_create(u32 addr);
+void cluster_delete(struct cluster *c_ptr);
+void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr);
+void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest);
+void cluster_broadcast(struct sk_buff *buf);
+int cluster_init(void);
+u32 cluster_next_node(struct cluster *c_ptr, u32 addr);
+void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
+void cluster_send_local_routes(struct cluster *c_ptr, u32 dest);
+void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
+
+static inline struct cluster *cluster_find(u32 addr)
+{
+	struct _zone *z_ptr = zone_find(addr);
+
+	if (z_ptr)
+		return z_ptr->clusters[1];
+	return 0;
+}
+
+#endif
diff --git a/net/tipc/config.c b/net/tipc/config.c
new file mode 100644
index 0000000..8ddef4f
--- /dev/null
+++ b/net/tipc/config.c
@@ -0,0 +1,718 @@
+/*
+ * net/tipc/config.c: TIPC configuration management code
+ * 
+ * Copyright (c) 2002-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "bearer.h"
+#include "port.h"
+#include "link.h"
+#include "zone.h"
+#include "addr.h"
+#include "name_table.h"
+#include "node.h"
+#include "config.h"
+#include "discover.h"
+
+struct subscr_data {
+	char usr_handle[8];
+	u32 domain;
+	u32 port_ref;
+	struct list_head subd_list;
+};
+
+struct manager {
+	u32 user_ref;
+	u32 port_ref;
+	u32 subscr_ref;
+	u32 link_subscriptions;
+	struct list_head link_subscribers;
+};
+
+static struct manager mng = { 0};
+
+static spinlock_t config_lock = SPIN_LOCK_UNLOCKED;
+
+static const void *req_tlv_area;	/* request message TLV area */
+static int req_tlv_space;		/* request message TLV area size */
+static int rep_headroom;		/* reply message headroom to use */
+
+
+void cfg_link_event(u32 addr, char *name, int up)
+{
+	/* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
+}
+
+
+struct sk_buff *cfg_reply_alloc(int payload_size)
+{
+	struct sk_buff *buf;
+
+	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
+	if (buf)
+		skb_reserve(buf, rep_headroom);
+	return buf;
+}
+
+int cfg_append_tlv(struct sk_buff *buf, int tlv_type, 
+		   void *tlv_data, int tlv_data_size)
+{
+	struct tlv_desc *tlv = (struct tlv_desc *)buf->tail;
+	int new_tlv_space = TLV_SPACE(tlv_data_size);
+
+	if (skb_tailroom(buf) < new_tlv_space) {
+		dbg("cfg_append_tlv unable to append TLV\n");
+		return 0;
+	}
+	skb_put(buf, new_tlv_space);
+	tlv->tlv_type = htons(tlv_type);
+	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
+	if (tlv_data_size && tlv_data)
+		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
+	return 1;
+}
+
+struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value)
+{
+	struct sk_buff *buf;
+	u32 value_net;
+
+	buf = cfg_reply_alloc(TLV_SPACE(sizeof(value)));
+	if (buf) {
+		value_net = htonl(value);
+		cfg_append_tlv(buf, tlv_type, &value_net, 
+			       sizeof(value_net));
+	}
+	return buf;
+}
+
+struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string)
+{
+	struct sk_buff *buf;
+	int string_len = strlen(string) + 1;
+
+	buf = cfg_reply_alloc(TLV_SPACE(string_len));
+	if (buf)
+		cfg_append_tlv(buf, tlv_type, string, string_len);
+	return buf;
+}
+
+
+
+
+#if 0
+
+/* Now obsolete code for handling commands not yet implemented the new way */
+
+int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
+		 char *data,
+		 u32 sz,
+		 u32 *ret_size,
+		 struct tipc_portid *orig)
+{
+	int rv = -EINVAL;
+	u32 cmd = msg->cmd;
+
+	*ret_size = 0;
+	switch (cmd) {
+	case TIPC_REMOVE_LINK:
+	case TIPC_CMD_BLOCK_LINK:
+	case TIPC_CMD_UNBLOCK_LINK:
+		if (!cfg_check_connection(orig))
+			rv = link_control(msg->argv.link_name, msg->cmd, 0);
+		break;
+	case TIPC_ESTABLISH:
+		{
+			int connected;
+
+			tipc_isconnected(mng.conn_port_ref, &connected);
+			if (connected || !orig) {
+				rv = TIPC_FAILURE;
+				break;
+			}
+			rv = tipc_connect2port(mng.conn_port_ref, orig);
+			if (rv == TIPC_OK)
+				orig = 0;
+			break;
+		}
+	case TIPC_GET_PEER_ADDRESS:
+		*ret_size = link_peer_addr(msg->argv.link_name, data, sz);
+		break;
+	case TIPC_GET_ROUTES:
+		rv = TIPC_OK;
+		break;
+	default: {}
+	}
+	if (*ret_size)
+		rv = TIPC_OK;
+	return rv;
+}
+
+static void cfg_cmd_event(struct tipc_cmd_msg *msg,
+			  char *data,
+			  u32 sz,        
+			  struct tipc_portid const *orig)
+{
+	int rv = -EINVAL;
+	struct tipc_cmd_result_msg rmsg;
+	struct iovec msg_sect[2];
+	int *arg;
+
+	msg->cmd = ntohl(msg->cmd);
+
+	cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect, 
+			    data, 0);
+	if (ntohl(msg->magic) != TIPC_MAGIC)
+		goto exit;
+
+	switch (msg->cmd) {
+	case TIPC_CREATE_LINK:
+		if (!cfg_check_connection(orig))
+			rv = disc_create_link(&msg->argv.create_link);
+		break;
+	case TIPC_LINK_SUBSCRIBE:
+		{
+			struct subscr_data *sub;
+
+			if (mng.link_subscriptions > 64)
+				break;
+			sub = (struct subscr_data *)kmalloc(sizeof(*sub),
+							    GFP_ATOMIC);
+			if (sub == NULL) {
+				warn("Memory squeeze; dropped remote link subscription\n");
+				break;
+			}
+			INIT_LIST_HEAD(&sub->subd_list);
+			tipc_createport(mng.user_ref,
+					(void *)sub,
+					TIPC_HIGH_IMPORTANCE,
+					0,
+					0,
+					(tipc_conn_shutdown_event)cfg_linksubscr_cancel,
+					0,
+					0,
+					(tipc_conn_msg_event)cfg_linksubscr_cancel,
+					0,
+					&sub->port_ref);
+			if (!sub->port_ref) {
+				kfree(sub);
+				break;
+			}
+			memcpy(sub->usr_handle,msg->usr_handle,
+			       sizeof(sub->usr_handle));
+			sub->domain = msg->argv.domain;
+			list_add_tail(&sub->subd_list, &mng.link_subscribers);
+			tipc_connect2port(sub->port_ref, orig);
+			rmsg.retval = TIPC_OK;
+			tipc_send(sub->port_ref, 2u, msg_sect);
+			mng.link_subscriptions++;
+			return;
+		}
+	default:
+		rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
+	}
+	exit:
+	rmsg.result_len = htonl(msg_sect[1].iov_len);
+	rmsg.retval = htonl(rv);
+	cfg_respond(msg_sect, 2u, orig);
+}
+#endif
+
+static struct sk_buff *cfg_enable_bearer(void)
+{
+	struct tipc_bearer_config *args;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
+	if (tipc_enable_bearer(args->name,
+			       ntohl(args->detect_scope),
+			       ntohl(args->priority)))
+		return cfg_reply_error_string("unable to enable bearer");
+
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_disable_bearer(void)
+{
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
+		return cfg_reply_error_string("unable to disable bearer");
+
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_own_addr(void)
+{
+	u32 addr;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	addr = *(u32 *)TLV_DATA(req_tlv_area);
+	addr = ntohl(addr);
+	if (addr == tipc_own_addr)
+		return cfg_reply_none();
+	if (!addr_node_valid(addr))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (node address)");
+	if (tipc_own_addr)
+		return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (cannot change node address once assigned)");
+
+	spin_unlock_bh(&config_lock);
+	stop_net();
+	tipc_own_addr = addr;
+	start_net();
+	spin_lock_bh(&config_lock);
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_remote_mng(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	tipc_remote_management = (value != 0);
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_publications(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 1, 65535))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (max publications must be 1-65535)");
+	tipc_max_publications = value;
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_subscriptions(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 1, 65535))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (max subscriptions must be 1-65535");
+	tipc_max_subscriptions = value;
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_ports(void)
+{
+	int orig_mode;
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 127, 65535))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (max ports must be 127-65535)");
+
+	if (value == tipc_max_ports)
+		return cfg_reply_none();
+
+	if (atomic_read(&tipc_user_count) > 2)
+		return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (cannot change max ports while TIPC users exist)");
+
+	spin_unlock_bh(&config_lock);
+	orig_mode = tipc_get_mode();
+	if (orig_mode == TIPC_NET_MODE)
+		stop_net();
+	stop_core();
+	tipc_max_ports = value;
+	start_core();
+	if (orig_mode == TIPC_NET_MODE)
+		start_net();
+	spin_lock_bh(&config_lock);
+	return cfg_reply_none();
+}
+
+static struct sk_buff *set_net_max(int value, int *parameter)
+{
+	int orig_mode;
+
+	if (value != *parameter) {
+		orig_mode = tipc_get_mode();
+		if (orig_mode == TIPC_NET_MODE)
+			stop_net();
+		*parameter = value;
+		if (orig_mode == TIPC_NET_MODE)
+			start_net();
+	}
+
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_zones(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 1, 255))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (max zones must be 1-255)");
+	return set_net_max(value, &tipc_max_zones);
+}
+
+static struct sk_buff *cfg_set_max_clusters(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != 1)
+		return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (max clusters fixed at 1)");
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_nodes(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 8, 2047))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (max nodes must be 8-2047)");
+	return set_net_max(value, &tipc_max_nodes);
+}
+
+static struct sk_buff *cfg_set_max_slaves(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != 0)
+		return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (max secondary nodes fixed at 0)");
+	return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_netid(void)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 1, 9999))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (network id must be 1-9999)");
+
+	if (tipc_own_addr)
+		return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (cannot change network id once part of network)");
+	
+	return set_net_max(value, &tipc_net_id);
+}
+
+struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
+			   int request_space, int reply_headroom)
+{
+	struct sk_buff *rep_tlv_buf;
+
+	spin_lock_bh(&config_lock);
+
+	/* Save request and reply details in a well-known location */
+
+	req_tlv_area = request_area;
+	req_tlv_space = request_space;
+	rep_headroom = reply_headroom;
+
+	/* Check command authorization */
+
+	if (likely(orig_node == tipc_own_addr)) {
+		/* command is permitted */
+	} else if (cmd >= 0x8000) {
+		rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+						     " (cannot be done remotely)");
+		goto exit;
+	} else if (!tipc_remote_management) {
+		rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
+		goto exit;
+	}
+	else if (cmd >= 0x4000) {
+		u32 domain = 0;
+
+		if ((nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
+		    (domain != orig_node)) {
+			rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
+			goto exit;
+		}
+	}
+
+	/* Call appropriate processing routine */
+
+	switch (cmd) {
+	case TIPC_CMD_NOOP:
+		rep_tlv_buf = cfg_reply_none();
+		break;
+	case TIPC_CMD_GET_NODES:
+		rep_tlv_buf = node_get_nodes(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_GET_LINKS:
+		rep_tlv_buf = node_get_links(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_SHOW_LINK_STATS:
+		rep_tlv_buf = link_cmd_show_stats(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_RESET_LINK_STATS:
+		rep_tlv_buf = link_cmd_reset_stats(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_SHOW_NAME_TABLE:
+		rep_tlv_buf = nametbl_get(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_GET_BEARER_NAMES:
+		rep_tlv_buf = bearer_get_names();
+		break;
+	case TIPC_CMD_GET_MEDIA_NAMES:
+		rep_tlv_buf = media_get_names();
+		break;
+	case TIPC_CMD_SHOW_PORTS:
+		rep_tlv_buf = port_get_ports();
+		break;
+#if 0
+	case TIPC_CMD_SHOW_PORT_STATS:
+		rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_RESET_PORT_STATS:
+		rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
+		break;
+#endif
+	case TIPC_CMD_SET_LOG_SIZE:
+		rep_tlv_buf = log_resize(req_tlv_area, req_tlv_space);
+		break;
+	case TIPC_CMD_DUMP_LOG:
+		rep_tlv_buf = log_dump();
+		break;
+	case TIPC_CMD_SET_LINK_TOL:
+	case TIPC_CMD_SET_LINK_PRI:
+	case TIPC_CMD_SET_LINK_WINDOW:
+		rep_tlv_buf = link_cmd_config(req_tlv_area, req_tlv_space, cmd);
+		break;
+	case TIPC_CMD_ENABLE_BEARER:
+		rep_tlv_buf = cfg_enable_bearer();
+		break;
+	case TIPC_CMD_DISABLE_BEARER:
+		rep_tlv_buf = cfg_disable_bearer();
+		break;
+	case TIPC_CMD_SET_NODE_ADDR:
+		rep_tlv_buf = cfg_set_own_addr();
+		break;
+	case TIPC_CMD_SET_REMOTE_MNG:
+		rep_tlv_buf = cfg_set_remote_mng();
+		break;
+	case TIPC_CMD_SET_MAX_PORTS:
+		rep_tlv_buf = cfg_set_max_ports();
+		break;
+	case TIPC_CMD_SET_MAX_PUBL:
+		rep_tlv_buf = cfg_set_max_publications();
+		break;
+	case TIPC_CMD_SET_MAX_SUBSCR:
+		rep_tlv_buf = cfg_set_max_subscriptions();
+		break;
+	case TIPC_CMD_SET_MAX_ZONES:
+		rep_tlv_buf = cfg_set_max_zones();
+		break;
+	case TIPC_CMD_SET_MAX_CLUSTERS:
+		rep_tlv_buf = cfg_set_max_clusters();
+		break;
+	case TIPC_CMD_SET_MAX_NODES:
+		rep_tlv_buf = cfg_set_max_nodes();
+		break;
+	case TIPC_CMD_SET_MAX_SLAVES:
+		rep_tlv_buf = cfg_set_max_slaves();
+		break;
+	case TIPC_CMD_SET_NETID:
+		rep_tlv_buf = cfg_set_netid();
+		break;
+	case TIPC_CMD_GET_REMOTE_MNG:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_remote_management);
+		break;
+	case TIPC_CMD_GET_MAX_PORTS:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_ports);
+		break;
+	case TIPC_CMD_GET_MAX_PUBL:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_publications);
+		break;
+	case TIPC_CMD_GET_MAX_SUBSCR:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_subscriptions);
+		break;
+	case TIPC_CMD_GET_MAX_ZONES:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_zones);
+		break;
+	case TIPC_CMD_GET_MAX_CLUSTERS:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_clusters);
+		break;
+	case TIPC_CMD_GET_MAX_NODES:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_nodes);
+		break;
+	case TIPC_CMD_GET_MAX_SLAVES:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_max_slaves);
+		break;
+	case TIPC_CMD_GET_NETID:
+		rep_tlv_buf = cfg_reply_unsigned(tipc_net_id);
+		break;
+	default:
+		rep_tlv_buf = NULL;
+		break;
+	}
+
+	/* Return reply buffer */
+exit:
+	spin_unlock_bh(&config_lock);
+	return rep_tlv_buf;
+}
+
+static void cfg_named_msg_event(void *userdata,
+				u32 port_ref,
+				struct sk_buff **buf,
+				const unchar *msg,
+				u32 size,
+				u32 importance, 
+				struct tipc_portid const *orig,
+				struct tipc_name_seq const *dest)
+{
+	struct tipc_cfg_msg_hdr *req_hdr;
+	struct tipc_cfg_msg_hdr *rep_hdr;
+	struct sk_buff *rep_buf;
+
+	/* Validate configuration message header (ignore invalid message) */
+
+	req_hdr = (struct tipc_cfg_msg_hdr *)msg;
+	if ((size < sizeof(*req_hdr)) ||
+	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
+	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
+		warn("discarded invalid configuration message\n");
+		return;
+	}
+
+	/* Generate reply for request (if can't, return request) */
+
+	rep_buf = cfg_do_cmd(orig->node,
+			     ntohs(req_hdr->tcm_type), 
+			     msg + sizeof(*req_hdr),
+			     size - sizeof(*req_hdr),
+			     BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
+	if (rep_buf) {
+		skb_push(rep_buf, sizeof(*rep_hdr));
+		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
+		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
+		rep_hdr->tcm_len = htonl(rep_buf->len);
+		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
+	} else {
+		rep_buf = *buf;
+		*buf = NULL;
+	}
+
+	/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
+	tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
+}
+
+int cfg_init(void)
+{
+	struct tipc_name_seq seq;
+	int res;
+
+	memset(&mng, 0, sizeof(mng));
+	INIT_LIST_HEAD(&mng.link_subscribers);
+
+	res = tipc_attach(&mng.user_ref, 0, 0);
+	if (res)
+		goto failed;
+
+	res = tipc_createport(mng.user_ref, 0, TIPC_CRITICAL_IMPORTANCE,
+			      NULL, NULL, NULL,
+			      NULL, cfg_named_msg_event, NULL,
+			      NULL, &mng.port_ref);
+	if (res)
+		goto failed;
+
+	seq.type = TIPC_CFG_SRV;
+	seq.lower = seq.upper = tipc_own_addr;
+	res = nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
+	if (res)
+		goto failed;
+
+	return 0;
+
+failed:
+	err("Unable to create configuration service\n");
+	tipc_detach(mng.user_ref);
+	mng.user_ref = 0;
+	return res;
+}
+
+void cfg_stop(void)
+{
+	if (mng.user_ref) {
+		tipc_detach(mng.user_ref);
+		mng.user_ref = 0;
+	}
+}
diff --git a/net/tipc/config.h b/net/tipc/config.h
new file mode 100644
index 0000000..646377d
--- /dev/null
+++ b/net/tipc/config.h
@@ -0,0 +1,80 @@
+/*
+ * net/tipc/config.h: Include file for TIPC configuration service code
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CONFIG_H
+#define _TIPC_CONFIG_H
+
+/* ---------------------------------------------------------------------- */
+
+#include <linux/tipc.h>
+#include <linux/tipc_config.h>
+#include "link.h"
+
+struct sk_buff *cfg_reply_alloc(int payload_size);
+int cfg_append_tlv(struct sk_buff *buf, int tlv_type, 
+		   void *tlv_data, int tlv_data_size);
+struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value);
+struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string);
+
+static inline struct sk_buff *cfg_reply_none(void)
+{
+	return cfg_reply_alloc(0);
+}
+
+static inline struct sk_buff *cfg_reply_unsigned(u32 value)
+{
+	return cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
+}
+
+static inline struct sk_buff *cfg_reply_error_string(char *string)
+{
+	return cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
+}
+
+static inline struct sk_buff *cfg_reply_ultra_string(char *string)
+{
+	return cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
+}
+
+struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd, 
+			   const void *req_tlv_area, int req_tlv_space, 
+			   int headroom);
+
+void cfg_link_event(u32 addr, char *name, int up);
+int  cfg_init(void);
+void cfg_stop(void);
+
+#endif
diff --git a/net/tipc/core.c b/net/tipc/core.c
new file mode 100644
index 0000000..e83ac06
--- /dev/null
+++ b/net/tipc/core.c
@@ -0,0 +1,285 @@
+/*
+ * net/tipc/core.c: TIPC module code
+ *
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/random.h>
+
+#include "core.h"
+#include "dbg.h"
+#include "ref.h"
+#include "net.h"
+#include "user_reg.h"
+#include "name_table.h"
+#include "subscr.h"
+#include "config.h"
+
+int  eth_media_start(void);
+void eth_media_stop(void);
+int  handler_start(void);
+void handler_stop(void);
+int  socket_init(void);
+void socket_stop(void);
+int  netlink_start(void);
+void netlink_stop(void);
+
+#define MOD_NAME "tipc_start: "
+
+#ifndef CONFIG_TIPC_ZONES
+#define CONFIG_TIPC_ZONES 3
+#endif
+
+#ifndef CONFIG_TIPC_CLUSTERS
+#define CONFIG_TIPC_CLUSTERS 1
+#endif
+
+#ifndef CONFIG_TIPC_NODES
+#define CONFIG_TIPC_NODES 255
+#endif
+
+#ifndef CONFIG_TIPC_SLAVE_NODES
+#define CONFIG_TIPC_SLAVE_NODES 0
+#endif
+
+#ifndef CONFIG_TIPC_PORTS
+#define CONFIG_TIPC_PORTS 8191
+#endif
+
+#ifndef CONFIG_TIPC_LOG
+#define CONFIG_TIPC_LOG 0
+#endif
+
+/* global variables used by multiple sub-systems within TIPC */
+
+int tipc_mode = TIPC_NOT_RUNNING;
+int tipc_random;
+atomic_t tipc_user_count = ATOMIC_INIT(0);
+
+const char tipc_alphabet[] = 
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+/* configurable TIPC parameters */
+
+u32 tipc_own_addr;
+int tipc_max_zones;
+int tipc_max_clusters;
+int tipc_max_nodes;
+int tipc_max_slaves;
+int tipc_max_ports;
+int tipc_max_subscriptions;
+int tipc_max_publications;
+int tipc_net_id;
+int tipc_remote_management;
+
+
+int tipc_get_mode(void)
+{
+	return tipc_mode;
+}
+
+/**
+ * stop_net - shut down TIPC networking sub-systems
+ */
+
+void stop_net(void)
+{
+	eth_media_stop();
+	tipc_stop_net();
+}
+
+/**
+ * start_net - start TIPC networking sub-systems
+ */
+
+int start_net(void)
+{
+	int res;
+
+	if ((res = tipc_start_net()) ||
+	    (res = eth_media_start())) {
+		stop_net();
+	}
+	return res;
+}
+
+/**
+ * stop_core - switch TIPC from SINGLE NODE to NOT RUNNING mode
+ */
+
+void stop_core(void)
+{
+	if (tipc_mode != TIPC_NODE_MODE)
+		return;
+
+	tipc_mode = TIPC_NOT_RUNNING;
+
+	netlink_stop();
+	handler_stop();
+	cfg_stop();
+	subscr_stop();
+	reg_stop();
+	nametbl_stop();
+	ref_table_stop();
+	socket_stop();
+}
+
+/**
+ * start_core - switch TIPC from NOT RUNNING to SINGLE NODE mode
+ */
+
+int start_core(void)
+{
+	int res;
+
+	if (tipc_mode != TIPC_NOT_RUNNING)
+		return -ENOPROTOOPT;
+
+	get_random_bytes(&tipc_random, sizeof(tipc_random));
+	tipc_mode = TIPC_NODE_MODE;
+
+	if ((res = handler_start()) || 
+	    (res = ref_table_init(tipc_max_ports + tipc_max_subscriptions,
+				  tipc_random)) ||
+	    (res = reg_start()) ||
+	    (res = nametbl_init()) ||
+            (res = k_signal((Handler)subscr_start, 0)) ||
+	    (res = k_signal((Handler)cfg_init, 0)) || 
+	    (res = netlink_start()) ||
+	    (res = socket_init())) {
+		stop_core();
+	}
+	return res;
+}
+
+
+static int __init tipc_init(void)
+{
+	int res;
+
+	log_reinit(CONFIG_TIPC_LOG);
+	info("Activated (compiled " __DATE__ " " __TIME__ ")\n");
+
+	tipc_own_addr = 0;
+	tipc_remote_management = 1;
+	tipc_max_publications = 10000;
+	tipc_max_subscriptions = 2000;
+	tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
+	tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 511);
+	tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
+	tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
+	tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
+	tipc_net_id = 4711;
+
+	if ((res = start_core()))
+		err("Unable to start in single node mode\n");
+	else	
+		info("Started in single node mode\n");
+        return res;
+}
+
+static void __exit tipc_exit(void)
+{
+	stop_net();
+	stop_core();
+	info("Deactivated\n");
+	log_stop();
+}
+
+module_init(tipc_init);
+module_exit(tipc_exit);
+
+MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* Native TIPC API for kernel-space applications (see tipc.h) */
+
+EXPORT_SYMBOL(tipc_attach);
+EXPORT_SYMBOL(tipc_detach);
+EXPORT_SYMBOL(tipc_get_addr);
+EXPORT_SYMBOL(tipc_get_mode);
+EXPORT_SYMBOL(tipc_createport);
+EXPORT_SYMBOL(tipc_deleteport);
+EXPORT_SYMBOL(tipc_ownidentity);
+EXPORT_SYMBOL(tipc_portimportance);
+EXPORT_SYMBOL(tipc_set_portimportance);
+EXPORT_SYMBOL(tipc_portunreliable);
+EXPORT_SYMBOL(tipc_set_portunreliable);
+EXPORT_SYMBOL(tipc_portunreturnable);
+EXPORT_SYMBOL(tipc_set_portunreturnable);
+EXPORT_SYMBOL(tipc_publish);
+EXPORT_SYMBOL(tipc_withdraw);
+EXPORT_SYMBOL(tipc_connect2port);
+EXPORT_SYMBOL(tipc_disconnect);
+EXPORT_SYMBOL(tipc_shutdown);
+EXPORT_SYMBOL(tipc_isconnected);
+EXPORT_SYMBOL(tipc_peer);
+EXPORT_SYMBOL(tipc_ref_valid);
+EXPORT_SYMBOL(tipc_send);
+EXPORT_SYMBOL(tipc_send_buf);
+EXPORT_SYMBOL(tipc_send2name);
+EXPORT_SYMBOL(tipc_forward2name);
+EXPORT_SYMBOL(tipc_send_buf2name);
+EXPORT_SYMBOL(tipc_forward_buf2name);
+EXPORT_SYMBOL(tipc_send2port);
+EXPORT_SYMBOL(tipc_forward2port);
+EXPORT_SYMBOL(tipc_send_buf2port);
+EXPORT_SYMBOL(tipc_forward_buf2port);
+EXPORT_SYMBOL(tipc_multicast);
+/* EXPORT_SYMBOL(tipc_multicast_buf); not available yet */
+EXPORT_SYMBOL(tipc_ispublished);
+EXPORT_SYMBOL(tipc_available_nodes);
+
+/* TIPC API for external bearers (see tipc_bearer.h) */
+
+EXPORT_SYMBOL(tipc_block_bearer);
+EXPORT_SYMBOL(tipc_continue); 
+EXPORT_SYMBOL(tipc_disable_bearer);
+EXPORT_SYMBOL(tipc_enable_bearer);
+EXPORT_SYMBOL(tipc_recv_msg);
+EXPORT_SYMBOL(tipc_register_media); 
+
+/* TIPC API for external APIs (see tipc_port.h) */
+
+EXPORT_SYMBOL(tipc_createport_raw);
+EXPORT_SYMBOL(tipc_set_msg_option);
+EXPORT_SYMBOL(tipc_reject_msg);
+EXPORT_SYMBOL(tipc_send_buf_fast);
+EXPORT_SYMBOL(tipc_acknowledge);
+EXPORT_SYMBOL(tipc_get_port);
+EXPORT_SYMBOL(tipc_get_handle);
+
diff --git a/net/tipc/core.h b/net/tipc/core.h
new file mode 100644
index 0000000..b69b60b
--- /dev/null
+++ b/net/tipc/core.h
@@ -0,0 +1,316 @@
+/*
+ * net/tipc/core.h: Include file for TIPC global declarations
+ * 
+ * Copyright (c) 2005-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CORE_H
+#define _TIPC_CORE_H
+
+#include <net/tipc/tipc.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>	
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+
+/*
+ * TIPC debugging code
+ */
+
+#define assert(i)  BUG_ON(!(i))
+
+struct tipc_msg;
+extern struct print_buf *CONS, *LOG;
+extern struct print_buf *TEE(struct print_buf *, struct print_buf *);
+void msg_print(struct print_buf*,struct tipc_msg *,const char*);
+void tipc_printf(struct print_buf *, const char *fmt, ...);
+void tipc_dump(struct print_buf*,const char *fmt, ...);
+
+#ifdef CONFIG_TIPC_DEBUG
+
+/*
+ * TIPC debug support included:
+ * - system messages are printed to TIPC_OUTPUT print buffer
+ * - debug messages are printed to DBG_OUTPUT print buffer
+ */
+
+#define err(fmt, arg...)  tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
+#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
+#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+
+#define dbg(fmt, arg...)  do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
+#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) msg_print(DBG_OUTPUT, msg, txt);} while(0)
+#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+
+
+/*	
+ * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
+ * while DBG_OUTPUT is the null print buffer.  These defaults can be changed
+ * here, or on a per .c file basis, by redefining these symbols.  The following
+ * print buffer options are available:
+ *
+ * NULL			: Output to null print buffer (i.e. print nowhere)
+ * CONS			: Output to system console
+ * LOG			: Output to TIPC log buffer 
+ * &buf 		: Output to user-defined buffer (struct print_buf *)
+ * TEE(&buf_a,&buf_b)	: Output to two print buffers (eg. TEE(CONS,LOG) )
+ */
+
+#ifndef TIPC_OUTPUT
+#define TIPC_OUTPUT TEE(CONS,LOG)
+#endif
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT NULL
+#endif
+
+#else
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT NULL
+#endif
+
+/*
+ * TIPC debug support not included:
+ * - system messages are printed to system console
+ * - debug messages are not printed
+ */
+
+#define err(fmt, arg...)  printk(KERN_ERR "TIPC: " fmt , ## arg)
+#define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
+#define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
+
+#define dbg(fmt, arg...) do {} while (0)
+#define msg_dbg(msg,txt) do {} while (0)
+#define dump(fmt,arg...) do {} while (0)
+
+#endif			  
+
+
+/* 
+ * TIPC-specific error codes
+ */
+
+#define ELINKCONG EAGAIN	/* link congestion <=> resource unavailable */
+
+/*
+ * Global configuration variables
+ */
+
+extern u32 tipc_own_addr;
+extern int tipc_max_zones;
+extern int tipc_max_clusters;
+extern int tipc_max_nodes;
+extern int tipc_max_slaves;
+extern int tipc_max_ports;
+extern int tipc_max_subscriptions;
+extern int tipc_max_publications;
+extern int tipc_net_id;
+extern int tipc_remote_management;
+
+/*
+ * Other global variables
+ */
+
+extern int tipc_mode;
+extern int tipc_random;
+extern const char tipc_alphabet[];
+extern atomic_t tipc_user_count;
+
+
+/*
+ * Routines available to privileged subsystems
+ */
+
+extern int  start_core(void);
+extern void stop_core(void);
+extern int  start_net(void);
+extern void stop_net(void);
+
+static inline int delimit(int val, int min, int max)
+{
+	if (val > max)
+		return max;
+	if (val < min)
+		return min;
+	return val;
+}
+
+
+/*
+ * TIPC timer and signal code
+ */
+
+typedef void (*Handler) (unsigned long);
+
+u32 k_signal(Handler routine, unsigned long argument);
+
+/**
+ * k_init_timer - initialize a timer
+ * @timer: pointer to timer structure
+ * @routine: pointer to routine to invoke when timer expires
+ * @argument: value to pass to routine when timer expires
+ * 
+ * Timer must be initialized before use (and terminated when no longer needed).
+ */
+
+static inline void k_init_timer(struct timer_list *timer, Handler routine, 
+				unsigned long argument)
+{
+	dbg("initializing timer %p\n", timer);
+	init_timer(timer);
+	timer->function = routine;
+	timer->data = argument;
+}
+
+/**
+ * k_start_timer - start a timer
+ * @timer: pointer to timer structure
+ * @msec: time to delay (in ms)
+ * 
+ * Schedules a previously initialized timer for later execution.
+ * If timer is already running, the new timeout overrides the previous request.
+ * 
+ * To ensure the timer doesn't expire before the specified delay elapses,
+ * the amount of delay is rounded up when converting to the jiffies
+ * then an additional jiffy is added to account for the fact that 
+ * the starting time may be in the middle of the current jiffy.
+ */
+
+static inline void k_start_timer(struct timer_list *timer, unsigned long msec)
+{
+	dbg("starting timer %p for %u\n", timer, msec);
+	mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1);
+}
+
+/**
+ * k_cancel_timer - cancel a timer
+ * @timer: pointer to timer structure
+ * 
+ * Cancels a previously initialized timer.  
+ * Can be called safely even if the timer is already inactive.
+ * 
+ * WARNING: Must not be called when holding locks required by the timer's
+ *          timeout routine, otherwise deadlock can occur on SMP systems!
+ */
+
+static inline void k_cancel_timer(struct timer_list *timer)
+{
+	dbg("cancelling timer %p\n", timer);
+	del_timer_sync(timer);
+}
+
+/**
+ * k_term_timer - terminate a timer
+ * @timer: pointer to timer structure
+ * 
+ * Prevents further use of a previously initialized timer.
+ * 
+ * WARNING: Caller must ensure timer isn't currently running.
+ * 
+ * (Do not "enhance" this routine to automatically cancel an active timer,
+ * otherwise deadlock can arise when a timeout routine calls k_term_timer.)
+ */
+
+static inline void k_term_timer(struct timer_list *timer)
+{
+	dbg("terminating timer %p\n", timer);
+}
+
+
+/*
+ * TIPC message buffer code
+ *
+ * TIPC message buffer headroom leaves room for 14 byte Ethernet header, 
+ * while ensuring TIPC header is word aligned for quicker access
+ */
+
+#define BUF_HEADROOM 16u 
+
+struct tipc_skb_cb {
+	void *handle;
+};
+
+#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
+
+
+static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
+{
+	return (struct tipc_msg *)skb->data;
+}
+
+/**
+ * buf_acquire - creates a TIPC message buffer
+ * @size: message size (including TIPC header)
+ *
+ * Returns a new buffer.  Space is reserved for a data link header.
+ */
+
+static inline struct sk_buff *buf_acquire(u32 size)
+{
+	struct sk_buff *skb;
+	unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
+
+	skb = alloc_skb(buf_size, GFP_ATOMIC);
+	if (skb) {
+		skb_reserve(skb, BUF_HEADROOM);
+		skb_put(skb, size);
+		skb->next = NULL;
+	}
+	return skb;
+}
+
+/**
+ * buf_discard - frees a TIPC message buffer
+ * @skb: message buffer
+ *
+ * Frees a new buffer.  If passed NULL, just returns.
+ */
+
+static inline void buf_discard(struct sk_buff *skb)
+{
+	if (likely(skb != NULL))
+		kfree_skb(skb);
+}
+
+#endif			
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
new file mode 100644
index 0000000..7ed60a1
--- /dev/null
+++ b/net/tipc/dbg.c
@@ -0,0 +1,395 @@
+/*
+ * net/tipc/dbg.c: TIPC print buffer routines for debuggign
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+
+#define MAX_STRING 512
+
+static char print_string[MAX_STRING];
+static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
+
+static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
+struct print_buf *CONS = &cons_buf;
+
+static struct print_buf log_buf = { NULL, 0, NULL, NULL };
+struct print_buf *LOG = &log_buf;
+
+
+#define FORMAT(PTR,LEN,FMT) \
+{\
+       va_list args;\
+       va_start(args, FMT);\
+       LEN = vsprintf(PTR, FMT, args);\
+       va_end(args);\
+       *(PTR + LEN) = '\0';\
+}
+
+/*
+ * Locking policy when using print buffers.
+ *
+ * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
+ *    simultaneous use of the print buffer(s) being manipulated.
+ * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
+ *    'print_string' and to protect its print buffer(s).
+ * 3) TEE() uses 'print_lock' to protect its print buffer(s).
+ * 4) Routines of the form log_XXX() uses 'print_lock' to protect LOG.
+ */
+
+/**
+ * printbuf_init - initialize print buffer to empty
+ */
+
+void printbuf_init(struct print_buf *pb, char *raw, u32 sz)
+{
+	if (!pb || !raw || (sz < (MAX_STRING + 1)))
+		return;
+
+	pb->crs = pb->buf = raw;
+	pb->size = sz;
+	pb->next = 0;
+	pb->buf[0] = 0;
+	pb->buf[sz-1] = ~0;
+}
+
+/**
+ * printbuf_reset - reinitialize print buffer to empty state
+ */
+
+void printbuf_reset(struct print_buf *pb)
+{
+	if (pb && pb->buf)
+		printbuf_init(pb, pb->buf, pb->size);
+}
+
+/**
+ * printbuf_empty - test if print buffer is in empty state
+ */
+
+int printbuf_empty(struct print_buf *pb)
+{
+	return (!pb || !pb->buf || (pb->crs == pb->buf));
+}
+
+/**
+ * printbuf_validate - check for print buffer overflow
+ * 
+ * Verifies that a print buffer has captured all data written to it. 
+ * If data has been lost, linearize buffer and prepend an error message
+ * 
+ * Returns length of print buffer data string (including trailing NULL)
+ */
+
+int printbuf_validate(struct print_buf *pb)
+{
+        char *err = "             *** PRINT BUFFER WRAPPED AROUND ***\n";
+        char *cp_buf;
+        struct print_buf cb;
+
+	if (!pb || !pb->buf)
+		return 0;
+
+	if (pb->buf[pb->size - 1] == '\0') {
+                cp_buf = kmalloc(pb->size, GFP_ATOMIC);
+                if (cp_buf != NULL){
+                        printbuf_init(&cb, cp_buf, pb->size);
+                        printbuf_move(&cb, pb);
+                        printbuf_move(pb, &cb);
+                        kfree(cp_buf);
+                        memcpy(pb->buf, err, strlen(err));
+                } else {
+                        printbuf_reset(pb);
+                        tipc_printf(pb, err);
+                }
+	}
+	return (pb->crs - pb->buf + 1);
+}
+
+/**
+ * printbuf_move - move print buffer contents to another print buffer
+ * 
+ * Current contents of destination print buffer (if any) are discarded.
+ * Source print buffer becomes empty if a successful move occurs.
+ */
+
+void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
+{
+	int len;
+
+	/* Handle the cases where contents can't be moved */
+
+	if (!pb_to || !pb_to->buf)
+		return;
+
+	if (!pb_from || !pb_from->buf) {
+		printbuf_reset(pb_to);
+		return;
+	}
+
+	if (pb_to->size < pb_from->size) {
+		printbuf_reset(pb_to);
+		tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
+		return;
+	}
+
+	/* Copy data from char after cursor to end (if used) */
+	len = pb_from->buf + pb_from->size - pb_from->crs - 2;
+	if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+		strcpy(pb_to->buf, pb_from->crs + 1);
+		pb_to->crs = pb_to->buf + len;
+	} else
+		pb_to->crs = pb_to->buf;
+
+	/* Copy data from start to cursor (always) */
+	len = pb_from->crs - pb_from->buf;
+	strcpy(pb_to->crs, pb_from->buf);
+	pb_to->crs += len;
+
+	printbuf_reset(pb_from);
+}
+
+/**
+ * tipc_printf - append formatted output to print buffer chain
+ */
+
+void tipc_printf(struct print_buf *pb, const char *fmt, ...)
+{
+	int chars_to_add;
+	int chars_left;
+	char save_char;
+	struct print_buf *pb_next;
+
+	spin_lock_bh(&print_lock);
+	FORMAT(print_string, chars_to_add, fmt);
+	if (chars_to_add >= MAX_STRING)
+		strcpy(print_string, "*** STRING TOO LONG ***");
+
+	while (pb) {
+		if (pb == CONS)
+			printk(print_string);
+		else if (pb->buf) {
+			chars_left = pb->buf + pb->size - pb->crs - 1;
+			if (chars_to_add <= chars_left) {
+				strcpy(pb->crs, print_string);
+				pb->crs += chars_to_add;
+			} else {
+				strcpy(pb->buf, print_string + chars_left);
+                                save_char = print_string[chars_left];
+                                print_string[chars_left] = 0;
+                                strcpy(pb->crs, print_string);
+                                print_string[chars_left] = save_char;
+                                pb->crs = pb->buf + chars_to_add - chars_left;
+                        }
+                }
+		pb_next = pb->next;
+		pb->next = 0;
+		pb = pb_next;
+	}
+	spin_unlock_bh(&print_lock);
+}
+
+/**
+ * TEE - perform next output operation on both print buffers  
+ */
+
+struct print_buf *TEE(struct print_buf *b0, struct print_buf *b1)
+{
+	struct print_buf *pb = b0;
+
+	if (!b0 || (b0 == b1))
+		return b1;
+	if (!b1)
+		return b0;
+
+	spin_lock_bh(&print_lock);
+	while (pb->next) {
+		if ((pb->next == b1) || (pb->next == b0))
+			pb->next = pb->next->next;
+		else
+			pb = pb->next;
+	}
+	pb->next = b1;
+	spin_unlock_bh(&print_lock);
+	return b0;
+}
+
+/**
+ * print_to_console - write string of bytes to console in multiple chunks
+ */
+
+static void print_to_console(char *crs, int len)
+{
+	int rest = len;
+
+	while (rest > 0) {
+		int sz = rest < MAX_STRING ? rest : MAX_STRING;
+		char c = crs[sz];
+
+		crs[sz] = 0;
+		printk((const char *)crs);
+		crs[sz] = c;
+		rest -= sz;
+		crs += sz;
+	}
+}
+
+/**
+ * printbuf_dump - write print buffer contents to console
+ */
+
+static void printbuf_dump(struct print_buf *pb)
+{
+	int len;
+
+	/* Dump print buffer from char after cursor to end (if used) */
+	len = pb->buf + pb->size - pb->crs - 2;
+	if ((pb->buf[pb->size - 1] == 0) && (len > 0))
+		print_to_console(pb->crs + 1, len);
+
+	/* Dump print buffer from start to cursor (always) */
+	len = pb->crs - pb->buf;
+	print_to_console(pb->buf, len);
+}
+
+/**
+ * tipc_dump - dump non-console print buffer(s) to console
+ */
+
+void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+{
+	int len;
+
+	spin_lock_bh(&print_lock);
+	FORMAT(CONS->buf, len, fmt);
+	printk(CONS->buf);
+
+	for (; pb; pb = pb->next) {
+		if (pb == CONS)
+			continue;
+		printk("\n---- Start of dump,%s log ----\n\n", 
+		       (pb == LOG) ? "global" : "local");
+		printbuf_dump(pb);
+		printbuf_reset(pb);
+		printk("\n-------- End of dump --------\n");
+	}
+	spin_unlock_bh(&print_lock);
+}
+
+/**
+ * log_stop - free up TIPC log print buffer 
+ */
+
+void log_stop(void)
+{
+	spin_lock_bh(&print_lock);
+	if (LOG->buf) {
+		kfree(LOG->buf);
+		LOG->buf = NULL;
+	}
+	spin_unlock_bh(&print_lock);
+}
+
+/**
+ * log_reinit - set TIPC log print buffer to specified size
+ */
+
+void log_reinit(int log_size)
+{
+	log_stop();
+
+	if (log_size) {
+		if (log_size <= MAX_STRING)
+			log_size = MAX_STRING + 1;
+		spin_lock_bh(&print_lock);
+		printbuf_init(LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
+		spin_unlock_bh(&print_lock);
+	}
+}
+
+/**
+ * log_resize - reconfigure size of TIPC log buffer
+ */
+
+struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space)
+{
+	u32 value;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	value = *(u32 *)TLV_DATA(req_tlv_area);
+	value = ntohl(value);
+	if (value != delimit(value, 0, 32768))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (log size must be 0-32768)");
+	log_reinit(value);
+	return cfg_reply_none();
+}
+
+/**
+ * log_dump - capture TIPC log buffer contents in configuration message
+ */
+
+struct sk_buff *log_dump(void)
+{
+	struct sk_buff *reply;
+
+	spin_lock_bh(&print_lock);
+	if (!LOG->buf)
+		reply = cfg_reply_ultra_string("log not activated\n");
+	else if (printbuf_empty(LOG))
+		reply = cfg_reply_ultra_string("log is empty\n");
+	else {
+		struct tlv_desc *rep_tlv;
+		struct print_buf pb;
+		int str_len;
+
+		str_len = min(LOG->size, 32768u);
+		reply = cfg_reply_alloc(TLV_SPACE(str_len));
+		if (reply) {
+			rep_tlv = (struct tlv_desc *)reply->data;
+			printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
+			printbuf_move(&pb, LOG);
+			str_len = strlen(TLV_DATA(rep_tlv)) + 1;
+			skb_put(reply, TLV_SPACE(str_len));
+			TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+		}
+	}
+	spin_unlock_bh(&print_lock);
+	return reply;
+}
+
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
new file mode 100644
index 0000000..c6b2a64
--- /dev/null
+++ b/net/tipc/dbg.h
@@ -0,0 +1,59 @@
+/*
+ * net/tipc/dbg.h: Include file for TIPC print buffer routines
+ * 
+ * Copyright (c) 1997-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_DBG_H
+#define _TIPC_DBG_H
+
+struct print_buf {
+	char *buf;
+	u32 size;
+	char *crs;
+	struct print_buf *next;
+};
+
+void printbuf_init(struct print_buf *pb, char *buf, u32 sz);
+void printbuf_reset(struct print_buf *pb);
+int  printbuf_empty(struct print_buf *pb);
+int  printbuf_validate(struct print_buf *pb);
+void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
+
+void log_reinit(int log_size);
+void log_stop(void);
+
+struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *log_dump(void);
+
+#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
new file mode 100644
index 0000000..b106ef1
--- /dev/null
+++ b/net/tipc/discover.c
@@ -0,0 +1,318 @@
+/*
+ * net/tipc/discover.c
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "link.h"
+#include "zone.h"
+#include "discover.h"
+#include "port.h"
+#include "name_table.h"
+
+#define TIPC_LINK_REQ_INIT	125	/* min delay during bearer start up */
+#define TIPC_LINK_REQ_FAST	2000	/* normal delay if bearer has no links */
+#define TIPC_LINK_REQ_SLOW	600000	/* normal delay if bearer has links */
+
+#if 0
+#define  GET_NODE_INFO         300
+#define  GET_NODE_INFO_RESULT  301
+#define  FORWARD_LINK_PROBE    302
+#define  LINK_REQUEST_REJECTED 303
+#define  LINK_REQUEST_ACCEPTED 304
+#define  DROP_LINK_REQUEST     305
+#define  CHECK_LINK_COUNT      306
+#endif
+
+/* 
+ * TODO: Most of the inter-cluster setup stuff should be
+ * rewritten, and be made conformant with specification.
+ */ 
+
+
+/**
+ * struct link_req - information about an ongoing link setup request
+ * @bearer: bearer issuing requests
+ * @dest: destination address for request messages
+ * @buf: request message to be (repeatedly) sent
+ * @timer: timer governing period between requests
+ * @timer_intv: current interval between requests (in ms)
+ */
+struct link_req {
+	struct bearer *bearer;
+	struct tipc_media_addr dest;
+	struct sk_buff *buf;
+	struct timer_list timer;
+	unsigned int timer_intv;
+};
+
+
+#if 0
+int disc_create_link(const struct tipc_link_create *argv) 
+{
+	/* 
+	 * Code for inter cluster link setup here 
+	 */
+	return TIPC_OK;
+}
+#endif
+
+/*
+ * disc_lost_link(): A link has lost contact
+ */
+
+void disc_link_event(u32 addr, char *name, int up) 
+{
+	if (in_own_cluster(addr))
+		return;
+	/* 
+	 * Code for inter cluster link setup here 
+	 */
+}
+
+/** 
+ * disc_init_msg - initialize a link setup message
+ * @type: message type (request or response)
+ * @req_links: number of links associated with message
+ * @dest_domain: network domain of node(s) which should respond to message
+ * @b_ptr: ptr to bearer issuing message
+ */
+
+struct sk_buff *disc_init_msg(u32 type,
+			      u32 req_links,
+			      u32 dest_domain,
+			      struct bearer *b_ptr)
+{
+	struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
+	struct tipc_msg *msg;
+
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
+			 dest_domain);
+		msg_set_non_seq(msg);
+		msg_set_req_links(msg, req_links);
+		msg_set_dest_domain(msg, dest_domain);
+		msg_set_bc_netid(msg, tipc_net_id);
+		msg_set_media_addr(msg, &b_ptr->publ.addr);
+	}
+	return buf;
+}
+
+/**
+ * disc_recv_msg - handle incoming link setup message (request or response)
+ * @buf: buffer containing message
+ */
+
+void disc_recv_msg(struct sk_buff *buf)
+{
+	struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
+	struct link *link;
+	struct tipc_media_addr media_addr;
+	struct tipc_msg *msg = buf_msg(buf);
+	u32 dest = msg_dest_domain(msg);
+	u32 orig = msg_prevnode(msg);
+	u32 net_id = msg_bc_netid(msg);
+	u32 type = msg_type(msg);
+
+	msg_get_media_addr(msg,&media_addr);
+	msg_dbg(msg, "RECV:");
+	buf_discard(buf);
+
+	if (net_id != tipc_net_id)
+		return;
+	if (!addr_domain_valid(dest))
+		return;
+	if (!addr_node_valid(orig))
+		return;
+	if (orig == tipc_own_addr)
+		return;
+	if (!in_scope(dest, tipc_own_addr))
+		return;
+	if (is_slave(tipc_own_addr) && is_slave(orig))
+		return;
+	if (is_slave(orig) && !in_own_cluster(orig))
+		return;
+	if (in_own_cluster(orig)) {
+		/* Always accept link here */
+		struct sk_buff *rbuf;
+		struct tipc_media_addr *addr;
+		struct node *n_ptr = node_find(orig);
+		int link_up;
+		dbg(" in own cluster\n");
+		if (n_ptr == NULL) {
+			n_ptr = node_create(orig);
+		}
+		if (n_ptr == NULL) {
+			warn("Memory squeeze; Failed to create node\n");
+			return;
+		}
+		spin_lock_bh(&n_ptr->lock);
+		link = n_ptr->links[b_ptr->identity];
+		if (!link) {
+			dbg("creating link\n");
+			link = link_create(b_ptr, orig, &media_addr);
+			if (!link) {
+				spin_unlock_bh(&n_ptr->lock);                
+				return;
+			}
+		}
+		addr = &link->media_addr;
+		if (memcmp(addr, &media_addr, sizeof(*addr))) {
+			char addr_string[16];
+
+			warn("New bearer address for %s\n", 
+			     addr_string_fill(addr_string, orig));
+			memcpy(addr, &media_addr, sizeof(*addr));
+			link_reset(link);     
+		}
+		link_up = link_is_up(link);
+		spin_unlock_bh(&n_ptr->lock);                
+		if ((type == DSC_RESP_MSG) || link_up)
+			return;
+		rbuf = disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
+		if (rbuf != NULL) {
+			msg_dbg(buf_msg(rbuf),"SEND:");
+			b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr);
+			buf_discard(rbuf);
+		}
+	}
+}
+
+/**
+ * disc_stop_link_req - stop sending periodic link setup requests
+ * @req: ptr to link request structure
+ */
+
+void disc_stop_link_req(struct link_req *req) 
+{
+	if (!req)
+		return;
+		
+	k_cancel_timer(&req->timer);
+	k_term_timer(&req->timer);
+	buf_discard(req->buf);
+	kfree(req);
+} 
+
+/**
+ * disc_update_link_req - update frequency of periodic link setup requests
+ * @req: ptr to link request structure
+ */
+
+void disc_update_link_req(struct link_req *req) 
+{
+	if (!req)
+		return;
+
+	if (req->timer_intv == TIPC_LINK_REQ_SLOW) {
+		if (!req->bearer->nodes.count) {
+			req->timer_intv = TIPC_LINK_REQ_FAST;
+			k_start_timer(&req->timer, req->timer_intv);
+		}
+	} else if (req->timer_intv == TIPC_LINK_REQ_FAST) {
+		if (req->bearer->nodes.count) {
+			req->timer_intv = TIPC_LINK_REQ_SLOW;
+			k_start_timer(&req->timer, req->timer_intv);
+		}
+	} else {
+		/* leave timer "as is" if haven't yet reached a "normal" rate */
+	}
+} 
+
+/**
+ * disc_timeout - send a periodic link setup request
+ * @req: ptr to link request structure
+ * 
+ * Called whenever a link setup request timer associated with a bearer expires.
+ */
+
+static void disc_timeout(struct link_req *req) 
+{
+	spin_lock_bh(&req->bearer->publ.lock);
+
+	req->bearer->media->send_msg(req->buf, &req->bearer->publ, &req->dest);
+
+	if ((req->timer_intv == TIPC_LINK_REQ_SLOW) ||
+	    (req->timer_intv == TIPC_LINK_REQ_FAST)) {
+		/* leave timer interval "as is" if already at a "normal" rate */
+	} else {
+		req->timer_intv *= 2;
+		if (req->timer_intv > TIPC_LINK_REQ_SLOW)
+			req->timer_intv = TIPC_LINK_REQ_SLOW;
+		if ((req->timer_intv == TIPC_LINK_REQ_FAST) && 
+		    (req->bearer->nodes.count))
+			req->timer_intv = TIPC_LINK_REQ_SLOW;
+	}
+	k_start_timer(&req->timer, req->timer_intv);
+
+	spin_unlock_bh(&req->bearer->publ.lock);
+}
+
+/**
+ * disc_init_link_req - start sending periodic link setup requests
+ * @b_ptr: ptr to bearer issuing requests
+ * @dest: destination address for request messages
+ * @dest_domain: network domain of node(s) which should respond to message
+ * @req_links: max number of desired links
+ * 
+ * Returns pointer to link request structure, or NULL if unable to create.
+ */
+
+struct link_req *disc_init_link_req(struct bearer *b_ptr, 
+				    const struct tipc_media_addr *dest,
+				    u32 dest_domain,
+				    u32 req_links) 
+{
+	struct link_req *req;
+
+	req = (struct link_req *)kmalloc(sizeof(*req), GFP_ATOMIC);
+	if (!req)
+		return NULL;
+
+	req->buf = disc_init_msg(DSC_REQ_MSG, req_links, dest_domain, b_ptr);
+	if (!req->buf) {
+		kfree(req);
+		return NULL;
+	}
+
+	memcpy(&req->dest, dest, sizeof(*dest));
+	req->bearer = b_ptr;
+	req->timer_intv = TIPC_LINK_REQ_INIT;
+	k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
+	k_start_timer(&req->timer, req->timer_intv);
+	return req;
+} 
+
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
new file mode 100644
index 0000000..2a6114d
--- /dev/null
+++ b/net/tipc/discover.h
@@ -0,0 +1,58 @@
+/*
+ * net/tipc/discover.h
+ *
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_DISCOVER_H
+#define _TIPC_DISCOVER_H
+
+#include <linux/tipc.h>
+
+struct link_req;
+
+struct link_req *disc_init_link_req(struct bearer *b_ptr, 
+			            const struct tipc_media_addr *dest,
+			            u32 dest_domain,
+			            u32 req_links);
+void disc_update_link_req(struct link_req *req);
+void disc_stop_link_req(struct link_req *req);
+
+void disc_recv_msg(struct sk_buff *buf);
+
+void disc_link_event(u32 addr, char *name, int up);
+#if 0
+int  disc_create_link(const struct tipc_link_create *argv);
+#endif
+
+#endif
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
new file mode 100644
index 0000000..34d0462
--- /dev/null
+++ b/net/tipc/eth_media.c
@@ -0,0 +1,299 @@
+/*
+ * net/tipc/eth_media.c: Ethernet bearer support for TIPC
+ * 
+ * Copyright (c) 2001-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <net/tipc/tipc.h>
+#include <net/tipc/tipc_bearer.h>
+#include <net/tipc/tipc_msg.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+
+#define MAX_ETH_BEARERS		2
+#define TIPC_PROTOCOL		0x88ca
+#define ETH_LINK_PRIORITY	10
+#define ETH_LINK_TOLERANCE	TIPC_DEF_LINK_TOL
+
+
+/**
+ * struct eth_bearer - Ethernet bearer data structure
+ * @bearer: ptr to associated "generic" bearer structure
+ * @dev: ptr to associated Ethernet network device
+ * @tipc_packet_type: used in binding TIPC to Ethernet driver
+ */
+ 
+struct eth_bearer {
+	struct tipc_bearer *bearer;
+	struct net_device *dev;
+	struct packet_type tipc_packet_type;
+};
+
+static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
+static int eth_started = 0;
+static struct notifier_block notifier;
+
+/**
+ * send_msg - send a TIPC message out over an Ethernet interface 
+ */
+
+static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, 
+		    struct tipc_media_addr *dest)
+{
+	struct sk_buff *clone;
+	struct net_device *dev;
+
+	clone = skb_clone(buf, GFP_ATOMIC);
+	if (clone) {
+		clone->nh.raw = clone->data;
+		dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
+		clone->dev = dev;
+		dev->hard_header(clone, dev, TIPC_PROTOCOL, 
+				 &dest->dev_addr.eth_addr,
+				 dev->dev_addr, clone->len);
+		dev_queue_xmit(clone);
+	}
+	return TIPC_OK;
+}
+
+/**
+ * recv_msg - handle incoming TIPC message from an Ethernet interface
+ * 
+ * Routine truncates any Ethernet padding/CRC appended to the message,
+ * and ensures message size matches actual length
+ */
+
+static int recv_msg(struct sk_buff *buf, struct net_device *dev, 
+		    struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
+	u32 size;
+
+	if (likely(eb_ptr->bearer)) {
+		size = msg_size((struct tipc_msg *)buf->data);
+		skb_trim(buf, size);
+		if (likely(buf->len == size)) {
+			buf->next = NULL;
+			tipc_recv_msg(buf, eb_ptr->bearer);
+		} else {
+			kfree_skb(buf);
+		}
+	} else {
+		kfree_skb(buf);
+	}
+	return TIPC_OK;
+}
+
+/**
+ * enable_bearer - attach TIPC bearer to an Ethernet interface 
+ */
+
+static int enable_bearer(struct tipc_bearer *tb_ptr)
+{
+	struct net_device *dev = dev_base;
+	struct eth_bearer *eb_ptr = &eth_bearers[0];
+	struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
+	char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+
+	/* Find device with specified name */
+
+	while (dev && dev->name &&
+	       (memcmp(dev->name, driver_name, strlen(dev->name)))) {
+		dev = dev->next;
+	}
+	if (!dev)
+		return -ENODEV;
+
+	/* Find Ethernet bearer for device (or create one) */
+
+	for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++);
+	if (eb_ptr == stop)
+		return -EDQUOT;
+	if (!eb_ptr->dev) {
+		eb_ptr->dev = dev;
+		eb_ptr->tipc_packet_type.type = __constant_htons(TIPC_PROTOCOL);
+		eb_ptr->tipc_packet_type.dev = dev;
+		eb_ptr->tipc_packet_type.func = recv_msg;
+		eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
+		INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
+		dev_hold(dev);
+		dev_add_pack(&eb_ptr->tipc_packet_type);
+	}
+
+	/* Associate TIPC bearer with Ethernet bearer */
+
+	eb_ptr->bearer = tb_ptr;
+	tb_ptr->usr_handle = (void *)eb_ptr;
+	tb_ptr->mtu = dev->mtu;
+	tb_ptr->blocked = 0; 
+	tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
+	memcpy(&tb_ptr->addr.dev_addr, &dev->dev_addr, ETH_ALEN);
+	return 0;
+}
+
+/**
+ * disable_bearer - detach TIPC bearer from an Ethernet interface 
+ *
+ * We really should do dev_remove_pack() here, but this function can not be
+ * called at tasklet level. => Use eth_bearer->bearer as a flag to throw away
+ * incoming buffers, & postpone dev_remove_pack() to eth_media_stop() on exit.
+ */
+
+static void disable_bearer(struct tipc_bearer *tb_ptr)
+{
+	((struct eth_bearer *)tb_ptr->usr_handle)->bearer = 0;
+}
+
+/**
+ * recv_notification - handle device updates from OS
+ *
+ * Change the state of the Ethernet bearer (if any) associated with the 
+ * specified device.
+ */
+
+static int recv_notification(struct notifier_block *nb, unsigned long evt, 
+			     void *dv)
+{
+	struct net_device *dev = (struct net_device *)dv;
+	struct eth_bearer *eb_ptr = &eth_bearers[0];
+	struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
+
+	while ((eb_ptr->dev != dev)) {
+		if (++eb_ptr == stop)
+			return NOTIFY_DONE;	/* couldn't find device */
+	}
+	if (!eb_ptr->bearer)
+		return NOTIFY_DONE;		/* bearer had been disabled */
+
+        eb_ptr->bearer->mtu = dev->mtu;
+
+	switch (evt) {
+	case NETDEV_CHANGE:
+		if (netif_carrier_ok(dev))
+			tipc_continue(eb_ptr->bearer);
+		else
+			tipc_block_bearer(eb_ptr->bearer->name);
+		break;
+	case NETDEV_UP:
+		tipc_continue(eb_ptr->bearer);
+		break;
+	case NETDEV_DOWN:
+		tipc_block_bearer(eb_ptr->bearer->name);
+		break;
+	case NETDEV_CHANGEMTU:
+        case NETDEV_CHANGEADDR:
+		tipc_block_bearer(eb_ptr->bearer->name);
+                tipc_continue(eb_ptr->bearer);
+		break;
+	case NETDEV_UNREGISTER:
+        case NETDEV_CHANGENAME:
+		tipc_disable_bearer(eb_ptr->bearer->name);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+/**
+ * eth_addr2str - convert Ethernet address to string
+ */
+
+static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
+{                       
+	unchar *addr = (unchar *)&a->dev_addr;
+
+	if (str_size < 18)
+		*str_buf = '\0';
+	else
+		sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+	return str_buf;
+}
+
+/**
+ * eth_media_start - activate Ethernet bearer support
+ *
+ * Register Ethernet media type with TIPC bearer code.  Also register
+ * with OS for notifications about device state changes.
+ */
+
+int eth_media_start(void)
+{                       
+	struct tipc_media_addr bcast_addr;
+	int res;
+
+	if (eth_started)
+		return -EINVAL;
+
+	memset(&bcast_addr, 0xff, sizeof(bcast_addr));
+	memset(eth_bearers, 0, sizeof(eth_bearers));
+
+	res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
+				  enable_bearer, disable_bearer, send_msg, 
+				  eth_addr2str, &bcast_addr, ETH_LINK_PRIORITY, 
+				  ETH_LINK_TOLERANCE, TIPC_DEF_LINK_WIN);
+	if (res)
+		return res;
+
+	notifier.notifier_call = &recv_notification;
+	notifier.priority = 0;
+	res = register_netdevice_notifier(&notifier);
+	if (!res)
+		eth_started = 1;
+	return res;
+}
+
+/**
+ * eth_media_stop - deactivate Ethernet bearer support
+ */
+
+void eth_media_stop(void)
+{
+	int i;
+
+	if (!eth_started)
+		return;
+
+	unregister_netdevice_notifier(&notifier);
+	for (i = 0; i < MAX_ETH_BEARERS ; i++) {
+		if (eth_bearers[i].bearer) {
+			eth_bearers[i].bearer->blocked = 1;
+			eth_bearers[i].bearer = 0;
+		}
+		if (eth_bearers[i].dev) {
+			dev_remove_pack(&eth_bearers[i].tipc_packet_type);
+			dev_put(eth_bearers[i].dev);
+		}
+	}
+	memset(&eth_bearers, 0, sizeof(eth_bearers));
+	eth_started = 0;
+}
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
new file mode 100644
index 0000000..f320010
--- /dev/null
+++ b/net/tipc/handler.c
@@ -0,0 +1,132 @@
+/*
+ * net/tipc/handler.c: TIPC signal handling
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+struct queue_item {
+	struct list_head next_signal;
+	void (*handler) (unsigned long);
+	unsigned long data;
+};
+
+static kmem_cache_t *tipc_queue_item_cache;
+static struct list_head signal_queue_head;
+static spinlock_t qitem_lock = SPIN_LOCK_UNLOCKED;
+static int handler_enabled = 0;
+
+static void process_signal_queue(unsigned long dummy);
+
+static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
+
+
+unsigned int k_signal(Handler routine, unsigned long argument)
+{
+	struct queue_item *item;
+
+	if (!handler_enabled) {
+		err("Signal request ignored by handler\n");
+		return -ENOPROTOOPT;
+	}
+
+	spin_lock_bh(&qitem_lock);
+	item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
+	if (!item) {
+		err("Signal queue out of memory\n");
+		spin_unlock_bh(&qitem_lock);
+		return -ENOMEM;
+	}
+	item->handler = routine;
+	item->data = argument;
+	list_add_tail(&item->next_signal, &signal_queue_head);
+	spin_unlock_bh(&qitem_lock);
+	tasklet_schedule(&tipc_tasklet);
+	return 0;
+}
+
+static void process_signal_queue(unsigned long dummy)
+{
+	struct queue_item *__volatile__ item;
+	struct list_head *l, *n;
+
+	spin_lock_bh(&qitem_lock);
+	list_for_each_safe(l, n, &signal_queue_head) {
+		item = list_entry(l, struct queue_item, next_signal);
+		list_del(&item->next_signal);
+		spin_unlock_bh(&qitem_lock);
+		item->handler(item->data);
+		spin_lock_bh(&qitem_lock);
+		kmem_cache_free(tipc_queue_item_cache, item);
+	}
+	spin_unlock_bh(&qitem_lock);
+}
+
+int handler_start(void)
+{
+	tipc_queue_item_cache = 
+		kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
+				  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!tipc_queue_item_cache)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&signal_queue_head);
+	tasklet_enable(&tipc_tasklet);
+	handler_enabled = 1;
+	return 0;
+}
+
+void handler_stop(void)
+{
+	struct list_head *l, *n;
+	struct queue_item *item; 
+
+	if (!handler_enabled)
+		return;
+
+	handler_enabled = 0;
+	tasklet_disable(&tipc_tasklet);
+	tasklet_kill(&tipc_tasklet);
+
+	spin_lock_bh(&qitem_lock);
+	list_for_each_safe(l, n, &signal_queue_head) {
+		item = list_entry(l, struct queue_item, next_signal);
+		list_del(&item->next_signal);
+		kmem_cache_free(tipc_queue_item_cache, item);
+	}
+	spin_unlock_bh(&qitem_lock);
+
+	kmem_cache_destroy(tipc_queue_item_cache);
+}
+
diff --git a/net/tipc/link.c b/net/tipc/link.c
new file mode 100644
index 0000000..7265f4b
--- /dev/null
+++ b/net/tipc/link.c
@@ -0,0 +1,3167 @@
+/*
+ * net/tipc/link.c: TIPC link code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "link.h"
+#include "net.h"
+#include "node.h"
+#include "port.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "name_distr.h"
+#include "bearer.h"
+#include "name_table.h"
+#include "discover.h"
+#include "config.h"
+#include "bcast.h"
+
+
+/* 
+ * Limit for deferred reception queue: 
+ */
+
+#define DEF_QUEUE_LIMIT 256u
+
+/* 
+ * Link state events: 
+ */
+
+#define  STARTING_EVT    856384768	/* link processing trigger */
+#define  TRAFFIC_MSG_EVT 560815u	/* rx'd ??? */
+#define  TIMEOUT_EVT     560817u	/* link timer expired */
+
+/*   
+ * The following two 'message types' is really just implementation 
+ * data conveniently stored in the message header. 
+ * They must not be considered part of the protocol
+ */
+#define OPEN_MSG   0
+#define CLOSED_MSG 1
+
+/* 
+ * State value stored in 'exp_msg_count'
+ */
+
+#define START_CHANGEOVER 100000u
+
+/**
+ * struct link_name - deconstructed link name
+ * @addr_local: network address of node at this end
+ * @if_local: name of interface at this end
+ * @addr_peer: network address of node at far end
+ * @if_peer: name of interface at far end
+ */
+
+struct link_name {
+	u32 addr_local;
+	char if_local[TIPC_MAX_IF_NAME];
+	u32 addr_peer;
+	char if_peer[TIPC_MAX_IF_NAME];
+};
+
+#if 0
+
+/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
+
+/** 
+ * struct link_event - link up/down event notification
+ */
+
+struct link_event {
+	u32 addr;
+	int up;
+	void (*fcn)(u32, char *, int);
+	char name[TIPC_MAX_LINK_NAME];
+};
+
+#endif
+
+static void link_handle_out_of_seq_msg(struct link *l_ptr,
+				       struct sk_buff *buf);
+static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
+static int  link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf);
+static void link_set_supervision_props(struct link *l_ptr, u32 tolerance);
+static int  link_send_sections_long(struct port *sender,
+				    struct iovec const *msg_sect,
+				    u32 num_sect, u32 destnode);
+static void link_check_defragm_bufs(struct link *l_ptr);
+static void link_state_event(struct link *l_ptr, u32 event);
+static void link_reset_statistics(struct link *l_ptr);
+static void link_print(struct link *l_ptr, struct print_buf *buf, 
+		       const char *str);
+
+/*
+ * Debugging code used by link routines only
+ *
+ * When debugging link problems on a system that has multiple links,
+ * the standard TIPC debugging routines may not be useful since they
+ * allow the output from multiple links to be intermixed.  For this reason
+ * routines of the form "dbg_link_XXX()" have been created that will capture
+ * debug info into a link's personal print buffer, which can then be dumped
+ * into the TIPC system log (LOG) upon request.
+ *
+ * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
+ * of the print buffer used by each link.  If LINK_LOG_BUF_SIZE is set to 0,
+ * the dbg_link_XXX() routines simply send their output to the standard 
+ * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful
+ * when there is only a single link in the system being debugged.
+ *
+ * Notes:
+ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
+ * - "l_ptr" must be valid when using dbg_link_XXX() macros  
+ */
+
+#define LINK_LOG_BUF_SIZE 0
+
+#define dbg_link(fmt, arg...)  do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
+#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) msg_print(&l_ptr->print_buf, msg, txt); } while(0)
+#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
+#define dbg_link_dump() do { \
+	if (LINK_LOG_BUF_SIZE) { \
+		tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
+		printbuf_move(LOG, &l_ptr->print_buf); \
+	} \
+} while (0)
+
+static inline void dbg_print_link(struct link *l_ptr, const char *str)
+{
+	if (DBG_OUTPUT)
+		link_print(l_ptr, DBG_OUTPUT, str);
+}
+
+static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
+{
+	if (DBG_OUTPUT) {
+		struct sk_buff *buf = root_buf;
+
+		while (buf) {
+			msg_dbg(buf_msg(buf), "In chain: ");
+			buf = buf->next;
+		}
+	}
+}
+
+/*
+ *  Simple inlined link routines
+ */
+
+static inline unsigned int align(unsigned int i)
+{
+	return (i + 3) & ~3u;
+}
+
+static inline int link_working_working(struct link *l_ptr)
+{
+	return (l_ptr->state == WORKING_WORKING);
+}
+
+static inline int link_working_unknown(struct link *l_ptr)
+{
+	return (l_ptr->state == WORKING_UNKNOWN);
+}
+
+static inline int link_reset_unknown(struct link *l_ptr)
+{
+	return (l_ptr->state == RESET_UNKNOWN);
+}
+
+static inline int link_reset_reset(struct link *l_ptr)
+{
+	return (l_ptr->state == RESET_RESET);
+}
+
+static inline int link_blocked(struct link *l_ptr)
+{
+	return (l_ptr->exp_msg_count || l_ptr->blocked);
+}
+
+static inline int link_congested(struct link *l_ptr)
+{
+	return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
+}
+
+static inline u32 link_max_pkt(struct link *l_ptr)
+{
+	return l_ptr->max_pkt;
+}
+
+static inline void link_init_max_pkt(struct link *l_ptr)
+{
+	u32 max_pkt;
+	
+	max_pkt = (l_ptr->b_ptr->publ.mtu & ~3);
+	if (max_pkt > MAX_MSG_SIZE)
+		max_pkt = MAX_MSG_SIZE;
+
+        l_ptr->max_pkt_target = max_pkt;
+	if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
+		l_ptr->max_pkt = l_ptr->max_pkt_target;
+	else 
+		l_ptr->max_pkt = MAX_PKT_DEFAULT;
+
+        l_ptr->max_pkt_probes = 0;
+}
+
+static inline u32 link_next_sent(struct link *l_ptr)
+{
+	if (l_ptr->next_out)
+		return msg_seqno(buf_msg(l_ptr->next_out));
+	return mod(l_ptr->next_out_no);
+}
+
+static inline u32 link_last_sent(struct link *l_ptr)
+{
+	return mod(link_next_sent(l_ptr) - 1);
+}
+
+/*
+ *  Simple non-inlined link routines (i.e. referenced outside this file)
+ */
+
+int link_is_up(struct link *l_ptr)
+{
+	if (!l_ptr)
+		return 0;
+	return (link_working_working(l_ptr) || link_working_unknown(l_ptr));
+}
+
+int link_is_active(struct link *l_ptr)
+{
+	return ((l_ptr->owner->active_links[0] == l_ptr) ||
+		(l_ptr->owner->active_links[1] == l_ptr));
+}
+
+/**
+ * link_name_validate - validate & (optionally) deconstruct link name
+ * @name - ptr to link name string
+ * @name_parts - ptr to area for link name components (or NULL if not needed)
+ * 
+ * Returns 1 if link name is valid, otherwise 0.
+ */
+
+static int link_name_validate(const char *name, struct link_name *name_parts)
+{
+	char name_copy[TIPC_MAX_LINK_NAME];
+	char *addr_local;
+	char *if_local;
+	char *addr_peer;
+	char *if_peer;
+	char dummy;
+	u32 z_local, c_local, n_local;
+	u32 z_peer, c_peer, n_peer;
+	u32 if_local_len;
+	u32 if_peer_len;
+
+	/* copy link name & ensure length is OK */
+
+	name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
+	/* need above in case non-Posix strncpy() doesn't pad with nulls */
+	strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
+	if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
+		return 0;
+
+	/* ensure all component parts of link name are present */
+
+	addr_local = name_copy;
+	if ((if_local = strchr(addr_local, ':')) == NULL)
+		return 0;
+	*(if_local++) = 0;
+	if ((addr_peer = strchr(if_local, '-')) == NULL)
+		return 0;
+	*(addr_peer++) = 0;
+	if_local_len = addr_peer - if_local;
+	if ((if_peer = strchr(addr_peer, ':')) == NULL)
+		return 0;
+	*(if_peer++) = 0;
+	if_peer_len = strlen(if_peer) + 1;
+
+	/* validate component parts of link name */
+
+	if ((sscanf(addr_local, "%u.%u.%u%c",
+		    &z_local, &c_local, &n_local, &dummy) != 3) ||
+	    (sscanf(addr_peer, "%u.%u.%u%c",
+		    &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
+	    (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
+	    (z_peer  > 255) || (c_peer  > 4095) || (n_peer  > 4095) ||
+	    (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) || 
+	    (if_peer_len  <= 1) || (if_peer_len  > TIPC_MAX_IF_NAME) || 
+	    (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
+	    (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
+		return 0;
+
+	/* return link name components, if necessary */
+
+	if (name_parts) {
+		name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
+		strcpy(name_parts->if_local, if_local);
+		name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
+		strcpy(name_parts->if_peer, if_peer);
+	}
+	return 1;
+}
+
+/**
+ * link_timeout - handle expiration of link timer
+ * @l_ptr: pointer to link
+ * 
+ * This routine must not grab "net_lock" to avoid a potential deadlock conflict
+ * with link_delete().  (There is no risk that the node will be deleted by
+ * another thread because link_delete() always cancels the link timer before
+ * node_delete() is called.)
+ */
+
+static void link_timeout(struct link *l_ptr)
+{
+	node_lock(l_ptr->owner);
+
+	/* update counters used in statistical profiling of send traffic */
+
+	l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
+	l_ptr->stats.queue_sz_counts++;
+
+	if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
+		l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
+
+	if (l_ptr->first_out) {
+		struct tipc_msg *msg = buf_msg(l_ptr->first_out);
+		u32 length = msg_size(msg);
+
+		if ((msg_user(msg) == MSG_FRAGMENTER)
+		    && (msg_type(msg) == FIRST_FRAGMENT)) {
+			length = msg_size(msg_get_wrapped(msg));
+		}
+		if (length) {
+			l_ptr->stats.msg_lengths_total += length;
+			l_ptr->stats.msg_length_counts++;
+			if (length <= 64)
+				l_ptr->stats.msg_length_profile[0]++;
+			else if (length <= 256)
+				l_ptr->stats.msg_length_profile[1]++;
+			else if (length <= 1024)
+				l_ptr->stats.msg_length_profile[2]++;
+			else if (length <= 4096)
+				l_ptr->stats.msg_length_profile[3]++;
+			else if (length <= 16384)
+				l_ptr->stats.msg_length_profile[4]++;
+			else if (length <= 32768)
+				l_ptr->stats.msg_length_profile[5]++;
+			else
+				l_ptr->stats.msg_length_profile[6]++;
+		}
+	}
+
+	/* do all other link processing performed on a periodic basis */
+
+	link_check_defragm_bufs(l_ptr);
+
+	link_state_event(l_ptr, TIMEOUT_EVT);
+
+	if (l_ptr->next_out)
+		link_push_queue(l_ptr);
+
+	node_unlock(l_ptr->owner);
+}
+
+static inline void link_set_timer(struct link *l_ptr, u32 time)
+{
+	k_start_timer(&l_ptr->timer, time);
+}
+
+/**
+ * link_create - create a new link
+ * @b_ptr: pointer to associated bearer
+ * @peer: network address of node at other end of link
+ * @media_addr: media address to use when sending messages over link
+ * 
+ * Returns pointer to link.
+ */
+
+struct link *link_create(struct bearer *b_ptr, const u32 peer,
+			 const struct tipc_media_addr *media_addr)
+{
+	struct link *l_ptr;
+	struct tipc_msg *msg;
+	char *if_name;
+
+	l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
+	if (!l_ptr) {
+		warn("Memory squeeze; Failed to create link\n");
+		return NULL;
+	}
+	memset(l_ptr, 0, sizeof(*l_ptr));
+
+	l_ptr->addr = peer;
+	if_name = strchr(b_ptr->publ.name, ':') + 1;
+	sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
+		tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
+		tipc_node(tipc_own_addr), 
+		if_name,
+		tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
+		/* note: peer i/f is appended to link name by reset/activate */
+	memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
+	k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
+	list_add_tail(&l_ptr->link_list, &b_ptr->links);
+	l_ptr->checkpoint = 1;
+	l_ptr->b_ptr = b_ptr;
+	link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
+	l_ptr->state = RESET_UNKNOWN;
+
+	l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
+	msg = l_ptr->pmsg;
+	msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+	msg_set_size(msg, sizeof(l_ptr->proto_msg));
+	msg_set_session(msg, tipc_random);
+	msg_set_bearer_id(msg, b_ptr->identity);
+	strcpy((char *)msg_data(msg), if_name);
+
+	l_ptr->priority = b_ptr->priority;
+	link_set_queue_limits(l_ptr, b_ptr->media->window);
+
+	link_init_max_pkt(l_ptr);
+
+	l_ptr->next_out_no = 1;
+	INIT_LIST_HEAD(&l_ptr->waiting_ports);
+
+	link_reset_statistics(l_ptr);
+
+	l_ptr->owner = node_attach_link(l_ptr);
+	if (!l_ptr->owner) {
+		kfree(l_ptr);
+		return NULL;
+	}
+
+	if (LINK_LOG_BUF_SIZE) {
+		char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC);
+
+		if (!pb) {
+			kfree(l_ptr);
+			warn("Memory squeeze; Failed to create link\n");
+			return NULL;
+		}
+		printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
+	}
+
+	k_signal((Handler)link_start, (unsigned long)l_ptr);
+
+	dbg("link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
+	    l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
+	
+	return l_ptr;
+}
+
+/** 
+ * link_delete - delete a link
+ * @l_ptr: pointer to link
+ * 
+ * Note: 'net_lock' is write_locked, bearer is locked.
+ * This routine must not grab the node lock until after link timer cancellation
+ * to avoid a potential deadlock situation.  
+ */
+
+void link_delete(struct link *l_ptr)
+{
+	if (!l_ptr) {
+		err("Attempt to delete non-existent link\n");
+		return;
+	}
+
+	dbg("link_delete()\n");
+
+	k_cancel_timer(&l_ptr->timer);
+	
+	node_lock(l_ptr->owner);
+	link_reset(l_ptr);
+	node_detach_link(l_ptr->owner, l_ptr);
+	link_stop(l_ptr);
+	list_del_init(&l_ptr->link_list);
+	if (LINK_LOG_BUF_SIZE)
+		kfree(l_ptr->print_buf.buf);
+	node_unlock(l_ptr->owner);
+	k_term_timer(&l_ptr->timer);
+	kfree(l_ptr);
+}
+
+void link_start(struct link *l_ptr)
+{
+	dbg("link_start %x\n", l_ptr);
+	link_state_event(l_ptr, STARTING_EVT);
+}
+
+/**
+ * link_schedule_port - schedule port for deferred sending 
+ * @l_ptr: pointer to link
+ * @origport: reference to sending port
+ * @sz: amount of data to be sent
+ * 
+ * Schedules port for renewed sending of messages after link congestion 
+ * has abated.
+ */
+
+static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
+{
+	struct port *p_ptr;
+
+	spin_lock_bh(&port_list_lock);
+	p_ptr = port_lock(origport);
+	if (p_ptr) {
+		if (!p_ptr->wakeup)
+			goto exit;
+		if (!list_empty(&p_ptr->wait_list))
+			goto exit;
+		p_ptr->congested_link = l_ptr;
+		p_ptr->publ.congested = 1;
+		p_ptr->waiting_pkts = 1 + ((sz - 1) / link_max_pkt(l_ptr));
+		list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
+		l_ptr->stats.link_congs++;
+exit:
+		port_unlock(p_ptr);
+	}
+	spin_unlock_bh(&port_list_lock);
+	return -ELINKCONG;
+}
+
+void link_wakeup_ports(struct link *l_ptr, int all)
+{
+	struct port *p_ptr;
+	struct port *temp_p_ptr;
+	int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
+
+	if (all)
+		win = 100000;
+	if (win <= 0)
+		return;
+	if (!spin_trylock_bh(&port_list_lock))
+		return;
+	if (link_congested(l_ptr))
+		goto exit;
+	list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports, 
+				 wait_list) {
+		if (win <= 0)
+			break;
+		list_del_init(&p_ptr->wait_list);
+		p_ptr->congested_link = 0;
+		assert(p_ptr->wakeup);
+		spin_lock_bh(p_ptr->publ.lock);
+		p_ptr->publ.congested = 0;
+		p_ptr->wakeup(&p_ptr->publ);
+		win -= p_ptr->waiting_pkts;
+		spin_unlock_bh(p_ptr->publ.lock);
+	}
+
+exit:
+	spin_unlock_bh(&port_list_lock);
+}
+
+/** 
+ * link_release_outqueue - purge link's outbound message queue
+ * @l_ptr: pointer to link
+ */
+
+static void link_release_outqueue(struct link *l_ptr)
+{
+	struct sk_buff *buf = l_ptr->first_out;
+	struct sk_buff *next;
+
+	while (buf) {
+		next = buf->next;
+		buf_discard(buf);
+		buf = next;
+	}
+	l_ptr->first_out = NULL;
+	l_ptr->out_queue_size = 0;
+}
+
+/**
+ * link_reset_fragments - purge link's inbound message fragments queue
+ * @l_ptr: pointer to link
+ */
+
+void link_reset_fragments(struct link *l_ptr)
+{
+	struct sk_buff *buf = l_ptr->defragm_buf;
+	struct sk_buff *next;
+
+	while (buf) {
+		next = buf->next;
+		buf_discard(buf);
+		buf = next;
+	}
+	l_ptr->defragm_buf = NULL;
+}
+
+/** 
+ * link_stop - purge all inbound and outbound messages associated with link
+ * @l_ptr: pointer to link
+ */
+
+void link_stop(struct link *l_ptr)
+{
+	struct sk_buff *buf;
+	struct sk_buff *next;
+
+	buf = l_ptr->oldest_deferred_in;
+	while (buf) {
+		next = buf->next;
+		buf_discard(buf);
+		buf = next;
+	}
+
+	buf = l_ptr->first_out;
+	while (buf) {
+		next = buf->next;
+		buf_discard(buf);
+		buf = next;
+	}
+
+	link_reset_fragments(l_ptr);
+
+	buf_discard(l_ptr->proto_msg_queue);
+	l_ptr->proto_msg_queue = NULL;
+}
+
+#if 0
+
+/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
+
+static void link_recv_event(struct link_event *ev)
+{
+	ev->fcn(ev->addr, ev->name, ev->up);
+	kfree(ev);
+}
+
+static void link_send_event(void (*fcn)(u32 a, char *n, int up),
+			    struct link *l_ptr, int up)
+{
+	struct link_event *ev;
+	
+	ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev) {
+		warn("Link event allocation failure\n");
+		return;
+	}
+	ev->addr = l_ptr->addr;
+	ev->up = up;
+	ev->fcn = fcn;
+	memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME);
+	k_signal((Handler)link_recv_event, (unsigned long)ev);
+}
+
+#else
+
+#define link_send_event(fcn, l_ptr, up) do { } while (0)
+
+#endif
+
+void link_reset(struct link *l_ptr)
+{
+	struct sk_buff *buf;
+	u32 prev_state = l_ptr->state;
+	u32 checkpoint = l_ptr->next_in_no;
+	
+	msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
+
+        /* Link is down, accept any session: */
+	l_ptr->peer_session = 0;
+
+        /* Prepare for max packet size negotiation */
+	link_init_max_pkt(l_ptr);
+	
+	l_ptr->state = RESET_UNKNOWN;
+	dbg_link_state("Resetting Link\n");
+
+	if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
+		return;
+
+	node_link_down(l_ptr->owner, l_ptr);
+	bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
+#if 0
+	tipc_printf(CONS, "\nReset link <%s>\n", l_ptr->name);
+	dbg_link_dump();
+#endif
+	if (node_has_active_links(l_ptr->owner) &&
+	    l_ptr->owner->permit_changeover) {
+		l_ptr->reset_checkpoint = checkpoint;
+		l_ptr->exp_msg_count = START_CHANGEOVER;
+	}
+
+	/* Clean up all queues: */
+
+	link_release_outqueue(l_ptr);
+	buf_discard(l_ptr->proto_msg_queue);
+	l_ptr->proto_msg_queue = NULL;
+	buf = l_ptr->oldest_deferred_in;
+	while (buf) {
+		struct sk_buff *next = buf->next;
+		buf_discard(buf);
+		buf = next;
+	}
+	if (!list_empty(&l_ptr->waiting_ports))
+		link_wakeup_ports(l_ptr, 1);
+
+	l_ptr->retransm_queue_head = 0;
+	l_ptr->retransm_queue_size = 0;
+	l_ptr->last_out = NULL;
+	l_ptr->first_out = NULL;
+	l_ptr->next_out = NULL;
+	l_ptr->unacked_window = 0;
+	l_ptr->checkpoint = 1;
+	l_ptr->next_out_no = 1;
+	l_ptr->deferred_inqueue_sz = 0;
+	l_ptr->oldest_deferred_in = NULL;
+	l_ptr->newest_deferred_in = NULL;
+	l_ptr->fsm_msg_cnt = 0;
+	l_ptr->stale_count = 0;
+	link_reset_statistics(l_ptr);
+
+	link_send_event(cfg_link_event, l_ptr, 0);
+	if (!in_own_cluster(l_ptr->addr))
+		link_send_event(disc_link_event, l_ptr, 0);
+}
+
+
+static void link_activate(struct link *l_ptr)
+{
+	l_ptr->next_in_no = 1;
+	node_link_up(l_ptr->owner, l_ptr);
+	bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
+	link_send_event(cfg_link_event, l_ptr, 1);
+	if (!in_own_cluster(l_ptr->addr))
+		link_send_event(disc_link_event, l_ptr, 1);
+}
+
+/**
+ * link_state_event - link finite state machine
+ * @l_ptr: pointer to link
+ * @event: state machine event to process
+ */
+
+static void link_state_event(struct link *l_ptr, unsigned event)
+{
+	struct link *other; 
+	u32 cont_intv = l_ptr->continuity_interval;
+
+	if (!l_ptr->started && (event != STARTING_EVT))
+		return;		/* Not yet. */
+
+	if (link_blocked(l_ptr)) {
+		if (event == TIMEOUT_EVT) {
+			link_set_timer(l_ptr, cont_intv);
+		}
+		return;	  /* Changeover going on */
+	}
+	dbg_link("STATE_EV: <%s> ", l_ptr->name);
+
+	switch (l_ptr->state) {
+	case WORKING_WORKING:
+		dbg_link("WW/");
+		switch (event) {
+		case TRAFFIC_MSG_EVT:
+			dbg_link("TRF-");
+			/* fall through */
+		case ACTIVATE_MSG:
+			dbg_link("ACT\n");
+			break;
+		case TIMEOUT_EVT:
+			dbg_link("TIM ");
+			if (l_ptr->next_in_no != l_ptr->checkpoint) {
+				l_ptr->checkpoint = l_ptr->next_in_no;
+				if (bclink_acks_missing(l_ptr->owner)) {
+					link_send_proto_msg(l_ptr, STATE_MSG, 
+							    0, 0, 0, 0, 0);
+					l_ptr->fsm_msg_cnt++;
+				} else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
+					link_send_proto_msg(l_ptr, STATE_MSG, 
+							    1, 0, 0, 0, 0);
+					l_ptr->fsm_msg_cnt++;
+				}
+				link_set_timer(l_ptr, cont_intv);
+				break;
+			}
+			dbg_link(" -> WU\n");
+			l_ptr->state = WORKING_UNKNOWN;
+			l_ptr->fsm_msg_cnt = 0;
+			link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv / 4);
+			break;
+		case RESET_MSG:
+			dbg_link("RES -> RR\n");
+			link_reset(l_ptr);
+			l_ptr->state = RESET_RESET;
+			l_ptr->fsm_msg_cnt = 0;
+			link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		default:
+			err("Unknown link event %u in WW state\n", event);
+		}
+		break;
+	case WORKING_UNKNOWN:
+		dbg_link("WU/");
+		switch (event) {
+		case TRAFFIC_MSG_EVT:
+			dbg_link("TRF-");
+		case ACTIVATE_MSG:
+			dbg_link("ACT -> WW\n");
+			l_ptr->state = WORKING_WORKING;
+			l_ptr->fsm_msg_cnt = 0;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		case RESET_MSG:
+			dbg_link("RES -> RR\n");
+			link_reset(l_ptr);
+			l_ptr->state = RESET_RESET;
+			l_ptr->fsm_msg_cnt = 0;
+			link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		case TIMEOUT_EVT:
+			dbg_link("TIM ");
+			if (l_ptr->next_in_no != l_ptr->checkpoint) {
+				dbg_link("-> WW \n");
+				l_ptr->state = WORKING_WORKING;
+				l_ptr->fsm_msg_cnt = 0;
+				l_ptr->checkpoint = l_ptr->next_in_no;
+				if (bclink_acks_missing(l_ptr->owner)) {
+					link_send_proto_msg(l_ptr, STATE_MSG,
+							    0, 0, 0, 0, 0);
+					l_ptr->fsm_msg_cnt++;
+				}
+				link_set_timer(l_ptr, cont_intv);
+			} else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
+				dbg_link("Probing %u/%u,timer = %u ms)\n",
+					 l_ptr->fsm_msg_cnt, l_ptr->abort_limit,
+					 cont_intv / 4);
+				link_send_proto_msg(l_ptr, STATE_MSG, 
+						    1, 0, 0, 0, 0);
+				l_ptr->fsm_msg_cnt++;
+				link_set_timer(l_ptr, cont_intv / 4);
+			} else {	/* Link has failed */
+				dbg_link("-> RU (%u probes unanswered)\n",
+					 l_ptr->fsm_msg_cnt);
+				link_reset(l_ptr);
+				l_ptr->state = RESET_UNKNOWN;
+				l_ptr->fsm_msg_cnt = 0;
+				link_send_proto_msg(l_ptr, RESET_MSG,
+						    0, 0, 0, 0, 0);
+				l_ptr->fsm_msg_cnt++;
+				link_set_timer(l_ptr, cont_intv);
+			}
+			break;
+		default:
+			err("Unknown link event %u in WU state\n", event);
+		}
+		break;
+	case RESET_UNKNOWN:
+		dbg_link("RU/");
+		switch (event) {
+		case TRAFFIC_MSG_EVT:
+			dbg_link("TRF-\n");
+			break;
+		case ACTIVATE_MSG:
+			other = l_ptr->owner->active_links[0];
+			if (other && link_working_unknown(other)) {
+				dbg_link("ACT\n");
+				break;
+			}
+			dbg_link("ACT -> WW\n");
+			l_ptr->state = WORKING_WORKING;
+			l_ptr->fsm_msg_cnt = 0;
+			link_activate(l_ptr);
+			link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		case RESET_MSG:
+			dbg_link("RES \n");
+			dbg_link(" -> RR\n");
+			l_ptr->state = RESET_RESET;
+			l_ptr->fsm_msg_cnt = 0;
+			link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		case STARTING_EVT:
+			dbg_link("START-");
+			l_ptr->started = 1;
+			/* fall through */
+		case TIMEOUT_EVT:
+			dbg_link("TIM \n");
+			link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		default:
+			err("Unknown link event %u in RU state\n", event);
+		}
+		break;
+	case RESET_RESET:
+		dbg_link("RR/ ");
+		switch (event) {
+		case TRAFFIC_MSG_EVT:
+			dbg_link("TRF-");
+			/* fall through */
+		case ACTIVATE_MSG:
+			other = l_ptr->owner->active_links[0];
+			if (other && link_working_unknown(other)) {
+				dbg_link("ACT\n");
+				break;
+			}
+			dbg_link("ACT -> WW\n");
+			l_ptr->state = WORKING_WORKING;
+			l_ptr->fsm_msg_cnt = 0;
+			link_activate(l_ptr);
+			link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			break;
+		case RESET_MSG:
+			dbg_link("RES\n");
+			break;
+		case TIMEOUT_EVT:
+			dbg_link("TIM\n");
+			link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+			l_ptr->fsm_msg_cnt++;
+			link_set_timer(l_ptr, cont_intv);
+			dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt);
+			break;
+		default:
+			err("Unknown link event %u in RR state\n", event);
+		}
+		break;
+	default:
+		err("Unknown link state %u/%u\n", l_ptr->state, event);
+	}
+}
+
+/*
+ * link_bundle_buf(): Append contents of a buffer to
+ * the tail of an existing one. 
+ */
+
+static int link_bundle_buf(struct link *l_ptr,
+			   struct sk_buff *bundler, 
+			   struct sk_buff *buf)
+{
+	struct tipc_msg *bundler_msg = buf_msg(bundler);
+	struct tipc_msg *msg = buf_msg(buf);
+	u32 size = msg_size(msg);
+	u32 to_pos = align(msg_size(bundler_msg));
+	u32 rest = link_max_pkt(l_ptr) - to_pos;
+
+	if (msg_user(bundler_msg) != MSG_BUNDLER)
+		return 0;
+	if (msg_type(bundler_msg) != OPEN_MSG)
+		return 0;
+	if (rest < align(size))
+		return 0;
+
+	skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
+	memcpy(bundler->data + to_pos, buf->data, size);
+	msg_set_size(bundler_msg, to_pos + size);
+	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
+	dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
+	    msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg));
+	msg_dbg(msg, "PACKD:");
+	buf_discard(buf);
+	l_ptr->stats.sent_bundled++;
+	return 1;
+}
+
+static inline void link_add_to_outqueue(struct link *l_ptr, 
+					struct sk_buff *buf, 
+					struct tipc_msg *msg)
+{
+	u32 ack = mod(l_ptr->next_in_no - 1);
+	u32 seqno = mod(l_ptr->next_out_no++);
+
+	msg_set_word(msg, 2, ((ack << 16) | seqno));
+	msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
+	buf->next = NULL;
+	if (l_ptr->first_out) {
+		l_ptr->last_out->next = buf;
+		l_ptr->last_out = buf;
+	} else
+		l_ptr->first_out = l_ptr->last_out = buf;
+	l_ptr->out_queue_size++;
+}
+
+/* 
+ * link_send_buf() is the 'full path' for messages, called from 
+ * inside TIPC when the 'fast path' in tipc_send_buf
+ * has failed, and from link_send()
+ */
+
+int link_send_buf(struct link *l_ptr, struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	u32 size = msg_size(msg);
+	u32 dsz = msg_data_sz(msg);
+	u32 queue_size = l_ptr->out_queue_size;
+	u32 imp = msg_tot_importance(msg);
+	u32 queue_limit = l_ptr->queue_limit[imp];
+	u32 max_packet = link_max_pkt(l_ptr);
+
+	msg_set_prevnode(msg, tipc_own_addr);	/* If routed message */
+
+	/* Match msg importance against queue limits: */
+
+	if (unlikely(queue_size >= queue_limit)) {
+		if (imp <= TIPC_CRITICAL_IMPORTANCE) {
+			return link_schedule_port(l_ptr, msg_origport(msg),
+						  size);
+		}
+		msg_dbg(msg, "TIPC: Congestion, throwing away\n");
+		buf_discard(buf);
+		if (imp > CONN_MANAGER) {
+			warn("Resetting <%s>, send queue full", l_ptr->name);
+			link_reset(l_ptr);
+		}
+		return dsz;
+	}
+
+	/* Fragmentation needed ? */
+
+	if (size > max_packet)
+		return link_send_long_buf(l_ptr, buf);
+
+	/* Packet can be queued or sent: */
+
+	if (queue_size > l_ptr->stats.max_queue_sz)
+		l_ptr->stats.max_queue_sz = queue_size;
+
+	if (likely(!bearer_congested(l_ptr->b_ptr, l_ptr) && 
+		   !link_congested(l_ptr))) {
+		link_add_to_outqueue(l_ptr, buf, msg);
+
+		if (likely(bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
+			l_ptr->unacked_window = 0;
+		} else {
+			bearer_schedule(l_ptr->b_ptr, l_ptr);
+			l_ptr->stats.bearer_congs++;
+			l_ptr->next_out = buf;
+		}
+		return dsz;
+	}
+	/* Congestion: can message be bundled ?: */
+
+	if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
+	    (msg_user(msg) != MSG_FRAGMENTER)) {
+
+		/* Try adding message to an existing bundle */
+
+		if (l_ptr->next_out && 
+		    link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
+			bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
+			return dsz;
+		}
+
+		/* Try creating a new bundle */
+
+		if (size <= max_packet * 2 / 3) {
+			struct sk_buff *bundler = buf_acquire(max_packet);
+			struct tipc_msg bundler_hdr;
+
+			if (bundler) {
+				msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
+					 TIPC_OK, INT_H_SIZE, l_ptr->addr);
+				memcpy(bundler->data, (unchar *)&bundler_hdr, 
+				       INT_H_SIZE);
+				skb_trim(bundler, INT_H_SIZE);
+				link_bundle_buf(l_ptr, bundler, buf);
+				buf = bundler;
+				msg = buf_msg(buf);
+				l_ptr->stats.sent_bundles++;
+			}
+		}
+	}
+	if (!l_ptr->next_out)
+		l_ptr->next_out = buf;
+	link_add_to_outqueue(l_ptr, buf, msg);
+	bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
+	return dsz;
+}
+
+/* 
+ * link_send(): same as link_send_buf(), but the link to use has 
+ * not been selected yet, and the the owner node is not locked
+ * Called by TIPC internal users, e.g. the name distributor
+ */
+
+int link_send(struct sk_buff *buf, u32 dest, u32 selector)
+{
+	struct link *l_ptr;
+	struct node *n_ptr;
+	int res = -ELINKCONG;
+
+	read_lock_bh(&net_lock);
+	n_ptr = node_select(dest, selector);
+	if (n_ptr) {
+		node_lock(n_ptr);
+		l_ptr = n_ptr->active_links[selector & 1];
+		dbg("link_send: found link %x for dest %x\n", l_ptr, dest);
+		if (l_ptr) {
+			res = link_send_buf(l_ptr, buf);
+		}
+		node_unlock(n_ptr);
+	} else {
+		dbg("Attempt to send msg to unknown node:\n");
+		msg_dbg(buf_msg(buf),">>>");
+		buf_discard(buf);
+	}
+	read_unlock_bh(&net_lock);
+	return res;
+}
+
+/* 
+ * link_send_buf_fast: Entry for data messages where the 
+ * destination link is known and the header is complete,
+ * inclusive total message length. Very time critical.
+ * Link is locked. Returns user data length.
+ */
+
+static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
+				     u32 *used_max_pkt)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	int res = msg_data_sz(msg);
+
+	if (likely(!link_congested(l_ptr))) {
+		if (likely(msg_size(msg) <= link_max_pkt(l_ptr))) {
+			if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
+				link_add_to_outqueue(l_ptr, buf, msg);
+				if (likely(bearer_send(l_ptr->b_ptr, buf,
+						       &l_ptr->media_addr))) {
+					l_ptr->unacked_window = 0;
+					msg_dbg(msg,"SENT_FAST:");
+					return res;
+				}
+				dbg("failed sent fast...\n");
+				bearer_schedule(l_ptr->b_ptr, l_ptr);
+				l_ptr->stats.bearer_congs++;
+				l_ptr->next_out = buf;
+				return res;
+			}
+		}
+		else
+			*used_max_pkt = link_max_pkt(l_ptr);
+	}
+	return link_send_buf(l_ptr, buf);  /* All other cases */
+}
+
+/* 
+ * tipc_send_buf_fast: Entry for data messages where the 
+ * destination node is known and the header is complete,
+ * inclusive total message length.
+ * Returns user data length.
+ */
+int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
+{
+	struct link *l_ptr;
+	struct node *n_ptr;
+	int res;
+	u32 selector = msg_origport(buf_msg(buf)) & 1;
+	u32 dummy;
+
+	if (destnode == tipc_own_addr)
+		return port_recv_msg(buf);
+
+	read_lock_bh(&net_lock);
+	n_ptr = node_select(destnode, selector);
+	if (likely(n_ptr)) {
+		node_lock(n_ptr);
+		l_ptr = n_ptr->active_links[selector];
+		dbg("send_fast: buf %x selected %x, destnode = %x\n",
+		    buf, l_ptr, destnode);
+		if (likely(l_ptr)) {
+			res = link_send_buf_fast(l_ptr, buf, &dummy);
+			node_unlock(n_ptr);
+			read_unlock_bh(&net_lock);
+			return res;
+		}
+		node_unlock(n_ptr);
+	}
+	read_unlock_bh(&net_lock);
+	res = msg_data_sz(buf_msg(buf));
+	tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
+	return res;
+}
+
+
+/* 
+ * link_send_sections_fast: Entry for messages where the 
+ * destination processor is known and the header is complete,
+ * except for total message length. 
+ * Returns user data length or errno.
+ */
+int link_send_sections_fast(struct port *sender, 
+			    struct iovec const *msg_sect,
+			    const u32 num_sect, 
+			    u32 destaddr)
+{
+	struct tipc_msg *hdr = &sender->publ.phdr;
+	struct link *l_ptr;
+	struct sk_buff *buf;
+	struct node *node;
+	int res;
+	u32 selector = msg_origport(hdr) & 1;
+
+	assert(destaddr != tipc_own_addr);
+
+again:
+	/*
+	 * Try building message using port's max_pkt hint.
+	 * (Must not hold any locks while building message.)
+	 */
+
+	res = msg_build(hdr, msg_sect, num_sect, sender->max_pkt,
+			!sender->user_port, &buf);
+
+	read_lock_bh(&net_lock);
+	node = node_select(destaddr, selector);
+	if (likely(node)) {
+		node_lock(node);
+		l_ptr = node->active_links[selector];
+		if (likely(l_ptr)) {
+			if (likely(buf)) {
+				res = link_send_buf_fast(l_ptr, buf,
+							 &sender->max_pkt);
+				if (unlikely(res < 0))
+					buf_discard(buf);
+exit:
+				node_unlock(node);
+				read_unlock_bh(&net_lock);
+				return res;
+			}
+
+			/* Exit if build request was invalid */
+
+			if (unlikely(res < 0))
+				goto exit;
+
+			/* Exit if link (or bearer) is congested */
+
+			if (link_congested(l_ptr) || 
+			    !list_empty(&l_ptr->b_ptr->cong_links)) {
+				res = link_schedule_port(l_ptr,
+							 sender->publ.ref, res);
+				goto exit;
+			}
+
+			/* 
+			 * Message size exceeds max_pkt hint; update hint,
+			 * then re-try fast path or fragment the message
+			 */
+
+			sender->max_pkt = link_max_pkt(l_ptr);
+			node_unlock(node);
+			read_unlock_bh(&net_lock);
+
+
+			if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
+				goto again;
+
+			return link_send_sections_long(sender, msg_sect,
+						       num_sect, destaddr);
+		}
+		node_unlock(node);
+	}
+	read_unlock_bh(&net_lock);
+
+	/* Couldn't find a link to the destination node */
+
+	if (buf)
+		return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
+	if (res >= 0)
+		return port_reject_sections(sender, hdr, msg_sect, num_sect,
+					    TIPC_ERR_NO_NODE);
+	return res;
+}
+
+/* 
+ * link_send_sections_long(): Entry for long messages where the 
+ * destination node is known and the header is complete,
+ * inclusive total message length. 
+ * Link and bearer congestion status have been checked to be ok,
+ * and are ignored if they change.
+ *
+ * Note that fragments do not use the full link MTU so that they won't have
+ * to undergo refragmentation if link changeover causes them to be sent
+ * over another link with an additional tunnel header added as prefix.
+ * (Refragmentation will still occur if the other link has a smaller MTU.)
+ *
+ * Returns user data length or errno.
+ */
+static int link_send_sections_long(struct port *sender,
+				   struct iovec const *msg_sect,
+				   u32 num_sect,
+				   u32 destaddr)
+{
+	struct link *l_ptr;
+	struct node *node;
+	struct tipc_msg *hdr = &sender->publ.phdr;
+	u32 dsz = msg_data_sz(hdr);
+	u32 max_pkt,fragm_sz,rest;
+	struct tipc_msg fragm_hdr;
+	struct sk_buff *buf,*buf_chain,*prev;
+	u32 fragm_crs,fragm_rest,hsz,sect_rest;
+	const unchar *sect_crs;
+	int curr_sect;
+	u32 fragm_no;
+
+again:
+	fragm_no = 1;
+	max_pkt = sender->max_pkt - INT_H_SIZE;  
+		/* leave room for tunnel header in case of link changeover */
+	fragm_sz = max_pkt - INT_H_SIZE; 
+		/* leave room for fragmentation header in each fragment */
+	rest = dsz;
+	fragm_crs = 0;
+	fragm_rest = 0;
+	sect_rest = 0;
+	sect_crs = 0;
+	curr_sect = -1;
+
+	/* Prepare reusable fragment header: */
+
+	msg_dbg(hdr, ">FRAGMENTING>");
+	msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+		 TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
+	msg_set_link_selector(&fragm_hdr, sender->publ.ref);
+	msg_set_size(&fragm_hdr, max_pkt);
+	msg_set_fragm_no(&fragm_hdr, 1);
+
+	/* Prepare header of first fragment: */
+
+	buf_chain = buf = buf_acquire(max_pkt);
+	if (!buf)
+		return -ENOMEM;
+	buf->next = NULL;
+	memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+	hsz = msg_hdr_sz(hdr);
+	memcpy(buf->data + INT_H_SIZE, (unchar *)hdr, hsz);
+	msg_dbg(buf_msg(buf), ">BUILD>");
+
+	/* Chop up message: */
+
+	fragm_crs = INT_H_SIZE + hsz;
+	fragm_rest = fragm_sz - hsz;
+
+	do {		/* For all sections */
+		u32 sz;
+
+		if (!sect_rest) {
+			sect_rest = msg_sect[++curr_sect].iov_len;
+			sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
+		}
+
+		if (sect_rest < fragm_rest)
+			sz = sect_rest;
+		else
+			sz = fragm_rest;
+
+		if (likely(!sender->user_port)) {
+			if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) {
+error:
+				for (; buf_chain; buf_chain = buf) {
+					buf = buf_chain->next;
+					buf_discard(buf_chain);
+				}
+				return -EFAULT;
+			}
+		} else
+			memcpy(buf->data + fragm_crs, sect_crs, sz);
+
+		sect_crs += sz;
+		sect_rest -= sz;
+		fragm_crs += sz;
+		fragm_rest -= sz;
+		rest -= sz;
+
+		if (!fragm_rest && rest) {
+
+			/* Initiate new fragment: */
+			if (rest <= fragm_sz) {
+				fragm_sz = rest;
+				msg_set_type(&fragm_hdr,LAST_FRAGMENT);
+			} else {
+				msg_set_type(&fragm_hdr, FRAGMENT);
+			}
+			msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
+			msg_set_fragm_no(&fragm_hdr, ++fragm_no);
+			prev = buf;
+			buf = buf_acquire(fragm_sz + INT_H_SIZE);
+			if (!buf)
+				goto error;
+
+			buf->next = NULL;                                
+			prev->next = buf;
+			memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+			fragm_crs = INT_H_SIZE;
+			fragm_rest = fragm_sz;
+			msg_dbg(buf_msg(buf),"  >BUILD>");
+		}
+	}
+	while (rest > 0);
+
+	/* 
+	 * Now we have a buffer chain. Select a link and check
+	 * that packet size is still OK
+	 */
+	node = node_select(destaddr, sender->publ.ref & 1);
+	if (likely(node)) {
+		node_lock(node);
+		l_ptr = node->active_links[sender->publ.ref & 1];
+		if (!l_ptr) {
+			node_unlock(node);
+			goto reject;
+		}
+		if (link_max_pkt(l_ptr) < max_pkt) {
+			sender->max_pkt = link_max_pkt(l_ptr);
+			node_unlock(node);
+			for (; buf_chain; buf_chain = buf) {
+				buf = buf_chain->next;
+				buf_discard(buf_chain);
+			}
+			goto again;
+		}
+	} else {
+reject:
+		for (; buf_chain; buf_chain = buf) {
+			buf = buf_chain->next;
+			buf_discard(buf_chain);
+		}
+		return port_reject_sections(sender, hdr, msg_sect, num_sect,
+					    TIPC_ERR_NO_NODE);
+	}
+
+	/* Append whole chain to send queue: */
+
+	buf = buf_chain;
+	l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1);
+	if (!l_ptr->next_out)
+		l_ptr->next_out = buf_chain;
+	l_ptr->stats.sent_fragmented++;
+	while (buf) {
+		struct sk_buff *next = buf->next;
+		struct tipc_msg *msg = buf_msg(buf);
+
+		l_ptr->stats.sent_fragments++;
+		msg_set_long_msgno(msg, l_ptr->long_msg_seq_no);
+		link_add_to_outqueue(l_ptr, buf, msg);
+		msg_dbg(msg, ">ADD>");
+		buf = next;
+	}
+
+	/* Send it, if possible: */
+
+	link_push_queue(l_ptr);
+	node_unlock(node);
+	return dsz;
+}
+
+/* 
+ * link_push_packet: Push one unsent packet to the media
+ */
+u32 link_push_packet(struct link *l_ptr)
+{
+	struct sk_buff *buf = l_ptr->first_out;
+	u32 r_q_size = l_ptr->retransm_queue_size;
+	u32 r_q_head = l_ptr->retransm_queue_head;
+
+	/* Step to position where retransmission failed, if any,    */
+	/* consider that buffers may have been released in meantime */
+
+	if (r_q_size && buf) {
+		u32 last = lesser(mod(r_q_head + r_q_size), 
+				  link_last_sent(l_ptr));
+		u32 first = msg_seqno(buf_msg(buf));
+
+		while (buf && less(first, r_q_head)) {
+			first = mod(first + 1);
+			buf = buf->next;
+		}
+		l_ptr->retransm_queue_head = r_q_head = first;
+		l_ptr->retransm_queue_size = r_q_size = mod(last - first);
+	}
+
+	/* Continue retransmission now, if there is anything: */
+
+	if (r_q_size && buf && !skb_cloned(buf)) {
+		msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
+		msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); 
+		if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+			msg_dbg(buf_msg(buf), ">DEF-RETR>");
+			l_ptr->retransm_queue_head = mod(++r_q_head);
+			l_ptr->retransm_queue_size = --r_q_size;
+			l_ptr->stats.retransmitted++;
+			return TIPC_OK;
+		} else {
+			l_ptr->stats.bearer_congs++;
+			msg_dbg(buf_msg(buf), "|>DEF-RETR>");
+			return PUSH_FAILED;
+		}
+	}
+
+	/* Send deferred protocol message, if any: */
+
+	buf = l_ptr->proto_msg_queue;
+	if (buf) {
+		msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
+		msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in); 
+		if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+			msg_dbg(buf_msg(buf), ">DEF-PROT>");
+			l_ptr->unacked_window = 0;
+			buf_discard(buf);
+			l_ptr->proto_msg_queue = 0;
+			return TIPC_OK;
+		} else {
+			msg_dbg(buf_msg(buf), "|>DEF-PROT>");
+			l_ptr->stats.bearer_congs++;
+			return PUSH_FAILED;
+		}
+	}
+
+	/* Send one deferred data message, if send window not full: */
+
+	buf = l_ptr->next_out;
+	if (buf) {
+		struct tipc_msg *msg = buf_msg(buf);
+		u32 next = msg_seqno(msg);
+		u32 first = msg_seqno(buf_msg(l_ptr->first_out));
+
+		if (mod(next - first) < l_ptr->queue_limit[0]) {
+			msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+			msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+			if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+				if (msg_user(msg) == MSG_BUNDLER)
+					msg_set_type(msg, CLOSED_MSG);
+				msg_dbg(msg, ">PUSH-DATA>");
+				l_ptr->next_out = buf->next;
+				return TIPC_OK;
+			} else {
+				msg_dbg(msg, "|PUSH-DATA|");
+				l_ptr->stats.bearer_congs++;
+				return PUSH_FAILED;
+			}
+		}
+	}
+	return PUSH_FINISHED;
+}
+
+/*
+ * push_queue(): push out the unsent messages of a link where
+ *               congestion has abated. Node is locked
+ */
+void link_push_queue(struct link *l_ptr)
+{
+	u32 res;
+
+	if (bearer_congested(l_ptr->b_ptr, l_ptr))
+		return;
+
+	do {
+		res = link_push_packet(l_ptr);
+	}
+	while (res == TIPC_OK);
+	if (res == PUSH_FAILED)
+		bearer_schedule(l_ptr->b_ptr, l_ptr);
+}
+
+void link_retransmit(struct link *l_ptr, struct sk_buff *buf, 
+		     u32 retransmits)
+{
+	struct tipc_msg *msg;
+
+	dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
+
+	if (bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) {
+		msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>");
+		dbg_print_link(l_ptr, "   ");
+		l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
+		l_ptr->retransm_queue_size = retransmits;
+		return;
+	}
+	while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
+		msg = buf_msg(buf);
+		msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+		msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+		if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+                        /* Catch if retransmissions fail repeatedly: */
+                        if (l_ptr->last_retransmitted == msg_seqno(msg)) {
+                                if (++l_ptr->stale_count > 100) {
+                                        msg_print(CONS, buf_msg(buf), ">RETR>");
+                                        info("...Retransmitted %u times\n",
+					     l_ptr->stale_count);
+                                        link_print(l_ptr, CONS, "Resetting Link\n");;
+                                        link_reset(l_ptr);
+                                        break;
+                                }
+                        } else {
+                                l_ptr->stale_count = 0;
+                        }
+                        l_ptr->last_retransmitted = msg_seqno(msg);
+
+			msg_dbg(buf_msg(buf), ">RETR>");
+			buf = buf->next;
+			retransmits--;
+			l_ptr->stats.retransmitted++;
+		} else {
+			bearer_schedule(l_ptr->b_ptr, l_ptr);
+			l_ptr->stats.bearer_congs++;
+			l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
+			l_ptr->retransm_queue_size = retransmits;
+			return;
+		}
+	}
+	l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
+}
+
+/* 
+ * link_recv_non_seq: Receive packets which are outside
+ *                    the link sequence flow
+ */
+
+static void link_recv_non_seq(struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+
+	if (msg_user(msg) ==  LINK_CONFIG)
+		disc_recv_msg(buf);
+	else
+		bclink_recv_pkt(buf);
+}
+
+/** 
+ * link_insert_deferred_queue - insert deferred messages back into receive chain
+ */
+
+static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, 
+						  struct sk_buff *buf)
+{
+	u32 seq_no;
+
+	if (l_ptr->oldest_deferred_in == NULL)
+		return buf;
+
+	seq_no = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+	if (seq_no == mod(l_ptr->next_in_no)) {
+		l_ptr->newest_deferred_in->next = buf;
+		buf = l_ptr->oldest_deferred_in;
+		l_ptr->oldest_deferred_in = NULL;
+		l_ptr->deferred_inqueue_sz = 0;
+	}
+	return buf;
+}
+
+void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
+{
+	read_lock_bh(&net_lock);
+	while (head) {
+		struct bearer *b_ptr;
+		struct node *n_ptr;
+		struct link *l_ptr;
+		struct sk_buff *crs;
+		struct sk_buff *buf = head;
+		struct tipc_msg *msg = buf_msg(buf);
+		u32 seq_no = msg_seqno(msg);
+		u32 ackd = msg_ack(msg);
+		u32 released = 0;
+		int type;
+
+		b_ptr = (struct bearer *)tb_ptr;
+		TIPC_SKB_CB(buf)->handle = b_ptr;
+
+		head = head->next;
+		if (unlikely(msg_version(msg) != TIPC_VERSION))
+			goto cont;
+#if 0
+		if (msg_user(msg) != LINK_PROTOCOL)
+#endif
+			msg_dbg(msg,"<REC<");
+
+		if (unlikely(msg_non_seq(msg))) {
+			link_recv_non_seq(buf);
+			continue;
+		}
+		n_ptr = node_find(msg_prevnode(msg));
+		if (unlikely(!n_ptr))
+			goto cont;
+
+		node_lock(n_ptr);
+		l_ptr = n_ptr->links[b_ptr->identity];
+		if (unlikely(!l_ptr)) {
+			node_unlock(n_ptr);
+			goto cont;
+		}
+		/* 
+		 * Release acked messages 
+		 */
+		if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
+			if (node_is_up(n_ptr) && n_ptr->bclink.supported)
+				bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
+		}
+
+		crs = l_ptr->first_out;
+		while ((crs != l_ptr->next_out) && 
+		       less_eq(msg_seqno(buf_msg(crs)), ackd)) {
+			struct sk_buff *next = crs->next;
+
+			buf_discard(crs);
+			crs = next;
+			released++;
+		}
+		if (released) {
+			l_ptr->first_out = crs;
+			l_ptr->out_queue_size -= released;
+		}
+		if (unlikely(l_ptr->next_out))
+			link_push_queue(l_ptr);
+		if (unlikely(!list_empty(&l_ptr->waiting_ports)))
+			link_wakeup_ports(l_ptr, 0);
+		if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
+			l_ptr->stats.sent_acks++;
+			link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+		}
+
+protocol_check:
+		if (likely(link_working_working(l_ptr))) {
+			if (likely(seq_no == mod(l_ptr->next_in_no))) {
+				l_ptr->next_in_no++;
+				if (unlikely(l_ptr->oldest_deferred_in))
+					head = link_insert_deferred_queue(l_ptr,
+									  head);
+				if (likely(msg_is_dest(msg, tipc_own_addr))) {
+deliver:
+					if (likely(msg_isdata(msg))) {
+						node_unlock(n_ptr);
+						port_recv_msg(buf);
+						continue;
+					}
+					switch (msg_user(msg)) {
+					case MSG_BUNDLER:
+						l_ptr->stats.recv_bundles++;
+						l_ptr->stats.recv_bundled += 
+							msg_msgcnt(msg);
+						node_unlock(n_ptr);
+						link_recv_bundle(buf);
+						continue;
+					case ROUTE_DISTRIBUTOR:
+						node_unlock(n_ptr);
+						cluster_recv_routing_table(buf);
+						continue;
+					case NAME_DISTRIBUTOR:
+						node_unlock(n_ptr);
+						named_recv(buf);
+						continue;
+					case CONN_MANAGER:
+						node_unlock(n_ptr);
+						port_recv_proto_msg(buf);
+						continue;
+					case MSG_FRAGMENTER:
+						l_ptr->stats.recv_fragments++;
+						if (link_recv_fragment(
+							&l_ptr->defragm_buf, 
+							&buf, &msg)) {
+							l_ptr->stats.recv_fragmented++;
+							goto deliver;
+						}
+						break;
+					case CHANGEOVER_PROTOCOL:
+						type = msg_type(msg);
+						if (link_recv_changeover_msg(
+							&l_ptr, &buf)) {
+							msg = buf_msg(buf);
+							seq_no = msg_seqno(msg);
+							TIPC_SKB_CB(buf)->handle 
+								= b_ptr;
+							if (type == ORIGINAL_MSG)
+								goto deliver;
+							goto protocol_check;
+						}
+						break;
+					}
+				}
+				node_unlock(n_ptr);
+				net_route_msg(buf);
+				continue;
+			}
+			link_handle_out_of_seq_msg(l_ptr, buf);
+			head = link_insert_deferred_queue(l_ptr, head);
+			node_unlock(n_ptr);
+			continue;
+		}
+
+		if (msg_user(msg) == LINK_PROTOCOL) {
+			link_recv_proto_msg(l_ptr, buf);
+			head = link_insert_deferred_queue(l_ptr, head);
+			node_unlock(n_ptr);
+			continue;
+		}
+		msg_dbg(msg,"NSEQ<REC<");
+		link_state_event(l_ptr, TRAFFIC_MSG_EVT);
+
+		if (link_working_working(l_ptr)) {
+			/* Re-insert in front of queue */
+			msg_dbg(msg,"RECV-REINS:");
+			buf->next = head;
+			head = buf;
+			node_unlock(n_ptr);
+			continue;
+		}
+		node_unlock(n_ptr);
+cont:
+		buf_discard(buf);
+	}
+	read_unlock_bh(&net_lock);
+}
+
+/* 
+ * link_defer_buf(): Sort a received out-of-sequence packet 
+ *                   into the deferred reception queue.
+ * Returns the increase of the queue length,i.e. 0 or 1
+ */
+
+u32 link_defer_pkt(struct sk_buff **head,
+		   struct sk_buff **tail,
+		   struct sk_buff *buf)
+{
+	struct sk_buff *prev = 0;
+	struct sk_buff *crs = *head;
+	u32 seq_no = msg_seqno(buf_msg(buf));
+
+	buf->next = NULL;
+
+	/* Empty queue ? */
+	if (*head == NULL) {
+		*head = *tail = buf;
+		return 1;
+	}
+
+	/* Last ? */
+	if (less(msg_seqno(buf_msg(*tail)), seq_no)) {
+		(*tail)->next = buf;
+		*tail = buf;
+		return 1;
+	}
+
+	/* Scan through queue and sort it in */
+	do {
+		struct tipc_msg *msg = buf_msg(crs);
+
+		if (less(seq_no, msg_seqno(msg))) {
+			buf->next = crs;
+			if (prev)
+				prev->next = buf;
+			else
+				*head = buf;   
+			return 1;
+		}
+		if (seq_no == msg_seqno(msg)) {
+			break;
+		}
+		prev = crs;
+		crs = crs->next;
+	}
+	while (crs);
+
+	/* Message is a duplicate of an existing message */
+
+	buf_discard(buf);
+	return 0;
+}
+
+/** 
+ * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
+ */
+
+static void link_handle_out_of_seq_msg(struct link *l_ptr, 
+				       struct sk_buff *buf)
+{
+	u32 seq_no = msg_seqno(buf_msg(buf));
+
+	if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
+		link_recv_proto_msg(l_ptr, buf);
+		return;
+	}
+
+	dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n", 
+	    seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no);
+
+	/* Record OOS packet arrival (force mismatch on next timeout) */
+
+	l_ptr->checkpoint--;
+
+	/* 
+	 * Discard packet if a duplicate; otherwise add it to deferred queue
+	 * and notify peer of gap as per protocol specification
+	 */
+
+	if (less(seq_no, mod(l_ptr->next_in_no))) {
+		l_ptr->stats.duplicates++;
+		buf_discard(buf);
+		return;
+	}
+
+	if (link_defer_pkt(&l_ptr->oldest_deferred_in,
+			   &l_ptr->newest_deferred_in, buf)) {
+		l_ptr->deferred_inqueue_sz++;
+		l_ptr->stats.deferred_recv++;
+		if ((l_ptr->deferred_inqueue_sz % 16) == 1)
+			link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+	} else
+		l_ptr->stats.duplicates++;
+}
+
+/*
+ * Send protocol message to the other endpoint.
+ */
+void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
+			 u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
+{
+	struct sk_buff *buf = 0;
+	struct tipc_msg *msg = l_ptr->pmsg;
+        u32 msg_size = sizeof(l_ptr->proto_msg);
+
+	if (link_blocked(l_ptr))
+		return;
+	msg_set_type(msg, msg_typ);
+	msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
+	msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); 
+	msg_set_last_bcast(msg, bclink_get_last_sent());
+
+	if (msg_typ == STATE_MSG) {
+		u32 next_sent = mod(l_ptr->next_out_no);
+
+		if (!link_is_up(l_ptr))
+			return;
+		if (l_ptr->next_out)
+			next_sent = msg_seqno(buf_msg(l_ptr->next_out));
+		msg_set_next_sent(msg, next_sent);
+		if (l_ptr->oldest_deferred_in) {
+			u32 rec = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+			gap = mod(rec - mod(l_ptr->next_in_no));
+		}
+		msg_set_seq_gap(msg, gap);
+		if (gap)
+			l_ptr->stats.sent_nacks++;
+		msg_set_link_tolerance(msg, tolerance);
+		msg_set_linkprio(msg, priority);
+		msg_set_max_pkt(msg, ack_mtu);
+		msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+		msg_set_probe(msg, probe_msg != 0);
+		if (probe_msg) { 
+			u32 mtu = l_ptr->max_pkt;
+
+                        if ((mtu < l_ptr->max_pkt_target) &&
+			    link_working_working(l_ptr) &&
+			    l_ptr->fsm_msg_cnt) {
+				msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
+                                if (l_ptr->max_pkt_probes == 10) {
+                                        l_ptr->max_pkt_target = (msg_size - 4);
+                                        l_ptr->max_pkt_probes = 0;
+					msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
+                                }
+				l_ptr->max_pkt_probes++;
+                        }
+
+			l_ptr->stats.sent_probes++;
+                }
+		l_ptr->stats.sent_states++;
+	} else {		/* RESET_MSG or ACTIVATE_MSG */
+		msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
+		msg_set_seq_gap(msg, 0);
+		msg_set_next_sent(msg, 1);
+		msg_set_link_tolerance(msg, l_ptr->tolerance);
+		msg_set_linkprio(msg, l_ptr->priority);
+		msg_set_max_pkt(msg, l_ptr->max_pkt_target);
+	}
+
+	if (node_has_redundant_links(l_ptr->owner)) {
+		msg_set_redundant_link(msg);
+	} else {
+		msg_clear_redundant_link(msg);
+	}
+	msg_set_linkprio(msg, l_ptr->priority);
+
+	/* Ensure sequence number will not fit : */
+
+	msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
+
+	/* Congestion? */
+
+	if (bearer_congested(l_ptr->b_ptr, l_ptr)) {
+		if (!l_ptr->proto_msg_queue) {
+			l_ptr->proto_msg_queue =
+				buf_acquire(sizeof(l_ptr->proto_msg));
+		}
+		buf = l_ptr->proto_msg_queue;
+		if (!buf)
+			return;
+		memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+		return;
+	}
+	msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
+
+	/* Message can be sent */
+
+	msg_dbg(msg, ">>");
+
+	buf = buf_acquire(msg_size);
+	if (!buf)
+		return;
+
+	memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+        msg_set_size(buf_msg(buf), msg_size);
+
+	if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+		l_ptr->unacked_window = 0;
+		buf_discard(buf);
+		return;
+	}
+
+	/* New congestion */
+	bearer_schedule(l_ptr->b_ptr, l_ptr);
+	l_ptr->proto_msg_queue = buf;
+	l_ptr->stats.bearer_congs++;
+}
+
+/*
+ * Receive protocol message :
+ * Note that network plane id propagates through the network, and may 
+ * change at any time. The node with lowest address rules    
+ */
+
+static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
+{
+	u32 rec_gap = 0;
+	u32 max_pkt_info;
+        u32 max_pkt_ack;
+	u32 msg_tol;
+	struct tipc_msg *msg = buf_msg(buf);
+
+	dbg("AT(%u):", jiffies_to_msecs(jiffies));
+	msg_dbg(msg, "<<");
+	if (link_blocked(l_ptr))
+		goto exit;
+
+	/* record unnumbered packet arrival (force mismatch on next timeout) */
+
+	l_ptr->checkpoint--;
+
+	if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
+		if (tipc_own_addr > msg_prevnode(msg))
+			l_ptr->b_ptr->net_plane = msg_net_plane(msg);
+
+	l_ptr->owner->permit_changeover = msg_redundant_link(msg);
+
+	switch (msg_type(msg)) {
+	
+	case RESET_MSG:
+		if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
+			if (msg_session(msg) == l_ptr->peer_session) {
+				dbg("Duplicate RESET: %u<->%u\n",
+				    msg_session(msg), l_ptr->peer_session);                                     
+				break; /* duplicate: ignore */
+			}
+		}
+		/* fall thru' */
+	case ACTIVATE_MSG:
+		/* Update link settings according other endpoint's values */
+
+		strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
+
+		if ((msg_tol = msg_link_tolerance(msg)) &&
+		    (msg_tol > l_ptr->tolerance))
+			link_set_supervision_props(l_ptr, msg_tol);
+
+		if (msg_linkprio(msg) > l_ptr->priority)
+			l_ptr->priority = msg_linkprio(msg);
+
+		max_pkt_info = msg_max_pkt(msg);
+                if (max_pkt_info) {
+			if (max_pkt_info < l_ptr->max_pkt_target)
+				l_ptr->max_pkt_target = max_pkt_info;
+			if (l_ptr->max_pkt > l_ptr->max_pkt_target)
+				l_ptr->max_pkt = l_ptr->max_pkt_target;
+		} else {
+                        l_ptr->max_pkt = l_ptr->max_pkt_target;
+		}
+		l_ptr->owner->bclink.supported = (max_pkt_info != 0);
+
+		link_state_event(l_ptr, msg_type(msg));
+
+		l_ptr->peer_session = msg_session(msg);
+		l_ptr->peer_bearer_id = msg_bearer_id(msg);
+
+		/* Synchronize broadcast sequence numbers */
+		if (!node_has_redundant_links(l_ptr->owner)) {
+			l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg));
+		}
+		break;
+	case STATE_MSG:
+
+		if ((msg_tol = msg_link_tolerance(msg)))
+			link_set_supervision_props(l_ptr, msg_tol);
+		
+		if (msg_linkprio(msg) && 
+		    (msg_linkprio(msg) != l_ptr->priority)) {
+			warn("Changing prio <%s>: %u->%u\n",
+			     l_ptr->name, l_ptr->priority, msg_linkprio(msg));
+			l_ptr->priority = msg_linkprio(msg);
+			link_reset(l_ptr); /* Enforce change to take effect */
+			break;
+		}
+		link_state_event(l_ptr, TRAFFIC_MSG_EVT);
+		l_ptr->stats.recv_states++;
+		if (link_reset_unknown(l_ptr))
+			break;
+
+		if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
+			rec_gap = mod(msg_next_sent(msg) - 
+				      mod(l_ptr->next_in_no));
+		}
+
+		max_pkt_ack = msg_max_pkt(msg);
+                if (max_pkt_ack > l_ptr->max_pkt) {
+                        dbg("Link <%s> updated MTU %u -> %u\n",
+                            l_ptr->name, l_ptr->max_pkt, max_pkt_ack);
+                        l_ptr->max_pkt = max_pkt_ack;
+                        l_ptr->max_pkt_probes = 0;
+                }
+
+		max_pkt_ack = 0;
+                if (msg_probe(msg)) {
+			l_ptr->stats.recv_probes++;
+                        if (msg_size(msg) > sizeof(l_ptr->proto_msg)) {
+                                max_pkt_ack = msg_size(msg);
+                        }
+                }
+
+		/* Protocol message before retransmits, reduce loss risk */
+
+		bclink_check_gap(l_ptr->owner, msg_last_bcast(msg));
+
+		if (rec_gap || (msg_probe(msg))) {
+			link_send_proto_msg(l_ptr, STATE_MSG,
+					    0, rec_gap, 0, 0, max_pkt_ack);
+		}
+		if (msg_seq_gap(msg)) {
+			msg_dbg(msg, "With Gap:");
+			l_ptr->stats.recv_nacks++;
+			link_retransmit(l_ptr, l_ptr->first_out,
+					msg_seq_gap(msg));
+		}
+		break;
+	default:
+		msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<");
+	}
+exit:
+	buf_discard(buf);
+}
+
+
+/*
+ * link_tunnel(): Send one message via a link belonging to 
+ * another bearer. Owner node is locked.
+ */
+void link_tunnel(struct link *l_ptr, 
+	    struct tipc_msg *tunnel_hdr, 
+	    struct tipc_msg  *msg,
+	    u32 selector)
+{
+	struct link *tunnel;
+	struct sk_buff *buf;
+	u32 length = msg_size(msg);
+
+	tunnel = l_ptr->owner->active_links[selector & 1];
+	if (!link_is_up(tunnel))
+		return;
+	msg_set_size(tunnel_hdr, length + INT_H_SIZE);
+	buf = buf_acquire(length + INT_H_SIZE);
+	if (!buf)
+		return;
+	memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
+	memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
+	dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
+	msg_dbg(buf_msg(buf), ">SEND>");
+	assert(tunnel);
+	link_send_buf(tunnel, buf);
+}
+
+
+
+/*
+ * changeover(): Send whole message queue via the remaining link
+ *               Owner node is locked.
+ */
+
+void link_changeover(struct link *l_ptr)
+{
+	u32 msgcount = l_ptr->out_queue_size;
+	struct sk_buff *crs = l_ptr->first_out;
+	struct link *tunnel = l_ptr->owner->active_links[0];
+	int split_bundles = node_has_redundant_links(l_ptr->owner);
+	struct tipc_msg tunnel_hdr;
+
+	if (!tunnel)
+		return;
+
+	if (!l_ptr->owner->permit_changeover)
+		return;
+
+	msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+		 ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+	msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
+	msg_set_msgcnt(&tunnel_hdr, msgcount);
+	if (!l_ptr->first_out) {
+		struct sk_buff *buf;
+
+		assert(!msgcount);
+		buf = buf_acquire(INT_H_SIZE);
+		if (buf) {
+			memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
+			msg_set_size(&tunnel_hdr, INT_H_SIZE);
+			dbg("%c->%c:", l_ptr->b_ptr->net_plane,
+			    tunnel->b_ptr->net_plane);
+			msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
+			link_send_buf(tunnel, buf);
+		} else {
+			warn("Memory squeeze; link changeover failed\n");
+		}
+		return;
+	}
+	while (crs) {
+		struct tipc_msg *msg = buf_msg(crs);
+
+		if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
+			u32 msgcount = msg_msgcnt(msg);
+			struct tipc_msg *m = msg_get_wrapped(msg);
+			unchar* pos = (unchar*)m;
+
+			while (msgcount--) {
+				msg_set_seqno(m,msg_seqno(msg));
+				link_tunnel(l_ptr, &tunnel_hdr, m,
+					    msg_link_selector(m));
+				pos += align(msg_size(m));
+				m = (struct tipc_msg *)pos;
+			}
+		} else {
+			link_tunnel(l_ptr, &tunnel_hdr, msg,
+				    msg_link_selector(msg));
+		}
+		crs = crs->next;
+	}
+}
+
+void link_send_duplicate(struct link *l_ptr, struct link *tunnel)
+{
+	struct sk_buff *iter;
+	struct tipc_msg tunnel_hdr;
+
+	msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+		 DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+	msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
+	msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
+	iter = l_ptr->first_out;
+	while (iter) {
+		struct sk_buff *outbuf;
+		struct tipc_msg *msg = buf_msg(iter);
+		u32 length = msg_size(msg);
+
+		if (msg_user(msg) == MSG_BUNDLER)
+			msg_set_type(msg, CLOSED_MSG);
+		msg_set_ack(msg, mod(l_ptr->next_in_no - 1));	/* Update */
+		msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+		msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
+		outbuf = buf_acquire(length + INT_H_SIZE);
+		if (outbuf == NULL) {
+			warn("Memory squeeze; buffer duplication failed\n");
+			return;
+		}
+		memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
+		memcpy(outbuf->data + INT_H_SIZE, iter->data, length);
+		dbg("%c->%c:", l_ptr->b_ptr->net_plane,
+		    tunnel->b_ptr->net_plane);
+		msg_dbg(buf_msg(outbuf), ">SEND>");
+		link_send_buf(tunnel, outbuf);
+		if (!link_is_up(l_ptr))
+			return;
+		iter = iter->next;
+	}
+}
+
+
+
+/**
+ * buf_extract - extracts embedded TIPC message from another message
+ * @skb: encapsulating message buffer
+ * @from_pos: offset to extract from
+ *
+ * Returns a new message buffer containing an embedded message.  The 
+ * encapsulating message itself is left unchanged.
+ */
+
+static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
+{
+	struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
+	u32 size = msg_size(msg);
+	struct sk_buff *eb;
+
+	eb = buf_acquire(size);
+	if (eb)
+		memcpy(eb->data, (unchar *)msg, size);
+	return eb;
+}
+
+/* 
+ *  link_recv_changeover_msg(): Receive tunneled packet sent
+ *  via other link. Node is locked. Return extracted buffer.
+ */
+
+static int link_recv_changeover_msg(struct link **l_ptr,
+				    struct sk_buff **buf)
+{
+	struct sk_buff *tunnel_buf = *buf;
+	struct link *dest_link;
+	struct tipc_msg *msg;
+	struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
+	u32 msg_typ = msg_type(tunnel_msg);
+	u32 msg_count = msg_msgcnt(tunnel_msg);
+
+	dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
+	assert(dest_link != *l_ptr);
+	if (!dest_link) {
+		msg_dbg(tunnel_msg, "NOLINK/<REC<");
+		goto exit;
+	}
+	dbg("%c<-%c:", dest_link->b_ptr->net_plane,
+	    (*l_ptr)->b_ptr->net_plane);
+	*l_ptr = dest_link;
+	msg = msg_get_wrapped(tunnel_msg);
+
+	if (msg_typ == DUPLICATE_MSG) {
+		if (less(msg_seqno(msg), mod(dest_link->next_in_no))) {
+			msg_dbg(tunnel_msg, "DROP/<REC<");
+			goto exit;
+		}
+		*buf = buf_extract(tunnel_buf,INT_H_SIZE);
+		if (*buf == NULL) {
+			warn("Memory squeeze; failed to extract msg\n");
+			goto exit;
+		}
+		msg_dbg(tunnel_msg, "TNL<REC<");
+		buf_discard(tunnel_buf);
+		return 1;
+	}
+
+	/* First original message ?: */
+
+	if (link_is_up(dest_link)) {
+		msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
+		link_reset(dest_link);
+		dest_link->exp_msg_count = msg_count;
+		if (!msg_count)
+			goto exit;
+	} else if (dest_link->exp_msg_count == START_CHANGEOVER) {
+		msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
+		dest_link->exp_msg_count = msg_count;
+		if (!msg_count)
+			goto exit;
+	}
+
+	/* Receive original message */
+
+	if (dest_link->exp_msg_count == 0) {
+		msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
+		dbg_print_link(dest_link, "LINK:");
+		goto exit;
+	}
+	dest_link->exp_msg_count--;
+	if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
+		msg_dbg(tunnel_msg, "DROP/DUPL/<REC<");
+		goto exit;
+	} else {
+		*buf = buf_extract(tunnel_buf, INT_H_SIZE);
+		if (*buf != NULL) {
+			msg_dbg(tunnel_msg, "TNL<REC<");
+			buf_discard(tunnel_buf);
+			return 1;
+		} else {
+			warn("Memory squeeze; dropped incoming msg\n");
+		}
+	}
+exit:
+	*buf = 0;
+	buf_discard(tunnel_buf);
+	return 0;
+}
+
+/*
+ *  Bundler functionality:
+ */
+void link_recv_bundle(struct sk_buff *buf)
+{
+	u32 msgcount = msg_msgcnt(buf_msg(buf));
+	u32 pos = INT_H_SIZE;
+	struct sk_buff *obuf;
+
+	msg_dbg(buf_msg(buf), "<BNDL<: ");
+	while (msgcount--) {
+		obuf = buf_extract(buf, pos);
+		if (obuf == NULL) {
+			char addr_string[16];
+
+			warn("Buffer allocation failure;\n");
+			warn("  incoming message(s) from %s lost\n",
+			     addr_string_fill(addr_string, 
+					      msg_orignode(buf_msg(buf))));
+			return;
+		};
+		pos += align(msg_size(buf_msg(obuf)));
+		msg_dbg(buf_msg(obuf), "     /");
+		net_route_msg(obuf);
+	}
+	buf_discard(buf);
+}
+
+/*
+ *  Fragmentation/defragmentation:
+ */
+
+
+/* 
+ * link_send_long_buf: Entry for buffers needing fragmentation.
+ * The buffer is complete, inclusive total message length. 
+ * Returns user data length.
+ */
+int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
+{
+	struct tipc_msg *inmsg = buf_msg(buf);
+	struct tipc_msg fragm_hdr;
+	u32 insize = msg_size(inmsg);
+	u32 dsz = msg_data_sz(inmsg);
+	unchar *crs = buf->data;
+	u32 rest = insize;
+	u32 pack_sz = link_max_pkt(l_ptr);
+	u32 fragm_sz = pack_sz - INT_H_SIZE;
+	u32 fragm_no = 1;
+	u32 destaddr = msg_destnode(inmsg);
+
+	if (msg_short(inmsg))
+		destaddr = l_ptr->addr;
+
+	if (msg_routed(inmsg))
+		msg_set_prevnode(inmsg, tipc_own_addr);
+
+	/* Prepare reusable fragment header: */
+
+	msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+		 TIPC_OK, INT_H_SIZE, destaddr);
+	msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
+	msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
+	msg_set_fragm_no(&fragm_hdr, fragm_no);
+	l_ptr->stats.sent_fragmented++;
+
+	/* Chop up message: */
+
+	while (rest > 0) {
+		struct sk_buff *fragm;
+
+		if (rest <= fragm_sz) {
+			fragm_sz = rest;
+			msg_set_type(&fragm_hdr, LAST_FRAGMENT);
+		}
+		fragm = buf_acquire(fragm_sz + INT_H_SIZE);
+		if (fragm == NULL) {
+			warn("Memory squeeze; failed to fragment msg\n");
+			dsz = -ENOMEM;
+			goto exit;
+		}
+		msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
+		memcpy(fragm->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+		memcpy(fragm->data + INT_H_SIZE, crs, fragm_sz);
+
+		/*  Send queued messages first, if any: */
+
+		l_ptr->stats.sent_fragments++;
+		link_send_buf(l_ptr, fragm);
+		if (!link_is_up(l_ptr))
+			return dsz;
+		msg_set_fragm_no(&fragm_hdr, ++fragm_no);
+		rest -= fragm_sz;
+		crs += fragm_sz;
+		msg_set_type(&fragm_hdr, FRAGMENT);
+	}
+exit:
+	buf_discard(buf);
+	return dsz;
+}
+
+/* 
+ * A pending message being re-assembled must store certain values 
+ * to handle subsequent fragments correctly. The following functions 
+ * help storing these values in unused, available fields in the
+ * pending message. This makes dynamic memory allocation unecessary.
+ */
+
+static inline u32 get_long_msg_seqno(struct sk_buff *buf)
+{
+	return msg_seqno(buf_msg(buf));
+}
+
+static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
+{
+	msg_set_seqno(buf_msg(buf), seqno);
+}
+
+static inline u32 get_fragm_size(struct sk_buff *buf)
+{
+	return msg_ack(buf_msg(buf));
+}
+
+static inline void set_fragm_size(struct sk_buff *buf, u32 sz)
+{
+	msg_set_ack(buf_msg(buf), sz);
+}
+
+static inline u32 get_expected_frags(struct sk_buff *buf)
+{
+	return msg_bcast_ack(buf_msg(buf));
+}
+
+static inline void set_expected_frags(struct sk_buff *buf, u32 exp)
+{
+	msg_set_bcast_ack(buf_msg(buf), exp);
+}
+
+static inline u32 get_timer_cnt(struct sk_buff *buf)
+{
+	return msg_reroute_cnt(buf_msg(buf));
+}
+
+static inline void incr_timer_cnt(struct sk_buff *buf)
+{
+	msg_incr_reroute_cnt(buf_msg(buf));
+}
+
+/* 
+ * link_recv_fragment(): Called with node lock on. Returns 
+ * the reassembled buffer if message is complete.
+ */
+int link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, 
+		       struct tipc_msg **m)
+{
+	struct sk_buff *prev = 0;
+	struct sk_buff *fbuf = *fb;
+	struct tipc_msg *fragm = buf_msg(fbuf);
+	struct sk_buff *pbuf = *pending;
+	u32 long_msg_seq_no = msg_long_msgno(fragm);
+
+	*fb = 0;
+	msg_dbg(fragm,"FRG<REC<");
+
+	/* Is there an incomplete message waiting for this fragment? */
+
+	while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no)
+			|| (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
+		prev = pbuf;
+		pbuf = pbuf->next;
+	}
+
+	if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
+		struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
+		u32 msg_sz = msg_size(imsg);
+		u32 fragm_sz = msg_data_sz(fragm);
+		u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz);
+		u32 max =  TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE;
+		if (msg_type(imsg) == TIPC_MCAST_MSG)
+			max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
+		if (msg_size(imsg) > max) {
+			msg_dbg(fragm,"<REC<Oversized: ");
+			buf_discard(fbuf);
+			return 0;
+		}
+		pbuf = buf_acquire(msg_size(imsg));
+		if (pbuf != NULL) {
+			pbuf->next = *pending;
+			*pending = pbuf;
+			memcpy(pbuf->data, (unchar *)imsg, msg_data_sz(fragm));
+
+			/*  Prepare buffer for subsequent fragments. */
+
+			set_long_msg_seqno(pbuf, long_msg_seq_no); 
+			set_fragm_size(pbuf,fragm_sz); 
+			set_expected_frags(pbuf,exp_fragm_cnt - 1); 
+		} else {
+			warn("Memory squeeze; got no defragmenting buffer\n");
+		}
+		buf_discard(fbuf);
+		return 0;
+	} else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
+		u32 dsz = msg_data_sz(fragm);
+		u32 fsz = get_fragm_size(pbuf);
+		u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
+		u32 exp_frags = get_expected_frags(pbuf) - 1;
+		memcpy(pbuf->data + crs, msg_data(fragm), dsz);
+		buf_discard(fbuf);
+
+		/* Is message complete? */
+
+		if (exp_frags == 0) {
+			if (prev)
+				prev->next = pbuf->next;
+			else
+				*pending = pbuf->next;
+			msg_reset_reroute_cnt(buf_msg(pbuf));
+			*fb = pbuf;
+			*m = buf_msg(pbuf);
+			return 1;
+		}
+		set_expected_frags(pbuf,exp_frags);     
+		return 0;
+	}
+	dbg(" Discarding orphan fragment %x\n",fbuf);
+	msg_dbg(fragm,"ORPHAN:");
+	dbg("Pending long buffers:\n");
+	dbg_print_buf_chain(*pending);
+	buf_discard(fbuf);
+	return 0;
+}
+
+/**
+ * link_check_defragm_bufs - flush stale incoming message fragments
+ * @l_ptr: pointer to link
+ */
+
+static void link_check_defragm_bufs(struct link *l_ptr)
+{
+	struct sk_buff *prev = 0;
+	struct sk_buff *next = 0;
+	struct sk_buff *buf = l_ptr->defragm_buf;
+
+	if (!buf)
+		return;
+	if (!link_working_working(l_ptr))
+		return;
+	while (buf) {
+		u32 cnt = get_timer_cnt(buf);
+
+		next = buf->next;
+		if (cnt < 4) {
+			incr_timer_cnt(buf);
+			prev = buf;
+		} else {
+			dbg(" Discarding incomplete long buffer\n");
+			msg_dbg(buf_msg(buf), "LONG:");
+			dbg_print_link(l_ptr, "curr:");
+			dbg("Pending long buffers:\n");
+			dbg_print_buf_chain(l_ptr->defragm_buf);
+			if (prev)
+				prev->next = buf->next;
+			else
+				l_ptr->defragm_buf = buf->next;
+			buf_discard(buf);
+		}
+		buf = next;
+	}
+}
+
+
+
+static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
+{
+	l_ptr->tolerance = tolerance;
+	l_ptr->continuity_interval =
+		((tolerance / 4) > 500) ? 500 : tolerance / 4;
+	l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
+}
+
+
+void link_set_queue_limits(struct link *l_ptr, u32 window)
+{
+	/* Data messages from this node, inclusive FIRST_FRAGM */
+	l_ptr->queue_limit[DATA_LOW] = window;
+	l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4;
+	l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5;
+	l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6;
+	/* Transiting data messages,inclusive FIRST_FRAGM */
+	l_ptr->queue_limit[DATA_LOW + 4] = 300;
+	l_ptr->queue_limit[DATA_MEDIUM + 4] = 600;
+	l_ptr->queue_limit[DATA_HIGH + 4] = 900;
+	l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200;
+	l_ptr->queue_limit[CONN_MANAGER] = 1200;
+	l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
+	l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
+	l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
+	/* FRAGMENT and LAST_FRAGMENT packets */
+	l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
+}
+
+/**
+ * link_find_link - locate link by name
+ * @name - ptr to link name string
+ * @node - ptr to area to be filled with ptr to associated node
+ * 
+ * Caller must hold 'net_lock' to ensure node and bearer are not deleted;
+ * this also prevents link deletion.
+ * 
+ * Returns pointer to link (or 0 if invalid link name).
+ */
+
+static struct link *link_find_link(const char *name, struct node **node)
+{
+	struct link_name link_name_parts;
+	struct bearer *b_ptr;
+	struct link *l_ptr; 
+
+	if (!link_name_validate(name, &link_name_parts))
+		return 0;
+
+	b_ptr = bearer_find_interface(link_name_parts.if_local);
+	if (!b_ptr)
+		return 0;
+
+	*node = node_find(link_name_parts.addr_peer); 
+	if (!*node)
+		return 0;
+
+	l_ptr = (*node)->links[b_ptr->identity];
+	if (!l_ptr || strcmp(l_ptr->name, name))
+		return 0;
+
+	return l_ptr;
+}
+
+struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space, 
+			        u16 cmd)
+{
+	struct tipc_link_config *args;
+        u32 new_value;
+	struct link *l_ptr;
+	struct node *node;
+        int res;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
+	new_value = ntohl(args->value);
+
+	if (!strcmp(args->name, bc_link_name)) {
+		if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
+		    (bclink_set_queue_limits(new_value) == 0))
+			return cfg_reply_none();
+	       	return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+					      " (cannot change setting on broadcast link)");
+	}
+
+	read_lock_bh(&net_lock);
+	l_ptr = link_find_link(args->name, &node); 
+	if (!l_ptr) {
+		read_unlock_bh(&net_lock);
+	       	return cfg_reply_error_string("link not found");
+	}
+
+	node_lock(node);
+	res = -EINVAL;
+	switch (cmd) {
+	case TIPC_CMD_SET_LINK_TOL: 
+		if ((new_value >= TIPC_MIN_LINK_TOL) && 
+		    (new_value <= TIPC_MAX_LINK_TOL)) {
+			link_set_supervision_props(l_ptr, new_value);
+			link_send_proto_msg(l_ptr, STATE_MSG, 
+					    0, 0, new_value, 0, 0);
+			res = TIPC_OK;
+		}
+		break;
+	case TIPC_CMD_SET_LINK_PRI: 
+		if (new_value < TIPC_NUM_LINK_PRI) {
+			l_ptr->priority = new_value;
+			link_send_proto_msg(l_ptr, STATE_MSG, 
+					    0, 0, 0, new_value, 0);
+			res = TIPC_OK;
+		}
+		break;
+	case TIPC_CMD_SET_LINK_WINDOW: 
+		if ((new_value >= TIPC_MIN_LINK_WIN) && 
+		    (new_value <= TIPC_MAX_LINK_WIN)) {
+			link_set_queue_limits(l_ptr, new_value);
+			res = TIPC_OK;
+		}
+		break;
+	}
+	node_unlock(node);
+
+	read_unlock_bh(&net_lock);
+	if (res)
+	       	return cfg_reply_error_string("cannot change link setting");
+
+	return cfg_reply_none();
+}
+
+/**
+ * link_reset_statistics - reset link statistics
+ * @l_ptr: pointer to link
+ */
+
+static void link_reset_statistics(struct link *l_ptr)
+{
+	memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
+	l_ptr->stats.sent_info = l_ptr->next_out_no;
+	l_ptr->stats.recv_info = l_ptr->next_in_no;
+}
+
+struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
+{
+	char *link_name;
+	struct link *l_ptr; 
+	struct node *node;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	link_name = (char *)TLV_DATA(req_tlv_area);
+	if (!strcmp(link_name, bc_link_name)) {
+		if (bclink_reset_stats())
+			return cfg_reply_error_string("link not found");
+		return cfg_reply_none();
+	}
+
+	read_lock_bh(&net_lock);
+	l_ptr = link_find_link(link_name, &node); 
+	if (!l_ptr) {
+		read_unlock_bh(&net_lock);
+		return cfg_reply_error_string("link not found");
+	}
+
+	node_lock(node);
+	link_reset_statistics(l_ptr);
+	node_unlock(node);
+	read_unlock_bh(&net_lock);
+	return cfg_reply_none();
+}
+
+/**
+ * percent - convert count to a percentage of total (rounding up or down)
+ */
+
+static u32 percent(u32 count, u32 total)
+{
+	return (count * 100 + (total / 2)) / total;
+}
+
+/**
+ * link_stats - print link statistics
+ * @name: link name
+ * @buf: print buffer area
+ * @buf_size: size of print buffer area
+ * 
+ * Returns length of print buffer data string (or 0 if error)
+ */
+
+static int link_stats(const char *name, char *buf, const u32 buf_size)
+{
+	struct print_buf pb;
+	struct link *l_ptr; 
+	struct node *node;
+	char *status;
+	u32 profile_total = 0;
+
+	if (!strcmp(name, bc_link_name))
+		return bclink_stats(buf, buf_size);
+
+	printbuf_init(&pb, buf, buf_size);
+
+	read_lock_bh(&net_lock);
+	l_ptr = link_find_link(name, &node); 
+	if (!l_ptr) {
+		read_unlock_bh(&net_lock);
+		return 0;
+	}
+	node_lock(node);
+
+	if (link_is_active(l_ptr))
+		status = "ACTIVE";
+	else if (link_is_up(l_ptr))
+		status = "STANDBY";
+	else
+		status = "DEFUNCT";
+	tipc_printf(&pb, "Link <%s>\n"
+		         "  %s  MTU:%u  Priority:%u  Tolerance:%u ms"
+		         "  Window:%u packets\n", 
+		    l_ptr->name, status, link_max_pkt(l_ptr), 
+		    l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
+	tipc_printf(&pb, "  RX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+		    l_ptr->next_in_no - l_ptr->stats.recv_info,
+		    l_ptr->stats.recv_fragments,
+		    l_ptr->stats.recv_fragmented,
+		    l_ptr->stats.recv_bundles,
+		    l_ptr->stats.recv_bundled);
+	tipc_printf(&pb, "  TX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+		    l_ptr->next_out_no - l_ptr->stats.sent_info,
+		    l_ptr->stats.sent_fragments,
+		    l_ptr->stats.sent_fragmented, 
+		    l_ptr->stats.sent_bundles,
+		    l_ptr->stats.sent_bundled);
+	profile_total = l_ptr->stats.msg_length_counts;
+	if (!profile_total)
+		profile_total = 1;
+	tipc_printf(&pb, "  TX profile sample:%u packets  average:%u octets\n"
+		         "  0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
+		         "-16354:%u%% -32768:%u%% -66000:%u%%\n",
+		    l_ptr->stats.msg_length_counts,
+		    l_ptr->stats.msg_lengths_total / profile_total,
+		    percent(l_ptr->stats.msg_length_profile[0], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[1], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[2], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[3], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[4], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[5], profile_total),
+		    percent(l_ptr->stats.msg_length_profile[6], profile_total));
+	tipc_printf(&pb, "  RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 
+		    l_ptr->stats.recv_states,
+		    l_ptr->stats.recv_probes,
+		    l_ptr->stats.recv_nacks,
+		    l_ptr->stats.deferred_recv, 
+		    l_ptr->stats.duplicates);
+	tipc_printf(&pb, "  TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 
+		    l_ptr->stats.sent_states, 
+		    l_ptr->stats.sent_probes, 
+		    l_ptr->stats.sent_nacks, 
+		    l_ptr->stats.sent_acks, 
+		    l_ptr->stats.retransmitted);
+	tipc_printf(&pb, "  Congestion bearer:%u link:%u  Send queue max:%u avg:%u\n",
+		    l_ptr->stats.bearer_congs,
+		    l_ptr->stats.link_congs, 
+		    l_ptr->stats.max_queue_sz,
+		    l_ptr->stats.queue_sz_counts
+		    ? (l_ptr->stats.accu_queue_sz / l_ptr->stats.queue_sz_counts)
+		    : 0);
+
+	node_unlock(node);
+	read_unlock_bh(&net_lock);
+	return printbuf_validate(&pb);
+}
+
+#define MAX_LINK_STATS_INFO 2000
+
+struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
+{
+	struct sk_buff *buf;
+	struct tlv_desc *rep_tlv;
+	int str_len;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	buf = cfg_reply_alloc(TLV_SPACE(MAX_LINK_STATS_INFO));
+	if (!buf)
+		return NULL;
+
+	rep_tlv = (struct tlv_desc *)buf->data;
+
+	str_len = link_stats((char *)TLV_DATA(req_tlv_area),
+			     (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);
+	if (!str_len) {
+		buf_discard(buf);
+	       	return cfg_reply_error_string("link not found");
+	}
+
+	skb_put(buf, TLV_SPACE(str_len));
+	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+	return buf;
+}
+
+#if 0
+int link_control(const char *name, u32 op, u32 val)
+{
+	int res = -EINVAL;
+	struct link *l_ptr;
+	u32 bearer_id;
+	struct node * node;
+	u32 a;
+
+	a = link_name2addr(name, &bearer_id);
+	read_lock_bh(&net_lock);
+	node = node_find(a);
+	if (node) {
+		node_lock(node);
+		l_ptr = node->links[bearer_id];
+		if (l_ptr) {
+			if (op == TIPC_REMOVE_LINK) {
+				struct bearer *b_ptr = l_ptr->b_ptr;
+				spin_lock_bh(&b_ptr->publ.lock);
+				link_delete(l_ptr);
+				spin_unlock_bh(&b_ptr->publ.lock);
+			}
+			if (op == TIPC_CMD_BLOCK_LINK) {
+				link_reset(l_ptr);
+				l_ptr->blocked = 1;
+			}
+			if (op == TIPC_CMD_UNBLOCK_LINK) {
+				l_ptr->blocked = 0;
+			}
+			res = TIPC_OK;
+		}
+		node_unlock(node);
+	}
+	read_unlock_bh(&net_lock);
+	return res;
+}
+#endif
+
+/**
+ * link_get_max_pkt - get maximum packet size to use when sending to destination
+ * @dest: network address of destination node
+ * @selector: used to select from set of active links
+ * 
+ * If no active link can be found, uses default maximum packet size.
+ */
+
+u32 link_get_max_pkt(u32 dest, u32 selector)
+{
+	struct node *n_ptr;
+	struct link *l_ptr;
+	u32 res = MAX_PKT_DEFAULT;
+	
+	if (dest == tipc_own_addr)
+		return MAX_MSG_SIZE;
+
+	read_lock_bh(&net_lock);        
+	n_ptr = node_select(dest, selector);
+	if (n_ptr) {
+		node_lock(n_ptr);
+		l_ptr = n_ptr->active_links[selector & 1];
+		if (l_ptr)
+			res = link_max_pkt(l_ptr);
+		node_unlock(n_ptr);
+	}
+	read_unlock_bh(&net_lock);       
+	return res;
+}
+
+#if 0
+static void link_dump_rec_queue(struct link *l_ptr)
+{
+	struct sk_buff *crs;
+
+	if (!l_ptr->oldest_deferred_in) {
+		info("Reception queue empty\n");
+		return;
+	}
+	info("Contents of Reception queue:\n");
+	crs = l_ptr->oldest_deferred_in;
+	while (crs) {
+		if (crs->data == (void *)0x0000a3a3) {
+			info("buffer %x invalid\n", crs);
+			return;
+		}
+		msg_dbg(buf_msg(crs), "In rec queue: \n");
+		crs = crs->next;
+	}
+}
+#endif
+
+static void link_dump_send_queue(struct link *l_ptr)
+{
+	if (l_ptr->next_out) {
+		info("\nContents of unsent queue:\n");
+		dbg_print_buf_chain(l_ptr->next_out);
+	}
+	info("\nContents of send queue:\n");
+	if (l_ptr->first_out) {
+		dbg_print_buf_chain(l_ptr->first_out);
+	}
+	info("Empty send queue\n");
+}
+
+static void link_print(struct link *l_ptr, struct print_buf *buf,
+		       const char *str)
+{
+	tipc_printf(buf, str);
+	if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr))
+		return;
+	tipc_printf(buf, "Link %x<%s>:",
+		    l_ptr->addr, l_ptr->b_ptr->publ.name);
+	tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no));
+	tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no));
+	tipc_printf(buf, "SQUE");
+	if (l_ptr->first_out) {
+		tipc_printf(buf, "[%u..", msg_seqno(buf_msg(l_ptr->first_out)));
+		if (l_ptr->next_out)
+			tipc_printf(buf, "%u..",
+				    msg_seqno(buf_msg(l_ptr->next_out)));
+		tipc_printf(buf, "%u]",
+			    msg_seqno(buf_msg
+				      (l_ptr->last_out)), l_ptr->out_queue_size);
+		if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) - 
+			 msg_seqno(buf_msg(l_ptr->first_out))) 
+		     != (l_ptr->out_queue_size - 1))
+		    || (l_ptr->last_out->next != 0)) {
+			tipc_printf(buf, "\nSend queue inconsistency\n");
+			tipc_printf(buf, "first_out= %x ", l_ptr->first_out);
+			tipc_printf(buf, "next_out= %x ", l_ptr->next_out);
+			tipc_printf(buf, "last_out= %x ", l_ptr->last_out);
+			link_dump_send_queue(l_ptr);
+		}
+	} else
+		tipc_printf(buf, "[]");
+	tipc_printf(buf, "SQSIZ(%u)", l_ptr->out_queue_size);
+	if (l_ptr->oldest_deferred_in) {
+		u32 o = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+		u32 n = msg_seqno(buf_msg(l_ptr->newest_deferred_in));
+		tipc_printf(buf, ":RQUE[%u..%u]", o, n);
+		if (l_ptr->deferred_inqueue_sz != mod((n + 1) - o)) {
+			tipc_printf(buf, ":RQSIZ(%u)",
+				    l_ptr->deferred_inqueue_sz);
+		}
+	}
+	if (link_working_unknown(l_ptr))
+		tipc_printf(buf, ":WU");
+	if (link_reset_reset(l_ptr))
+		tipc_printf(buf, ":RR");
+	if (link_reset_unknown(l_ptr))
+		tipc_printf(buf, ":RU");
+	if (link_working_working(l_ptr))
+		tipc_printf(buf, ":WW");
+	tipc_printf(buf, "\n");
+}
+
diff --git a/net/tipc/link.h b/net/tipc/link.h
new file mode 100644
index 0000000..c2553f0
--- /dev/null
+++ b/net/tipc/link.h
@@ -0,0 +1,296 @@
+/*
+ * net/tipc/link.h: Include file for TIPC link code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_LINK_H
+#define _TIPC_LINK_H
+
+#include "dbg.h"
+#include "msg.h"
+#include "bearer.h"
+#include "node.h"
+
+#define PUSH_FAILED   1
+#define PUSH_FINISHED 2
+
+/* 
+ * Link states 
+ */
+
+#define WORKING_WORKING 560810u
+#define WORKING_UNKNOWN 560811u
+#define RESET_UNKNOWN   560812u
+#define RESET_RESET     560813u
+
+/* 
+ * Starting value for maximum packet size negotiation on unicast links
+ * (unless bearer MTU is less)
+ */
+
+#define MAX_PKT_DEFAULT 1500
+
+/**
+ * struct link - TIPC link data structure
+ * @addr: network address of link's peer node
+ * @name: link name character string
+ * @media_addr: media address to use when sending messages over link
+ * @timer: link timer
+ * @owner: pointer to peer node
+ * @link_list: adjacent links in bearer's list of links
+ * @started: indicates if link has been started
+ * @checkpoint: reference point for triggering link continuity checking
+ * @peer_session: link session # being used by peer end of link
+ * @peer_bearer_id: bearer id used by link's peer endpoint
+ * @b_ptr: pointer to bearer used by link
+ * @tolerance: minimum link continuity loss needed to reset link [in ms] 
+ * @continuity_interval: link continuity testing interval [in ms]
+ * @abort_limit: # of unacknowledged continuity probes needed to reset link
+ * @state: current state of link FSM
+ * @blocked: indicates if link has been administratively blocked
+ * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state
+ * @proto_msg: template for control messages generated by link
+ * @pmsg: convenience pointer to "proto_msg" field
+ * @priority: current link priority
+ * @queue_limit: outbound message queue congestion thresholds (indexed by user)
+ * @exp_msg_count: # of tunnelled messages expected during link changeover
+ * @reset_checkpoint: seq # of last acknowledged message at time of link reset
+ * @max_pkt: current maximum packet size for this link
+ * @max_pkt_target: desired maximum packet size for this link
+ * @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target)
+ * @out_queue_size: # of messages in outbound message queue
+ * @first_out: ptr to first outbound message in queue
+ * @last_out: ptr to last outbound message in queue
+ * @next_out_no: next sequence number to use for outbound messages
+ * @last_retransmitted: sequence number of most recently retransmitted message
+ * @stale_count: # of identical retransmit requests made by peer
+ * @next_in_no: next sequence number to expect for inbound messages
+ * @deferred_inqueue_sz: # of messages in inbound message queue
+ * @oldest_deferred_in: ptr to first inbound message in queue
+ * @newest_deferred_in: ptr to last inbound message in queue
+ * @unacked_window: # of inbound messages rx'd without ack'ing back to peer
+ * @proto_msg_queue: ptr to (single) outbound control message
+ * @retransm_queue_size: number of messages to retransmit
+ * @retransm_queue_head: sequence number of first message to retransmit
+ * @next_out: ptr to first unsent outbound message in queue
+ * @waiting_ports: linked list of ports waiting for link congestion to abate
+ * @long_msg_seq_no: next identifier to use for outbound fragmented messages
+ * @defragm_buf: list of partially reassembled inbound message fragments
+ * @stats: collects statistics regarding link activity
+ * @print_buf: print buffer used to log link activity
+ */
+ 
+struct link {
+	u32 addr;
+	char name[TIPC_MAX_LINK_NAME];
+	struct tipc_media_addr media_addr;
+	struct timer_list timer;
+	struct node *owner;
+	struct list_head link_list;
+
+	/* Management and link supervision data */
+	int started;
+	u32 checkpoint;
+	u32 peer_session;
+	u32 peer_bearer_id;
+	struct bearer *b_ptr;
+	u32 tolerance;
+	u32 continuity_interval;
+	u32 abort_limit;
+	int state;
+	int blocked;
+	u32 fsm_msg_cnt;
+	struct {
+		unchar hdr[INT_H_SIZE];
+		unchar body[TIPC_MAX_IF_NAME];
+	} proto_msg;
+	struct tipc_msg *pmsg;
+	u32 priority;
+	u32 queue_limit[15];	/* queue_limit[0]==window limit */
+
+	/* Changeover */
+	u32 exp_msg_count;
+	u32 reset_checkpoint;
+
+        /* Max packet negotiation */
+        u32 max_pkt;
+        u32 max_pkt_target;
+        u32 max_pkt_probes;
+
+	/* Sending */
+	u32 out_queue_size;
+	struct sk_buff *first_out;
+	struct sk_buff *last_out;
+	u32 next_out_no;
+        u32 last_retransmitted;
+        u32 stale_count;
+
+	/* Reception */
+	u32 next_in_no;
+	u32 deferred_inqueue_sz;
+	struct sk_buff *oldest_deferred_in;
+	struct sk_buff *newest_deferred_in;
+	u32 unacked_window;
+
+	/* Congestion handling */
+	struct sk_buff *proto_msg_queue;
+	u32 retransm_queue_size;
+	u32 retransm_queue_head;
+	struct sk_buff *next_out;
+	struct list_head waiting_ports;
+
+	/* Fragmentation/defragmentation */
+	u32 long_msg_seq_no;
+	struct sk_buff *defragm_buf;
+
+        /* Statistics */
+	struct {
+		u32 sent_info;		/* used in counting # sent packets */
+		u32 recv_info;		/* used in counting # recv'd packets */
+		u32 sent_states;
+		u32 recv_states;
+		u32 sent_probes;
+		u32 recv_probes;
+		u32 sent_nacks;
+		u32 recv_nacks;
+		u32 sent_acks;
+		u32 sent_bundled;
+		u32 sent_bundles;
+		u32 recv_bundled;
+		u32 recv_bundles;
+		u32 retransmitted;
+		u32 sent_fragmented;
+		u32 sent_fragments;
+		u32 recv_fragmented;
+		u32 recv_fragments;
+		u32 link_congs;		/* # port sends blocked by congestion */
+		u32 bearer_congs;
+		u32 deferred_recv;
+		u32 duplicates;
+
+		/* for statistical profiling of send queue size */
+
+		u32 max_queue_sz;
+		u32 accu_queue_sz;
+		u32 queue_sz_counts;
+
+		/* for statistical profiling of message lengths */
+
+		u32 msg_length_counts;
+		u32 msg_lengths_total;
+		u32 msg_length_profile[7];
+#if 0
+		u32 sent_tunneled;
+		u32 recv_tunneled;
+#endif
+	} stats;
+
+	struct print_buf print_buf;
+};
+
+struct port;
+
+struct link *link_create(struct bearer *b_ptr, const u32 peer,
+			 const struct tipc_media_addr *media_addr);
+void link_delete(struct link *l_ptr);
+void link_changeover(struct link *l_ptr);
+void link_send_duplicate(struct link *l_ptr, struct link *dest);
+void link_reset_fragments(struct link *l_ptr);
+int link_is_up(struct link *l_ptr);
+int link_is_active(struct link *l_ptr);
+void link_start(struct link *l_ptr);
+u32 link_push_packet(struct link *l_ptr);
+void link_stop(struct link *l_ptr);
+struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd);
+struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space);
+void link_reset(struct link *l_ptr);
+int link_send(struct sk_buff *buf, u32 dest, u32 selector);
+int link_send_buf(struct link *l_ptr, struct sk_buff *buf);
+u32 link_get_max_pkt(u32 dest,u32 selector);
+int link_send_sections_fast(struct port* sender, 
+			    struct iovec const *msg_sect,
+			    const u32 num_sect, 
+			    u32 destnode);
+
+int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
+void link_tunnel(struct link *l_ptr, struct tipc_msg *tnl_hdr,
+		 struct tipc_msg *msg, u32 selector);
+void link_recv_bundle(struct sk_buff *buf);
+int  link_recv_fragment(struct sk_buff **pending,
+			struct sk_buff **fb,
+			struct tipc_msg **msg);
+void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int prob, u32 gap, 
+			 u32 tolerance, u32 priority, u32 acked_mtu);
+void link_push_queue(struct link *l_ptr);
+u32 link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
+		   struct sk_buff *buf);
+void link_wakeup_ports(struct link *l_ptr, int all);
+void link_set_queue_limits(struct link *l_ptr, u32 window);
+void link_retransmit(struct link *l_ptr, struct sk_buff *start, u32 retransmits);
+
+/*
+ * Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
+ */
+
+static inline u32 mod(u32 x)
+{
+	return x & 0xffffu;
+}
+
+static inline int between(u32 lower, u32 upper, u32 n)
+{
+	if ((lower < n) && (n < upper))
+		return 1;
+	if ((upper < lower) && ((n > lower) || (n < upper)))
+		return 1;
+	return 0;
+}
+
+static inline int less_eq(u32 left, u32 right)
+{
+	return (mod(right - left) < 32768u);
+}
+
+static inline int less(u32 left, u32 right)
+{
+	return (less_eq(left, right) && (mod(right) != mod(left)));
+}
+
+static inline u32 lesser(u32 left, u32 right)
+{
+	return less_eq(left, right) ? left : right;
+}
+
+#endif
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
new file mode 100644
index 0000000..03dbc55
--- /dev/null
+++ b/net/tipc/msg.c
@@ -0,0 +1,334 @@
+/*
+ * net/tipc/msg.c: TIPC message header routines
+ *     
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "addr.h"
+#include "dbg.h"
+#include "msg.h"
+#include "bearer.h"
+
+
+void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
+{
+	memcpy(&((int *)m)[5], a, sizeof(*a));
+}
+
+void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
+{
+	memcpy(a, &((int*)m)[5], sizeof(*a));
+}
+
+
+void msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
+{
+	u32 usr = msg_user(msg);
+	tipc_printf(buf, str);
+
+	switch (usr) {
+	case MSG_BUNDLER:
+		tipc_printf(buf, "BNDL::");
+		tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
+		break;
+	case BCAST_PROTOCOL:
+		tipc_printf(buf, "BCASTP::");
+		break;
+	case MSG_FRAGMENTER:
+		tipc_printf(buf, "FRAGM::");
+		switch (msg_type(msg)) {
+		case FIRST_FRAGMENT:
+			tipc_printf(buf, "FIRST:");
+			break;
+		case FRAGMENT:
+			tipc_printf(buf, "BODY:");
+			break;
+		case LAST_FRAGMENT:
+			tipc_printf(buf, "LAST:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
+
+		}
+		tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
+			    msg_fragm_no(msg));
+		break;
+	case DATA_LOW:
+	case DATA_MEDIUM:
+	case DATA_HIGH:
+	case DATA_CRITICAL:
+		tipc_printf(buf, "DAT%u:", msg_user(msg));
+		if (msg_short(msg)) {
+			tipc_printf(buf, "CON:");
+			break;
+		}
+		switch (msg_type(msg)) {
+		case TIPC_CONN_MSG:
+			tipc_printf(buf, "CON:");
+			break;
+		case TIPC_MCAST_MSG:
+			tipc_printf(buf, "MCST:");
+			break;
+		case TIPC_NAMED_MSG:
+			tipc_printf(buf, "NAM:");
+			break;
+		case TIPC_DIRECT_MSG:
+			tipc_printf(buf, "DIR:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg));
+		}
+		if (msg_routed(msg) && !msg_non_seq(msg))
+			tipc_printf(buf, "ROUT:");
+		if (msg_reroute_cnt(msg))
+			tipc_printf(buf, "REROUTED(%u):",
+				    msg_reroute_cnt(msg));
+		break;
+	case NAME_DISTRIBUTOR:
+		tipc_printf(buf, "NMD::");
+		switch (msg_type(msg)) {
+		case PUBLICATION:
+			tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20);	/* Items */
+			break;
+		case WITHDRAWAL:
+			tipc_printf(buf, "WDRW:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
+		}
+		if (msg_routed(msg))
+			tipc_printf(buf, "ROUT:");
+		if (msg_reroute_cnt(msg))
+			tipc_printf(buf, "REROUTED(%u):",
+				    msg_reroute_cnt(msg));
+		break;
+	case CONN_MANAGER:
+		tipc_printf(buf, "CONN_MNG:");
+		switch (msg_type(msg)) {
+		case CONN_PROBE:
+			tipc_printf(buf, "PROBE:");
+			break;
+		case CONN_PROBE_REPLY:
+			tipc_printf(buf, "PROBE_REPLY:");
+			break;
+		case CONN_ACK:
+			tipc_printf(buf, "CONN_ACK:");
+			tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg));
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+		}
+		if (msg_routed(msg))
+			tipc_printf(buf, "ROUT:");
+		if (msg_reroute_cnt(msg))
+			tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg));
+		break;
+	case LINK_PROTOCOL:
+		tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg));
+		switch (msg_type(msg)) {
+		case STATE_MSG:
+			tipc_printf(buf, "STATE:");
+			tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :"");
+			tipc_printf(buf, "NXS(%u):",msg_next_sent(msg));
+			tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg));
+			tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg));
+			break;
+		case RESET_MSG:
+			tipc_printf(buf, "RESET:");
+			if (msg_size(msg) != msg_hdr_sz(msg))
+				tipc_printf(buf, "BEAR:%s:",msg_data(msg));
+			break;
+		case ACTIVATE_MSG:
+			tipc_printf(buf, "ACTIVATE:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+		}
+		tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg));
+		tipc_printf(buf, "SESS(%u):",msg_session(msg));
+		break;
+	case CHANGEOVER_PROTOCOL:
+		tipc_printf(buf, "TUNL:");
+		switch (msg_type(msg)) {
+		case DUPLICATE_MSG:
+			tipc_printf(buf, "DUPL:");
+			break;
+		case ORIGINAL_MSG:
+			tipc_printf(buf, "ORIG:");
+			tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg));
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+		}
+		break;
+	case ROUTE_DISTRIBUTOR:
+		tipc_printf(buf, "ROUTING_MNG:");
+		switch (msg_type(msg)) {
+		case EXT_ROUTING_TABLE:
+			tipc_printf(buf, "EXT_TBL:");
+			tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+			break;
+		case LOCAL_ROUTING_TABLE:
+			tipc_printf(buf, "LOCAL_TBL:");
+			tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+			break;
+		case SLAVE_ROUTING_TABLE:
+			tipc_printf(buf, "DP_TBL:");
+			tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+			break;
+		case ROUTE_ADDITION:
+			tipc_printf(buf, "ADD:");
+			tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+			break;
+		case ROUTE_REMOVAL:
+			tipc_printf(buf, "REMOVE:");
+			tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+		}
+		break;
+	case LINK_CONFIG:
+		tipc_printf(buf, "CFG:");
+		switch (msg_type(msg)) {
+		case DSC_REQ_MSG:
+			tipc_printf(buf, "DSC_REQ:");
+			break;
+		case DSC_RESP_MSG:
+			tipc_printf(buf, "DSC_RESP:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg));
+			break;
+		}
+		break;
+	default:
+		tipc_printf(buf, "UNKNOWN USER:");
+	}
+
+	switch (usr) {
+	case CONN_MANAGER:
+	case NAME_DISTRIBUTOR:
+	case DATA_LOW:
+	case DATA_MEDIUM:
+	case DATA_HIGH:
+	case DATA_CRITICAL:
+		if (msg_short(msg))
+			break;	/* No error */
+		switch (msg_errcode(msg)) {
+		case TIPC_OK:
+			break;
+		case TIPC_ERR_NO_NAME:
+			tipc_printf(buf, "NO_NAME:");
+			break;
+		case TIPC_ERR_NO_PORT:
+			tipc_printf(buf, "NO_PORT:");
+			break;
+		case TIPC_ERR_NO_NODE:
+			tipc_printf(buf, "NO_PROC:");
+			break;
+		case TIPC_ERR_OVERLOAD:
+			tipc_printf(buf, "OVERLOAD:");
+			break;
+		case TIPC_CONN_SHUTDOWN:
+			tipc_printf(buf, "SHUTDOWN:");
+			break;
+		default:
+			tipc_printf(buf, "UNKNOWN ERROR(%x):",
+				    msg_errcode(msg));
+		}
+	default:{}
+	}
+
+	tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
+	tipc_printf(buf, "SZ(%u):", msg_size(msg));
+	tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));
+
+	if (msg_non_seq(msg))
+		tipc_printf(buf, "NOSEQ:");
+	else {
+		tipc_printf(buf, "ACK(%u):", msg_ack(msg));
+	}
+	tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
+	tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));
+
+	if (msg_isdata(msg)) {
+		if (msg_named(msg)) {
+			tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
+			tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
+		}
+	}
+
+	if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
+	    (usr != MSG_BUNDLER)) {
+		if (!msg_short(msg)) {
+			tipc_printf(buf, ":ORIG(%x:%u):",
+				    msg_orignode(msg), msg_origport(msg));
+			tipc_printf(buf, ":DEST(%x:%u):",
+				    msg_destnode(msg), msg_destport(msg));
+		} else {
+			tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
+			tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
+		}
+		if (msg_routed(msg) && !msg_non_seq(msg))
+			tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg));
+	}
+	if (msg_user(msg) == NAME_DISTRIBUTOR) {
+		tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
+		tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
+		if (msg_routed(msg)) {
+			tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg));
+		}
+	}
+
+	if (msg_user(msg) ==  LINK_CONFIG) {
+		u32* raw = (u32*)msg;
+		struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5];
+		tipc_printf(buf, ":REQL(%u):", msg_req_links(msg));
+		tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
+		tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
+		media_addr_printf(buf, orig);
+	}
+	if (msg_user(msg) == BCAST_PROTOCOL) {
+		tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
+		tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
+	}
+	tipc_printf(buf, "\n");
+	if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
+		msg_print(buf,msg_get_wrapped(msg),"      /");
+	}
+	if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
+		msg_print(buf,msg_get_wrapped(msg),"      /");
+	}
+}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
new file mode 100644
index 0000000..662c818
--- /dev/null
+++ b/net/tipc/msg.h
@@ -0,0 +1,818 @@
+/*
+ * net/tipc/msg.h: Include file for TIPC message header routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_MSG_H
+#define _TIPC_MSG_H
+
+#include <net/tipc/tipc_msg.h>
+
+#define TIPC_VERSION              2
+#define DATA_LOW                  TIPC_LOW_IMPORTANCE
+#define DATA_MEDIUM               TIPC_MEDIUM_IMPORTANCE
+#define DATA_HIGH                 TIPC_HIGH_IMPORTANCE
+#define DATA_CRITICAL             TIPC_CRITICAL_IMPORTANCE
+#define SHORT_H_SIZE              24	/* Connected,in cluster */
+#define DIR_MSG_H_SIZE            32	/* Directly addressed messages */
+#define CONN_MSG_H_SIZE           36	/* Routed connected msgs*/
+#define LONG_H_SIZE               40	/* Named Messages */
+#define MCAST_H_SIZE              44	/* Multicast messages */
+#define MAX_H_SIZE                60	/* Inclusive full options */
+#define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
+#define LINK_CONFIG               13
+
+
+/*
+		TIPC user data message header format, version 2
+		
+	- Fundamental definitions available to privileged TIPC users
+	  are located in tipc_msg.h.
+	- Remaining definitions available to TIPC internal users appear below. 
+*/
+
+
+static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val)
+{
+	m->hdr[w] = htonl(val);
+}
+
+static inline void msg_set_bits(struct tipc_msg *m, u32 w,
+				u32 pos, u32 mask, u32 val)
+{
+	u32 word = msg_word(m,w) & ~(mask << pos);
+	msg_set_word(m, w, (word |= (val << pos)));
+}
+
+/* 
+ * Word 0
+ */
+
+static inline u32 msg_version(struct tipc_msg *m)
+{
+	return msg_bits(m, 0, 29, 7);
+}
+
+static inline void msg_set_version(struct tipc_msg *m) 
+{
+	msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION);
+}
+
+static inline u32 msg_user(struct tipc_msg *m)
+{
+	return msg_bits(m, 0, 25, 0xf);
+}
+
+static inline u32 msg_isdata(struct tipc_msg *m)
+{
+	return (msg_user(m) <= DATA_CRITICAL);
+}
+
+static inline void msg_set_user(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 0, 25, 0xf, n);
+}
+
+static inline void msg_set_importance(struct tipc_msg *m, u32 i) 
+{
+	msg_set_user(m, i);
+}
+
+static inline void msg_set_hdr_sz(struct tipc_msg *m,u32 n) 
+{
+	msg_set_bits(m, 0, 21, 0xf, n>>2);
+}
+
+static inline int msg_non_seq(struct tipc_msg *m) 
+{
+	return msg_bits(m, 0, 20, 1);
+}
+
+static inline void msg_set_non_seq(struct tipc_msg *m) 
+{
+	msg_set_bits(m, 0, 20, 1, 1);
+}
+
+static inline int msg_dest_droppable(struct tipc_msg *m) 
+{
+	return msg_bits(m, 0, 19, 1);
+}
+
+static inline void msg_set_dest_droppable(struct tipc_msg *m, u32 d) 
+{
+	msg_set_bits(m, 0, 19, 1, d);
+}
+
+static inline int msg_src_droppable(struct tipc_msg *m) 
+{
+	return msg_bits(m, 0, 18, 1);
+}
+
+static inline void msg_set_src_droppable(struct tipc_msg *m, u32 d) 
+{
+	msg_set_bits(m, 0, 18, 1, d);
+}
+
+static inline void msg_set_size(struct tipc_msg *m, u32 sz)
+{
+	m->hdr[0] = htonl((msg_word(m, 0) & ~0x1ffff) | sz);
+}
+
+
+/* 
+ * Word 1
+ */
+
+static inline void msg_set_type(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 1, 29, 0x7, n);
+}
+
+static inline void msg_set_errcode(struct tipc_msg *m, u32 err) 
+{
+	msg_set_bits(m, 1, 25, 0xf, err);
+}
+
+static inline u32 msg_reroute_cnt(struct tipc_msg *m) 
+{
+	return msg_bits(m, 1, 21, 0xf);
+}
+
+static inline void msg_incr_reroute_cnt(struct tipc_msg *m) 
+{
+	msg_set_bits(m, 1, 21, 0xf, msg_reroute_cnt(m) + 1);
+}
+
+static inline void msg_reset_reroute_cnt(struct tipc_msg *m) 
+{
+	msg_set_bits(m, 1, 21, 0xf, 0);
+}
+
+static inline u32 msg_lookup_scope(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 19, 0x3);
+}
+
+static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 1, 19, 0x3, n);
+}
+
+static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz) 
+{
+	u32 hsz = msg_hdr_sz(m);
+	char *to = (char *)&m->hdr[hsz/4];
+
+	if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE))
+		return;
+	msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4);
+	msg_set_hdr_sz(m, hsz + sz);
+	memcpy(to, opt, sz);
+}
+
+static inline u32 msg_bcast_ack(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 0, 0xffff);
+}
+
+static inline void msg_set_bcast_ack(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 1, 0, 0xffff, n);
+}
+
+
+/* 
+ * Word 2
+ */
+
+static inline u32 msg_ack(struct tipc_msg *m)
+{
+	return msg_bits(m, 2, 16, 0xffff);
+}
+
+static inline void msg_set_ack(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 2, 16, 0xffff, n);
+}
+
+static inline u32 msg_seqno(struct tipc_msg *m)
+{
+	return msg_bits(m, 2, 0, 0xffff);
+}
+
+static inline void msg_set_seqno(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 2, 0, 0xffff, n);
+}
+
+
+/* 
+ * Words 3-10
+ */
+
+
+static inline void msg_set_prevnode(struct tipc_msg *m, u32 a) 
+{
+	msg_set_word(m, 3, a);
+}
+
+static inline void msg_set_origport(struct tipc_msg *m, u32 p) 
+{
+	msg_set_word(m, 4, p);
+}
+
+static inline void msg_set_destport(struct tipc_msg *m, u32 p) 
+{
+	msg_set_word(m, 5, p);
+}
+
+static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p) 
+{
+	msg_set_word(m, 5, p);
+}
+
+static inline void msg_set_orignode(struct tipc_msg *m, u32 a) 
+{
+	msg_set_word(m, 6, a);
+}
+
+static inline void msg_set_destnode(struct tipc_msg *m, u32 a) 
+{
+	msg_set_word(m, 7, a);
+}
+
+static inline int msg_is_dest(struct tipc_msg *m, u32 d) 
+{
+	return(msg_short(m) || (msg_destnode(m) == d));
+}
+
+static inline u32 msg_routed(struct tipc_msg *m)
+{
+	if (likely(msg_short(m)))
+		return 0;
+	return(msg_destnode(m) ^ msg_orignode(m)) >> 11;
+}
+
+static inline void msg_set_nametype(struct tipc_msg *m, u32 n) 
+{
+	msg_set_word(m, 8, n);
+}
+
+static inline u32 msg_transp_seqno(struct tipc_msg *m)
+{
+	return msg_word(m, 8);
+}
+
+static inline void msg_set_timestamp(struct tipc_msg *m, u32 n)
+{
+	msg_set_word(m, 8, n);
+}
+
+static inline u32 msg_timestamp(struct tipc_msg *m)
+{
+	return msg_word(m, 8);
+}
+
+static inline void msg_set_transp_seqno(struct tipc_msg *m, u32 n)
+{
+	msg_set_word(m, 8, n);
+}
+
+static inline void msg_set_namelower(struct tipc_msg *m, u32 n) 
+{
+	msg_set_word(m, 9, n);
+}
+
+static inline void msg_set_nameinst(struct tipc_msg *m, u32 n) 
+{
+	msg_set_namelower(m, n);
+}
+
+static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) 
+{
+	msg_set_word(m, 10, n);
+}
+
+static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
+{
+	return (struct tipc_msg *)msg_data(m);
+}
+
+static inline void msg_expand(struct tipc_msg *m, u32 destnode) 
+{
+	if (!msg_short(m))
+		return;
+	msg_set_hdr_sz(m, LONG_H_SIZE);
+	msg_set_orignode(m, msg_prevnode(m));
+	msg_set_destnode(m, destnode);
+	memset(&m->hdr[8], 0, 12);
+}
+
+
+
+/*
+		TIPC internal message header format, version 2
+
+       1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w0:|vers |msg usr|hdr sz |n|resrv|            packet size          |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w1:|m typ|rsv=0|   sequence gap    |       broadcast ack no        |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w2:| link level ack no/bc_gap_from |     seq no / bcast_gap_to     |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w3:|                       previous node                           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w4:|  next sent broadcast/fragm no | next sent pkt/ fragm msg no   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w5:|          session no           |rsv=0|r|berid|link prio|netpl|p|
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w6:|                      originating node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w7:|                      destination node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w8:|                   transport sequence number                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w9:|   msg count / bcast tag       |       link tolerance          |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      \                                                               \
+      /                     User Specific Data                        /
+      \                                                               \
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+      NB: CONN_MANAGER use data message format. LINK_CONFIG has own format.
+*/   
+
+/* 
+ * Internal users
+ */
+
+#define  BCAST_PROTOCOL       5
+#define  MSG_BUNDLER          6
+#define  LINK_PROTOCOL        7
+#define  CONN_MANAGER         8
+#define  ROUTE_DISTRIBUTOR    9
+#define  CHANGEOVER_PROTOCOL  10
+#define  NAME_DISTRIBUTOR     11
+#define  MSG_FRAGMENTER       12
+#define  LINK_CONFIG          13
+#define  INT_H_SIZE           40
+#define  DSC_H_SIZE           40
+
+/* 
+ *  Connection management protocol messages
+ */
+
+#define CONN_PROBE        0
+#define CONN_PROBE_REPLY  1
+#define CONN_ACK          2
+
+/* 
+ * Name distributor messages
+ */
+
+#define PUBLICATION       0
+#define WITHDRAWAL        1
+
+
+/* 
+ * Word 1
+ */
+
+static inline u32 msg_seq_gap(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 16, 0xff);
+}
+
+static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 1, 16, 0xff, n);
+}
+
+static inline u32 msg_req_links(struct tipc_msg *m)
+{
+	return msg_bits(m, 1, 16, 0xfff);
+}
+
+static inline void msg_set_req_links(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 1, 16, 0xfff, n);
+}
+
+
+/* 
+ * Word 2
+ */
+
+static inline u32 msg_dest_domain(struct tipc_msg *m)
+{
+	return msg_word(m, 2);
+}
+
+static inline void msg_set_dest_domain(struct tipc_msg *m, u32 n) 
+{
+	msg_set_word(m, 2, n);
+}
+
+static inline u32 msg_bcgap_after(struct tipc_msg *m)
+{
+	return msg_bits(m, 2, 16, 0xffff);
+}
+
+static inline void msg_set_bcgap_after(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 2, 16, 0xffff, n);
+}
+
+static inline u32 msg_bcgap_to(struct tipc_msg *m)
+{
+	return msg_bits(m, 2, 0, 0xffff);
+}
+
+static inline void msg_set_bcgap_to(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 2, 0, 0xffff, n);
+}
+
+
+/* 
+ * Word 4
+ */
+
+static inline u32 msg_last_bcast(struct tipc_msg *m)
+{
+	return msg_bits(m, 4, 16, 0xffff);
+}
+
+static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 4, 16, 0xffff, n);
+}
+
+
+static inline u32 msg_fragm_no(struct tipc_msg *m)
+{
+	return msg_bits(m, 4, 16, 0xffff);
+}
+
+static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 4, 16, 0xffff, n);
+}
+
+
+static inline u32 msg_next_sent(struct tipc_msg *m)
+{
+	return msg_bits(m, 4, 0, 0xffff);
+}
+
+static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 4, 0, 0xffff, n);
+}
+
+
+static inline u32 msg_long_msgno(struct tipc_msg *m)
+{
+	return msg_bits(m, 4, 0, 0xffff);
+}
+
+static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 4, 0, 0xffff, n);
+}
+
+static inline u32 msg_bc_netid(struct tipc_msg *m)
+{
+	return msg_word(m, 4);
+}
+
+static inline void msg_set_bc_netid(struct tipc_msg *m, u32 id)
+{
+	msg_set_word(m, 4, id);
+}
+
+static inline u32 msg_link_selector(struct tipc_msg *m)
+{
+	return msg_bits(m, 4, 0, 1);
+}
+
+static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 4, 0, 1, (n & 1));
+}
+
+/* 
+ * Word 5
+ */
+
+static inline u32 msg_session(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 16, 0xffff);
+}
+
+static inline void msg_set_session(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 5, 16, 0xffff, n);
+}
+
+static inline u32 msg_probe(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 0, 1);
+}
+
+static inline void msg_set_probe(struct tipc_msg *m, u32 val)
+{
+	msg_set_bits(m, 5, 0, 1, (val & 1));
+}
+
+static inline char msg_net_plane(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 1, 7) + 'A';
+}
+
+static inline void msg_set_net_plane(struct tipc_msg *m, char n)
+{
+	msg_set_bits(m, 5, 1, 7, (n - 'A'));
+}
+
+static inline u32 msg_linkprio(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 4, 0x1f);
+}
+
+static inline void msg_set_linkprio(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 5, 4, 0x1f, n);
+}
+
+static inline u32 msg_bearer_id(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 9, 0x7);
+}
+
+static inline void msg_set_bearer_id(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 5, 9, 0x7, n);
+}
+
+static inline u32 msg_redundant_link(struct tipc_msg *m)
+{
+	return msg_bits(m, 5, 12, 0x1);
+}
+
+static inline void msg_set_redundant_link(struct tipc_msg *m)
+{
+	msg_set_bits(m, 5, 12, 0x1, 1);
+}
+
+static inline void msg_clear_redundant_link(struct tipc_msg *m)
+{
+	msg_set_bits(m, 5, 12, 0x1, 0);
+}
+
+
+/* 
+ * Word 9
+ */
+
+static inline u32 msg_msgcnt(struct tipc_msg *m)
+{
+	return msg_bits(m, 9, 16, 0xffff);
+}
+
+static inline void msg_set_msgcnt(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 9, 16, 0xffff, n);
+}
+
+static inline u32 msg_bcast_tag(struct tipc_msg *m)
+{
+	return msg_bits(m, 9, 16, 0xffff);
+}
+
+static inline void msg_set_bcast_tag(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 9, 16, 0xffff, n);
+}
+
+static inline u32 msg_max_pkt(struct tipc_msg *m) 
+{
+	return (msg_bits(m, 9, 16, 0xffff) * 4);
+}
+
+static inline void msg_set_max_pkt(struct tipc_msg *m, u32 n) 
+{
+	msg_set_bits(m, 9, 16, 0xffff, (n / 4));
+}
+
+static inline u32 msg_link_tolerance(struct tipc_msg *m)
+{
+	return msg_bits(m, 9, 0, 0xffff);
+}
+
+static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
+{
+	msg_set_bits(m, 9, 0, 0xffff, n);
+}
+
+/* 
+ * Routing table message data
+ */
+
+
+static inline u32 msg_remote_node(struct tipc_msg *m)
+{
+	return msg_word(m, msg_hdr_sz(m)/4);
+}
+
+static inline void msg_set_remote_node(struct tipc_msg *m, u32 a)
+{
+	msg_set_word(m, msg_hdr_sz(m)/4, a);
+}
+
+static inline int msg_dataoctet(struct tipc_msg *m, u32 pos)
+{
+	return(msg_data(m)[pos + 4] != 0);
+}
+
+static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos)
+{
+	msg_data(m)[pos + 4] = 1;
+}
+
+/* 
+ * Segmentation message types
+ */
+
+#define FIRST_FRAGMENT     0
+#define FRAGMENT           1
+#define LAST_FRAGMENT      2
+
+/* 
+ * Link management protocol message types
+ */
+
+#define STATE_MSG       0
+#define RESET_MSG       1
+#define ACTIVATE_MSG    2
+
+/* 
+ * Changeover tunnel message types
+ */
+#define DUPLICATE_MSG    0
+#define ORIGINAL_MSG     1
+
+/* 
+ * Routing table message types
+ */
+#define EXT_ROUTING_TABLE    0
+#define LOCAL_ROUTING_TABLE  1
+#define SLAVE_ROUTING_TABLE  2
+#define ROUTE_ADDITION       3
+#define ROUTE_REMOVAL        4
+
+/* 
+ * Config protocol message types
+ */
+
+#define DSC_REQ_MSG          0
+#define DSC_RESP_MSG         1
+
+static inline u32 msg_tot_importance(struct tipc_msg *m)
+{
+	if (likely(msg_isdata(m))) {
+		if (likely(msg_orignode(m) == tipc_own_addr))
+			return msg_importance(m);
+		return msg_importance(m) + 4;
+	}
+	if ((msg_user(m) == MSG_FRAGMENTER)  &&
+	    (msg_type(m) == FIRST_FRAGMENT))
+		return msg_importance(msg_get_wrapped(m));
+	return msg_importance(m);
+}
+
+
+static inline void msg_init(struct tipc_msg *m, u32 user, u32 type, 
+			    u32 err, u32 hsize, u32 destnode)
+{
+	memset(m, 0, hsize);
+	msg_set_version(m);
+	msg_set_user(m, user);
+	msg_set_hdr_sz(m, hsize);
+	msg_set_size(m, hsize);
+	msg_set_prevnode(m, tipc_own_addr);
+	msg_set_type(m, type);
+	msg_set_errcode(m, err);
+	if (!msg_short(m)) {
+		msg_set_orignode(m, tipc_own_addr);
+		msg_set_destnode(m, destnode);
+	}
+}
+
+/** 
+ * msg_calc_data_size - determine total data size for message
+ */
+
+static inline int msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
+{
+	int dsz = 0;
+	int i;
+
+	for (i = 0; i < num_sect; i++)
+		dsz += msg_sect[i].iov_len;
+	return dsz;
+}
+
+/** 
+ * msg_build - create message using specified header and data
+ * 
+ * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
+ * 
+ * Returns message data size or errno
+ */
+
+static inline int msg_build(struct tipc_msg *hdr, 
+			    struct iovec const *msg_sect, u32 num_sect,
+			    int max_size, int usrmem, struct sk_buff** buf)
+{
+	int dsz, sz, hsz, pos, res, cnt;
+
+	dsz = msg_calc_data_size(msg_sect, num_sect);
+	if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
+		*buf = NULL;
+		return -EINVAL;
+	}
+
+	pos = hsz = msg_hdr_sz(hdr);
+	sz = hsz + dsz;
+	msg_set_size(hdr, sz);
+	if (unlikely(sz > max_size)) {
+		*buf = NULL;
+		return dsz;
+	}
+
+	*buf = buf_acquire(sz);
+	if (!(*buf))
+		return -ENOMEM;
+	memcpy((*buf)->data, (unchar *)hdr, hsz);
+	for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
+		if (likely(usrmem))
+			res = !copy_from_user((*buf)->data + pos, 
+					      msg_sect[cnt].iov_base, 
+					      msg_sect[cnt].iov_len);
+		else
+			memcpy((*buf)->data + pos, msg_sect[cnt].iov_base, 
+			       msg_sect[cnt].iov_len);
+		pos += msg_sect[cnt].iov_len;
+	}
+	if (likely(res))
+		return dsz;
+
+	buf_discard(*buf);
+	*buf = NULL;
+	return -EFAULT;
+}
+
+
+struct tipc_media_addr;
+
+extern void msg_set_media_addr(struct tipc_msg *m,
+			       struct tipc_media_addr *a);
+
+extern void msg_get_media_addr(struct tipc_msg *m,
+			       struct tipc_media_addr *a);
+
+
+#endif
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
new file mode 100644
index 0000000..41cbaf1
--- /dev/null
+++ b/net/tipc/name_distr.c
@@ -0,0 +1,309 @@
+/*
+ * net/tipc/name_distr.c: TIPC name distribution code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "cluster.h"
+#include "dbg.h"
+#include "link.h"
+#include "msg.h"
+#include "name_distr.h"
+
+#undef  DBG_OUTPUT
+#define DBG_OUTPUT NULL
+
+#define ITEM_SIZE sizeof(struct distr_item)
+
+/**
+ * struct distr_item - publication info distributed to other nodes
+ * @type: name sequence type
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @ref: publishing port reference
+ * @key: publication key
+ * 
+ * ===> All fields are stored in network byte order. <===
+ * 
+ * First 3 fields identify (name or) name sequence being published.
+ * Reference field uniquely identifies port that published name sequence.
+ * Key field uniquely identifies publication, in the event a port has
+ * multiple publications of the same name sequence.
+ * 
+ * Note: There is no field that identifies the publishing node because it is 
+ * the same for all items contained within a publication message.
+ */
+
+struct distr_item {
+	u32 type;
+	u32 lower;
+	u32 upper;
+	u32 ref;
+	u32 key;
+};
+
+/**
+ * List of externally visible publications by this node -- 
+ * that is, all publications having scope > TIPC_NODE_SCOPE.
+ */
+
+static LIST_HEAD(publ_root);
+static u32 publ_cnt = 0;		
+
+/**
+ * publ_to_item - add publication info to a publication message
+ */
+
+static void publ_to_item(struct distr_item *i, struct publication *p)
+{
+	i->type = htonl(p->type);
+	i->lower = htonl(p->lower);
+	i->upper = htonl(p->upper);
+	i->ref = htonl(p->ref);
+	i->key = htonl(p->key);
+	dbg("publ_to_item: %u, %u, %u\n", p->type, p->lower, p->upper);
+}
+
+/**
+ * named_prepare_buf - allocate & initialize a publication message
+ */
+
+static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
+{
+	struct sk_buff *buf = buf_acquire(LONG_H_SIZE + size);  
+	struct tipc_msg *msg;
+
+	if (buf != NULL) {
+		msg = buf_msg(buf);
+		msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK, 
+			 LONG_H_SIZE, dest);
+		msg_set_size(msg, LONG_H_SIZE + size);
+	}
+	return buf;
+}
+
+/**
+ * named_publish - tell other nodes about a new publication by this node
+ */
+
+void named_publish(struct publication *publ)
+{
+	struct sk_buff *buf;
+	struct distr_item *item;
+
+	list_add(&publ->local_list, &publ_root);
+	publ_cnt++;
+
+	buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
+	if (!buf) {
+		warn("Memory squeeze; failed to distribute publication\n");
+		return;
+	}
+
+	item = (struct distr_item *)msg_data(buf_msg(buf));
+	publ_to_item(item, publ);
+	dbg("named_withdraw: broadcasting publish msg\n");
+	cluster_broadcast(buf);
+}
+
+/**
+ * named_withdraw - tell other nodes about a withdrawn publication by this node
+ */
+
+void named_withdraw(struct publication *publ)
+{
+	struct sk_buff *buf;
+	struct distr_item *item;
+
+	list_del(&publ->local_list);
+	publ_cnt--;
+
+	buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
+	if (!buf) {
+		warn("Memory squeeze; failed to distribute withdrawal\n");
+		return;
+	}
+
+	item = (struct distr_item *)msg_data(buf_msg(buf));
+	publ_to_item(item, publ);
+	dbg("named_withdraw: broadcasting withdraw msg\n");
+	cluster_broadcast(buf);
+}
+
+/**
+ * named_node_up - tell specified node about all publications by this node
+ */
+
+void named_node_up(unsigned long node)
+{
+	struct publication *publ;
+	struct distr_item *item = 0;
+	struct sk_buff *buf = 0;
+	u32 left = 0;
+	u32 rest;
+	u32 max_item_buf;
+
+	assert(in_own_cluster(node));
+	read_lock_bh(&nametbl_lock); 
+	max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
+	max_item_buf *= ITEM_SIZE;
+	rest = publ_cnt * ITEM_SIZE;
+
+	list_for_each_entry(publ, &publ_root, local_list) {
+		if (!buf) {
+			left = (rest <= max_item_buf) ? rest : max_item_buf;
+			rest -= left;
+			buf = named_prepare_buf(PUBLICATION, left, node);       
+			if (buf == NULL) {
+				warn("Memory Squeeze; could not send publication\n");
+				goto exit;
+			}
+			item = (struct distr_item *)msg_data(buf_msg(buf));
+		}
+		publ_to_item(item, publ);
+		item++;
+		left -= ITEM_SIZE;
+		if (!left) {
+			msg_set_link_selector(buf_msg(buf), node);
+			dbg("named_node_up: sending publish msg to "
+			    "<%u.%u.%u>\n", tipc_zone(node), 
+			    tipc_cluster(node), tipc_node(node));
+			link_send(buf, node, node);
+			buf = 0;
+		}
+	}
+exit:
+	read_unlock_bh(&nametbl_lock); 
+}
+
+/**
+ * node_is_down - remove publication associated with a failed node
+ * 
+ * Invoked for each publication issued by a newly failed node.  
+ * Removes publication structure from name table & deletes it.
+ * In rare cases the link may have come back up again when this
+ * function is called, and we have two items representing the same
+ * publication. Nudge this item's key to distinguish it from the other.
+ * (Note: Publication's node subscription is already unsubscribed.)
+ */
+
+static void node_is_down(struct publication *publ)
+{
+	struct publication *p;
+        write_lock_bh(&nametbl_lock);
+	dbg("node_is_down: withdrawing %u, %u, %u\n", 
+	    publ->type, publ->lower, publ->upper);
+        publ->key += 1222345;
+	p = nametbl_remove_publ(publ->type, publ->lower, 
+				publ->node, publ->ref, publ->key);
+        assert(p == publ);
+	write_unlock_bh(&nametbl_lock);
+	if (publ)
+		kfree(publ);
+}
+
+/**
+ * named_recv - process name table update message sent by another node
+ */
+
+void named_recv(struct sk_buff *buf)
+{
+	struct publication *publ;
+	struct tipc_msg *msg = buf_msg(buf);
+	struct distr_item *item = (struct distr_item *)msg_data(msg);
+	u32 count = msg_data_sz(msg) / ITEM_SIZE;
+
+	write_lock_bh(&nametbl_lock); 
+	while (count--) {
+		if (msg_type(msg) == PUBLICATION) {
+			dbg("named_recv: got publication for %u, %u, %u\n", 
+			    ntohl(item->type), ntohl(item->lower),
+			    ntohl(item->upper));
+			publ = nametbl_insert_publ(ntohl(item->type), 
+						   ntohl(item->lower),
+						   ntohl(item->upper),
+						   TIPC_CLUSTER_SCOPE,
+						   msg_orignode(msg), 
+						   ntohl(item->ref),
+						   ntohl(item->key));
+			if (publ) {
+				nodesub_subscribe(&publ->subscr, 
+						  msg_orignode(msg), 
+						  publ,
+						  (net_ev_handler)node_is_down);
+			}
+		} else if (msg_type(msg) == WITHDRAWAL) {
+			dbg("named_recv: got withdrawl for %u, %u, %u\n", 
+			    ntohl(item->type), ntohl(item->lower),
+			    ntohl(item->upper));
+			publ = nametbl_remove_publ(ntohl(item->type),
+						   ntohl(item->lower),
+						   msg_orignode(msg),
+						   ntohl(item->ref),
+						   ntohl(item->key));
+
+			if (publ) {
+				nodesub_unsubscribe(&publ->subscr);
+        			kfree(publ);
+			}
+		} else {
+			warn("named_recv: unknown msg\n");
+		}
+		item++;
+	}
+	write_unlock_bh(&nametbl_lock); 
+	buf_discard(buf);
+}
+
+/**
+ * named_reinit - re-initialize local publication list
+ * 
+ * This routine is called whenever TIPC networking is (re)enabled.
+ * All existing publications by this node that have "cluster" or "zone" scope
+ * are updated to reflect the node's current network address.
+ * (If the node's address is unchanged, the update loop terminates immediately.)
+ */
+
+void named_reinit(void)
+{
+	struct publication *publ;
+
+	write_lock_bh(&nametbl_lock); 
+	list_for_each_entry(publ, &publ_root, local_list) {
+		if (publ->node == tipc_own_addr)
+			break;
+		publ->node = tipc_own_addr;
+	}
+	write_unlock_bh(&nametbl_lock); 
+}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
new file mode 100644
index 0000000..a04bdea
--- /dev/null
+++ b/net/tipc/name_distr.h
@@ -0,0 +1,48 @@
+/*
+ * net/tipc/name_distr.h: Include file for TIPC name distribution code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NAME_DISTR_H
+#define _TIPC_NAME_DISTR_H
+
+#include "name_table.h"
+
+void named_publish(struct publication *publ);
+void named_withdraw(struct publication *publ);
+void named_node_up(unsigned long node);
+void named_recv(struct sk_buff *buf);
+void named_reinit(void);
+
+#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
new file mode 100644
index 0000000..972c83e
--- /dev/null
+++ b/net/tipc/name_table.c
@@ -0,0 +1,1079 @@
+/*
+ * net/tipc/name_table.c: TIPC name table code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "name_table.h"
+#include "name_distr.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "subscr.h"
+#include "port.h"
+#include "cluster.h"
+#include "bcast.h"
+
+int tipc_nametbl_size = 1024;		/* must be a power of 2 */
+
+/**
+ * struct sub_seq - container for all published instances of a name sequence
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @node_list: circular list of matching publications with >= node scope
+ * @cluster_list: circular list of matching publications with >= cluster scope
+ * @zone_list: circular list of matching publications with >= zone scope
+ */
+
+struct sub_seq {
+	u32 lower;
+	u32 upper;
+	struct publication *node_list;
+	struct publication *cluster_list;
+	struct publication *zone_list;
+};
+
+/** 
+ * struct name_seq - container for all published instances of a name type
+ * @type: 32 bit 'type' value for name sequence
+ * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
+ *        sub-sequences are sorted in ascending order
+ * @alloc: number of sub-sequences currently in array
+ * @first_free: upper bound of highest sub-sequence + 1
+ * @ns_list: links to adjacent name sequences in hash chain
+ * @subscriptions: list of subscriptions for this 'type'
+ * @lock: spinlock controlling access to name sequence structure
+ */
+
+struct name_seq {
+	u32 type;
+	struct sub_seq *sseqs;
+	u32 alloc;
+	u32 first_free;
+	struct hlist_node ns_list;
+	struct list_head subscriptions;
+	spinlock_t lock;
+};
+
+/**
+ * struct name_table - table containing all existing port name publications
+ * @types: pointer to fixed-sized array of name sequence lists, 
+ *         accessed via hashing on 'type'; name sequence lists are *not* sorted
+ * @local_publ_count: number of publications issued by this node
+ */
+
+struct name_table {
+	struct hlist_head *types;
+	u32 local_publ_count;
+};
+
+struct name_table table = { NULL } ;
+static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
+rwlock_t nametbl_lock = RW_LOCK_UNLOCKED;
+
+
+static inline int hash(int x)
+{
+	return(x & (tipc_nametbl_size - 1));
+}
+
+/**
+ * publ_create - create a publication structure
+ */
+
+static struct publication *publ_create(u32 type, u32 lower, u32 upper, 
+				       u32 scope, u32 node, u32 port_ref,   
+				       u32 key)
+{
+	struct publication *publ =
+		(struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
+	if (publ == NULL) {
+		warn("Memory squeeze; failed to create publication\n");
+		return 0;
+	}
+
+	memset(publ, 0, sizeof(*publ));
+	publ->type = type;
+	publ->lower = lower;
+	publ->upper = upper;
+	publ->scope = scope;
+	publ->node = node;
+	publ->ref = port_ref;
+	publ->key = key;
+	INIT_LIST_HEAD(&publ->local_list);
+	INIT_LIST_HEAD(&publ->pport_list);
+	INIT_LIST_HEAD(&publ->subscr.nodesub_list);
+	return publ;
+}
+
+/**
+ * subseq_alloc - allocate a specified number of sub-sequence structures
+ */
+
+struct sub_seq *subseq_alloc(u32 cnt)
+{
+	u32 sz = cnt * sizeof(struct sub_seq);
+	struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);
+
+	if (sseq)
+		memset(sseq, 0, sz);
+	return sseq;
+}
+
+/**
+ * nameseq_create - create a name sequence structure for the specified 'type'
+ * 
+ * Allocates a single sub-sequence structure and sets it to all 0's.
+ */
+
+struct name_seq *nameseq_create(u32 type, struct hlist_head *seq_head)
+{
+	struct name_seq *nseq = 
+		(struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
+	struct sub_seq *sseq = subseq_alloc(1);
+
+	if (!nseq || !sseq) {
+		warn("Memory squeeze; failed to create name sequence\n");
+		kfree(nseq);
+		kfree(sseq);
+		return 0;
+	}
+
+	memset(nseq, 0, sizeof(*nseq));
+	nseq->lock = SPIN_LOCK_UNLOCKED;
+	nseq->type = type;
+	nseq->sseqs = sseq;
+	dbg("nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n",
+	    nseq, type, nseq->sseqs, nseq->first_free);
+	nseq->alloc = 1;
+	INIT_HLIST_NODE(&nseq->ns_list);
+	INIT_LIST_HEAD(&nseq->subscriptions);
+	hlist_add_head(&nseq->ns_list, seq_head);
+	return nseq;
+}
+
+/**
+ * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
+ *  
+ * Very time-critical, so binary searches through sub-sequence array.
+ */
+
+static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, 
+						  u32 instance)
+{
+	struct sub_seq *sseqs = nseq->sseqs;
+	int low = 0;
+	int high = nseq->first_free - 1;
+	int mid;
+
+	while (low <= high) {
+		mid = (low + high) / 2;
+		if (instance < sseqs[mid].lower)
+			high = mid - 1;
+		else if (instance > sseqs[mid].upper)
+			low = mid + 1;
+		else
+			return &sseqs[mid];
+	}
+	return 0;
+}
+
+/**
+ * nameseq_locate_subseq - determine position of name instance in sub-sequence
+ * 
+ * Returns index in sub-sequence array of the entry that contains the specified
+ * instance value; if no entry contains that value, returns the position
+ * where a new entry for it would be inserted in the array.
+ *
+ * Note: Similar to binary search code for locating a sub-sequence.
+ */
+
+static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
+{
+	struct sub_seq *sseqs = nseq->sseqs;
+	int low = 0;
+	int high = nseq->first_free - 1;
+	int mid;
+
+	while (low <= high) {
+		mid = (low + high) / 2;
+		if (instance < sseqs[mid].lower)
+			high = mid - 1;
+		else if (instance > sseqs[mid].upper)
+			low = mid + 1;
+		else
+			return mid;
+	}
+	return low;
+}
+
+/**
+ * nameseq_insert_publ - 
+ */
+
+struct publication *nameseq_insert_publ(struct name_seq *nseq,
+					u32 type, u32 lower, u32 upper,
+					u32 scope, u32 node, u32 port, u32 key)
+{
+	struct subscription *s;
+	struct subscription *st;
+	struct publication *publ;
+	struct sub_seq *sseq;
+	int created_subseq = 0;
+
+	assert(nseq->first_free <= nseq->alloc);
+	sseq = nameseq_find_subseq(nseq, lower);
+	dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n",
+	    nseq, type, lower, sseq);
+	if (sseq) {
+
+		/* Lower end overlaps existing entry => need an exact match */
+
+		if ((sseq->lower != lower) || (sseq->upper != upper)) {
+			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+			return 0;
+		}
+	} else {
+		u32 inspos;
+		struct sub_seq *freesseq;
+
+		/* Find where lower end should be inserted */
+
+		inspos = nameseq_locate_subseq(nseq, lower);
+
+		/* Fail if upper end overlaps into an existing entry */
+
+		if ((inspos < nseq->first_free) &&
+		    (upper >= nseq->sseqs[inspos].lower)) {
+			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+			return 0;
+		}
+
+		/* Ensure there is space for new sub-sequence */
+
+		if (nseq->first_free == nseq->alloc) {
+			struct sub_seq *sseqs = nseq->sseqs;
+			nseq->sseqs = subseq_alloc(nseq->alloc * 2);
+			if (nseq->sseqs != NULL) {
+				memcpy(nseq->sseqs, sseqs,
+				       nseq->alloc * sizeof (struct sub_seq));
+				kfree(sseqs);
+				dbg("Allocated %u sseqs\n", nseq->alloc);
+				nseq->alloc *= 2;
+			} else {
+				warn("Memory squeeze; failed to create sub-sequence\n");
+				return 0;
+			}
+		}
+		dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
+
+		/* Insert new sub-sequence */
+
+		dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free);
+		sseq = &nseq->sseqs[inspos];
+		freesseq = &nseq->sseqs[nseq->first_free];
+		memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq));
+		memset(sseq, 0, sizeof (*sseq));
+		nseq->first_free++;
+		sseq->lower = lower;
+		sseq->upper = upper;
+		created_subseq = 1;
+	}
+	dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n",
+	    type, lower, upper, node, port, sseq,
+	    sseq->lower, sseq->upper, nseq);
+
+	/* Insert a publication: */
+
+	publ = publ_create(type, lower, upper, scope, node, port, key);
+	if (!publ)
+		return 0;
+	dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
+	    publ, node, publ->node, publ->subscr.node);
+
+	if (!sseq->zone_list)
+		sseq->zone_list = publ->zone_list_next = publ;
+	else {
+		publ->zone_list_next = sseq->zone_list->zone_list_next;
+		sseq->zone_list->zone_list_next = publ;
+	}
+
+	if (in_own_cluster(node)) {
+		if (!sseq->cluster_list)
+			sseq->cluster_list = publ->cluster_list_next = publ;
+		else {
+			publ->cluster_list_next =
+			sseq->cluster_list->cluster_list_next;
+			sseq->cluster_list->cluster_list_next = publ;
+		}
+	}
+
+	if (node == tipc_own_addr) {
+		if (!sseq->node_list)
+			sseq->node_list = publ->node_list_next = publ;
+		else {
+			publ->node_list_next = sseq->node_list->node_list_next;
+			sseq->node_list->node_list_next = publ;
+		}
+	}
+
+	/* 
+	 * Any subscriptions waiting for notification? 
+	 */
+	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
+		dbg("calling report_overlap()\n");
+		subscr_report_overlap(s,
+				      publ->lower,
+				      publ->upper,
+				      TIPC_PUBLISHED,
+				      publ->ref, 
+				      publ->node,
+				      created_subseq);
+	}
+	return publ;
+}
+
+/**
+ * nameseq_remove_publ -
+ */
+
+struct publication *nameseq_remove_publ(struct name_seq *nseq, u32 inst,
+					u32 node, u32 ref, u32 key)
+{
+	struct publication *publ;
+	struct publication *prev;
+	struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
+	struct sub_seq *free;
+	struct subscription *s, *st;
+	int removed_subseq = 0;
+
+	assert(nseq);
+
+	if (!sseq) {
+		int i;
+
+		warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
+		assert(nseq->sseqs);
+		dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
+		    nseq->sseqs, nseq, nseq->alloc, 
+		    nseq->first_free);
+		for (i = 0; i < nseq->first_free; i++) {
+			dbg("Subseq %u(%x): lower = %u,upper = %u\n",
+			    i, &nseq->sseqs[i], nseq->sseqs[i].lower,
+			    nseq->sseqs[i].upper);
+		}
+		return 0;
+	}
+	dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
+	    nseq, sseq, nseq->type, inst, key);
+
+	prev = sseq->zone_list;
+	publ = sseq->zone_list->zone_list_next;
+	while ((publ->key != key) || (publ->ref != ref) || 
+	       (publ->node && (publ->node != node))) {
+		prev = publ;
+		publ = publ->zone_list_next;
+		assert(prev != sseq->zone_list);
+	}
+	if (publ != sseq->zone_list)
+		prev->zone_list_next = publ->zone_list_next;
+	else if (publ->zone_list_next != publ) {
+		prev->zone_list_next = publ->zone_list_next;
+		sseq->zone_list = publ->zone_list_next;
+	} else {
+		sseq->zone_list = 0;
+	}
+
+	if (in_own_cluster(node)) {
+		prev = sseq->cluster_list;
+		publ = sseq->cluster_list->cluster_list_next;
+		while ((publ->key != key) || (publ->ref != ref) || 
+		       (publ->node && (publ->node != node))) {
+			prev = publ;
+			publ = publ->cluster_list_next;
+			assert(prev != sseq->cluster_list);
+		}
+		if (publ != sseq->cluster_list)
+			prev->cluster_list_next = publ->cluster_list_next;
+		else if (publ->cluster_list_next != publ) {
+			prev->cluster_list_next = publ->cluster_list_next;
+			sseq->cluster_list = publ->cluster_list_next;
+		} else {
+			sseq->cluster_list = 0;
+		}
+	}
+
+	if (node == tipc_own_addr) {
+		prev = sseq->node_list;
+		publ = sseq->node_list->node_list_next;
+		while ((publ->key != key) || (publ->ref != ref) || 
+		       (publ->node && (publ->node != node))) {
+			prev = publ;
+			publ = publ->node_list_next;
+			assert(prev != sseq->node_list);
+		}
+		if (publ != sseq->node_list)
+			prev->node_list_next = publ->node_list_next;
+		else if (publ->node_list_next != publ) {
+			prev->node_list_next = publ->node_list_next;
+			sseq->node_list = publ->node_list_next;
+		} else {
+			sseq->node_list = 0;
+		}
+	}
+	assert(!publ->node || (publ->node == node));
+	assert(publ->ref == ref);
+	assert(publ->key == key);
+
+	/* 
+	 * Contract subseq list if no more publications:
+	 */
+	if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
+		free = &nseq->sseqs[nseq->first_free--];
+		memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
+		removed_subseq = 1;
+	}
+
+	/* 
+	 * Any subscriptions waiting ? 
+	 */
+	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
+		subscr_report_overlap(s,
+				      publ->lower,
+				      publ->upper,
+				      TIPC_WITHDRAWN, 
+				      publ->ref, 
+				      publ->node,
+				      removed_subseq);
+	}
+	return publ;
+}
+
+/**
+ * nameseq_subscribe: attach a subscription, and issue
+ * the prescribed number of events if there is any sub-
+ * sequence overlapping with the requested sequence
+ */
+
+void nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
+{
+	struct sub_seq *sseq = nseq->sseqs;
+
+	list_add(&s->nameseq_list, &nseq->subscriptions);
+
+	if (!sseq)
+		return;
+
+	while (sseq != &nseq->sseqs[nseq->first_free]) {
+		struct publication *zl = sseq->zone_list;
+		if (zl && subscr_overlap(s,sseq->lower,sseq->upper)) {
+			struct publication *crs = zl;
+			int must_report = 1;
+
+			do {
+				subscr_report_overlap(s, 
+						       sseq->lower, 
+						       sseq->upper,
+						       TIPC_PUBLISHED,
+						       crs->ref,
+						       crs->node,
+						       must_report);
+				must_report = 0;
+				crs = crs->zone_list_next;
+			} while (crs != zl);
+		}
+		sseq++;
+	}
+}
+
+static struct name_seq *nametbl_find_seq(u32 type)
+{
+	struct hlist_head *seq_head;
+	struct hlist_node *seq_node;
+	struct name_seq *ns;
+
+	dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n",
+	    type, ntohl(type), type, table.types, hash(type));
+
+	seq_head = &table.types[hash(type)];
+	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
+		if (ns->type == type) {
+			dbg("found %x\n", ns);
+			return ns;
+		}
+	}
+
+	return 0;
+};
+
+struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
+		    u32 scope, u32 node, u32 port, u32 key)
+{
+	struct name_seq *seq = nametbl_find_seq(type);
+
+	dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq);
+	if (lower > upper) {
+		warn("Failed to publish illegal <%u,%u,%u>\n",
+		     type, lower, upper);
+		return 0;
+	}
+
+	dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
+	if (!seq) {
+		seq = nameseq_create(type, &table.types[hash(type)]);
+		dbg("nametbl_insert_publ: created %x\n", seq);
+	}
+	if (!seq)
+		return 0;
+
+	assert(seq->type == type);
+	return nameseq_insert_publ(seq, type, lower, upper,
+				   scope, node, port, key);
+}
+
+struct publication *nametbl_remove_publ(u32 type, u32 lower, 
+					u32 node, u32 ref, u32 key)
+{
+	struct publication *publ;
+	struct name_seq *seq = nametbl_find_seq(type);
+
+	if (!seq)
+		return 0;
+
+	dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
+	publ = nameseq_remove_publ(seq, lower, node, ref, key);
+
+	if (!seq->first_free && list_empty(&seq->subscriptions)) {
+		hlist_del_init(&seq->ns_list);
+		kfree(seq->sseqs);
+		kfree(seq);
+	}
+	return publ;
+}
+
+/*
+ * nametbl_translate(): Translate tipc_name -> tipc_portid.
+ *                      Very time-critical.
+ *
+ * Note: on entry 'destnode' is the search domain used during translation;
+ *       on exit it passes back the node address of the matching port (if any)
+ */
+
+u32 nametbl_translate(u32 type, u32 instance, u32 *destnode)
+{
+	struct sub_seq *sseq;
+	struct publication *publ = 0;
+	struct name_seq *seq;
+	u32 ref;
+
+	if (!in_scope(*destnode, tipc_own_addr))
+		return 0;
+
+	read_lock_bh(&nametbl_lock);
+	seq = nametbl_find_seq(type);
+	if (unlikely(!seq))
+		goto not_found;
+	sseq = nameseq_find_subseq(seq, instance);
+	if (unlikely(!sseq))
+		goto not_found;
+	spin_lock_bh(&seq->lock);
+
+	/* Closest-First Algorithm: */
+	if (likely(!*destnode)) {
+		publ = sseq->node_list;
+		if (publ) {
+			sseq->node_list = publ->node_list_next;
+found:
+			ref = publ->ref;
+			*destnode = publ->node;
+			spin_unlock_bh(&seq->lock);
+			read_unlock_bh(&nametbl_lock);
+			return ref;
+		}
+		publ = sseq->cluster_list;
+		if (publ) {
+			sseq->cluster_list = publ->cluster_list_next;
+			goto found;
+		}
+		publ = sseq->zone_list;
+		if (publ) {
+			sseq->zone_list = publ->zone_list_next;
+			goto found;
+		}
+	}
+
+	/* Round-Robin Algorithm: */
+	else if (*destnode == tipc_own_addr) {
+		publ = sseq->node_list;
+		if (publ) {
+			sseq->node_list = publ->node_list_next;
+			goto found;
+		}
+	} else if (in_own_cluster(*destnode)) {
+		publ = sseq->cluster_list;
+		if (publ) {
+			sseq->cluster_list = publ->cluster_list_next;
+			goto found;
+		}
+	} else {
+		publ = sseq->zone_list;
+		if (publ) {
+			sseq->zone_list = publ->zone_list_next;
+			goto found;
+		}
+	}
+	spin_unlock_bh(&seq->lock);
+not_found:
+	*destnode = 0;
+	read_unlock_bh(&nametbl_lock);
+	return 0;
+}
+
+/**
+ * nametbl_mc_translate - find multicast destinations
+ * 
+ * Creates list of all local ports that overlap the given multicast address;
+ * also determines if any off-node ports overlap.
+ *
+ * Note: Publications with a scope narrower than 'limit' are ignored.
+ * (i.e. local node-scope publications mustn't receive messages arriving
+ * from another node, even if the multcast link brought it here)
+ * 
+ * Returns non-zero if any off-node ports overlap
+ */
+
+int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
+			 struct port_list *dports)
+{
+	struct name_seq *seq;
+	struct sub_seq *sseq;
+	struct sub_seq *sseq_stop;
+	int res = 0;
+
+	read_lock_bh(&nametbl_lock);
+	seq = nametbl_find_seq(type);
+	if (!seq)
+		goto exit;
+
+	spin_lock_bh(&seq->lock);
+
+	sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
+	sseq_stop = seq->sseqs + seq->first_free;
+	for (; sseq != sseq_stop; sseq++) {
+		struct publication *publ;
+
+		if (sseq->lower > upper)
+			break;
+		publ = sseq->cluster_list;
+		if (publ && (publ->scope <= limit))
+			do {
+				if (publ->node == tipc_own_addr)
+					port_list_add(dports, publ->ref);
+				else
+					res = 1;
+				publ = publ->cluster_list_next;
+			} while (publ != sseq->cluster_list);
+	}
+
+	spin_unlock_bh(&seq->lock);
+exit:
+	read_unlock_bh(&nametbl_lock);
+	return res;
+}
+
+/**
+ * nametbl_publish_rsv - publish port name using a reserved name type
+ */
+
+int nametbl_publish_rsv(u32 ref, unsigned int scope, 
+			struct tipc_name_seq const *seq)
+{
+	int res;
+
+	atomic_inc(&rsv_publ_ok);
+	res = tipc_publish(ref, scope, seq);
+	atomic_dec(&rsv_publ_ok);
+	return res;
+}
+
+/**
+ * nametbl_publish - add name publication to network name tables
+ */
+
+struct publication *nametbl_publish(u32 type, u32 lower, u32 upper, 
+				    u32 scope, u32 port_ref, u32 key)
+{
+	struct publication *publ;
+
+	if (table.local_publ_count >= tipc_max_publications) {
+		warn("Failed publish: max %u local publication\n", 
+		     tipc_max_publications);
+		return 0;
+	}
+	if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
+		warn("Failed to publish reserved name <%u,%u,%u>\n",
+		     type, lower, upper);
+		return 0;
+	}
+
+	write_lock_bh(&nametbl_lock);
+	table.local_publ_count++;
+	publ = nametbl_insert_publ(type, lower, upper, scope,
+				   tipc_own_addr, port_ref, key);
+	if (publ && (scope != TIPC_NODE_SCOPE)) {
+		named_publish(publ);
+	}
+	write_unlock_bh(&nametbl_lock);
+	return publ;
+}
+
+/**
+ * nametbl_withdraw - withdraw name publication from network name tables
+ */
+
+int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
+{
+	struct publication *publ;
+
+	dbg("nametbl_withdraw:<%d,%d,%d>\n", type, lower, key);
+	write_lock_bh(&nametbl_lock);
+	publ = nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
+	if (publ) {
+		table.local_publ_count--;
+		if (publ->scope != TIPC_NODE_SCOPE)
+			named_withdraw(publ);
+		write_unlock_bh(&nametbl_lock);
+		list_del_init(&publ->pport_list);
+		kfree(publ);
+		return 1;
+	}
+	write_unlock_bh(&nametbl_lock);
+	return 0;
+}
+
+/**
+ * nametbl_subscribe - add a subscription object to the name table
+ */
+
+void
+nametbl_subscribe(struct subscription *s)
+{
+	u32 type = s->seq.type;
+	struct name_seq *seq;
+
+        write_lock_bh(&nametbl_lock);
+	seq = nametbl_find_seq(type);
+	if (!seq) {
+		seq = nameseq_create(type, &table.types[hash(type)]);
+	}
+        if (seq){
+                spin_lock_bh(&seq->lock);
+                dbg("nametbl_subscribe:found %x for <%u,%u,%u>\n",
+                    seq, type, s->seq.lower, s->seq.upper);
+                assert(seq->type == type);
+                nameseq_subscribe(seq, s);
+                spin_unlock_bh(&seq->lock);
+        }
+        write_unlock_bh(&nametbl_lock);
+}
+
+/**
+ * nametbl_unsubscribe - remove a subscription object from name table
+ */
+
+void
+nametbl_unsubscribe(struct subscription *s)
+{
+	struct name_seq *seq;
+
+        write_lock_bh(&nametbl_lock);
+        seq = nametbl_find_seq(s->seq.type);
+	if (seq != NULL){
+                spin_lock_bh(&seq->lock);
+                list_del_init(&s->nameseq_list);
+                spin_unlock_bh(&seq->lock);
+                if ((seq->first_free == 0) && list_empty(&seq->subscriptions)) {
+                        hlist_del_init(&seq->ns_list);
+                        kfree(seq->sseqs);
+                        kfree(seq);
+                }
+        }
+        write_unlock_bh(&nametbl_lock);
+}
+
+
+/**
+ * subseq_list: print specified sub-sequence contents into the given buffer
+ */
+
+static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
+			u32 index)
+{
+	char portIdStr[27];
+	char *scopeStr;
+	struct publication *publ = sseq->zone_list;
+
+	tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);
+
+	if (depth == 2 || !publ) {
+		tipc_printf(buf, "\n");
+		return;
+	}
+
+	do {
+		sprintf (portIdStr, "<%u.%u.%u:%u>",
+			 tipc_zone(publ->node), tipc_cluster(publ->node),
+			 tipc_node(publ->node), publ->ref);
+		tipc_printf(buf, "%-26s ", portIdStr);
+		if (depth > 3) {
+			if (publ->node != tipc_own_addr)
+				scopeStr = "";
+			else if (publ->scope == TIPC_NODE_SCOPE)
+				scopeStr = "node";
+			else if (publ->scope == TIPC_CLUSTER_SCOPE)
+				scopeStr = "cluster";
+			else
+				scopeStr = "zone";
+			tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
+		}
+
+		publ = publ->zone_list_next;
+		if (publ == sseq->zone_list)
+			break;
+
+		tipc_printf(buf, "\n%33s", " ");
+	} while (1);
+
+	tipc_printf(buf, "\n");
+}
+
+/**
+ * nameseq_list: print specified name sequence contents into the given buffer
+ */
+
+static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
+			 u32 type, u32 lowbound, u32 upbound, u32 index)
+{
+	struct sub_seq *sseq;
+	char typearea[11];
+
+	sprintf(typearea, "%-10u", seq->type);
+
+	if (depth == 1) {
+		tipc_printf(buf, "%s\n", typearea);
+		return;
+	}
+
+	for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
+		if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
+			tipc_printf(buf, "%s ", typearea);
+			subseq_list(sseq, buf, depth, index);
+			sprintf(typearea, "%10s", " ");
+		}
+	}
+}
+
+/**
+ * nametbl_header - print name table header into the given buffer
+ */
+
+static void nametbl_header(struct print_buf *buf, u32 depth)
+{
+	tipc_printf(buf, "Type       ");
+
+	if (depth > 1)
+		tipc_printf(buf, "Lower      Upper      ");
+	if (depth > 2)
+		tipc_printf(buf, "Port Identity              ");
+	if (depth > 3)
+		tipc_printf(buf, "Publication");
+
+	tipc_printf(buf, "\n-----------");
+
+	if (depth > 1)
+		tipc_printf(buf, "--------------------- ");
+	if (depth > 2)
+		tipc_printf(buf, "-------------------------- ");
+	if (depth > 3)
+		tipc_printf(buf, "------------------");
+
+	tipc_printf(buf, "\n");
+}
+
+/**
+ * nametbl_list - print specified name table contents into the given buffer
+ */
+
+static void nametbl_list(struct print_buf *buf, u32 depth_info, 
+			 u32 type, u32 lowbound, u32 upbound)
+{
+	struct hlist_head *seq_head;
+	struct hlist_node *seq_node;
+	struct name_seq *seq;
+	int all_types;
+	u32 depth;
+	u32 i;
+
+	all_types = (depth_info & TIPC_NTQ_ALLTYPES);
+	depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
+
+	if (depth == 0)
+		return;
+
+	if (all_types) {
+		/* display all entries in name table to specified depth */
+		nametbl_header(buf, depth);
+		lowbound = 0;
+		upbound = ~0;
+		for (i = 0; i < tipc_nametbl_size; i++) {
+			seq_head = &table.types[i];
+			hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
+				nameseq_list(seq, buf, depth, seq->type, 
+					     lowbound, upbound, i);
+			}
+		}
+	} else {
+		/* display only the sequence that matches the specified type */
+		if (upbound < lowbound) {
+			tipc_printf(buf, "invalid name sequence specified\n");
+			return;
+		}
+		nametbl_header(buf, depth);
+		i = hash(type);
+		seq_head = &table.types[i];
+		hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
+			if (seq->type == type) {
+				nameseq_list(seq, buf, depth, type, 
+					     lowbound, upbound, i);
+				break;
+			}
+		}
+	}
+}
+
+void nametbl_print(struct print_buf *buf, const char *str)
+{
+	tipc_printf(buf, str);
+	read_lock_bh(&nametbl_lock);
+	nametbl_list(buf, 0, 0, 0, 0);
+	read_unlock_bh(&nametbl_lock);
+}
+
+#define MAX_NAME_TBL_QUERY 32768
+
+struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space)
+{
+	struct sk_buff *buf;
+	struct tipc_name_table_query *argv;
+	struct tlv_desc *rep_tlv;
+	struct print_buf b;
+	int str_len;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	buf = cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY));
+	if (!buf)
+		return NULL;
+
+	rep_tlv = (struct tlv_desc *)buf->data;
+	printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY);
+	argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
+	read_lock_bh(&nametbl_lock);
+	nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type), 
+		     ntohl(argv->lowbound), ntohl(argv->upbound));
+	read_unlock_bh(&nametbl_lock);
+	str_len = printbuf_validate(&b);
+
+	skb_put(buf, TLV_SPACE(str_len));
+	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+	return buf;
+}
+
+void nametbl_dump(void)
+{
+	nametbl_list(CONS, 0, 0, 0, 0);
+}
+
+int nametbl_init(void)
+{
+	int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
+
+	table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC);
+	if (!table.types)
+		return -ENOMEM;
+
+	write_lock_bh(&nametbl_lock);
+	memset(table.types, 0, array_size);
+	table.local_publ_count = 0;
+	write_unlock_bh(&nametbl_lock);
+	return 0;
+}
+
+void nametbl_stop(void)
+{
+	struct hlist_head *seq_head;
+	struct hlist_node *seq_node;
+	struct hlist_node *tmp;
+	struct name_seq *seq;
+	u32 i;
+
+	if (!table.types)
+		return;
+
+	write_lock_bh(&nametbl_lock);
+	for (i = 0; i < tipc_nametbl_size; i++) {
+		seq_head = &table.types[i];
+		hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) {
+			struct sub_seq *sseq = seq->sseqs;
+
+			for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
+				struct publication *publ = sseq->zone_list;
+				assert(publ);
+				do {
+					struct publication *next =
+						publ->zone_list_next;
+					kfree(publ);
+					publ = next;
+				}
+				while (publ != sseq->zone_list);
+			}
+		}
+	}
+	kfree(table.types);
+	table.types = NULL;
+	write_unlock_bh(&nametbl_lock);
+}
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
new file mode 100644
index 0000000..f826933
--- /dev/null
+++ b/net/tipc/name_table.h
@@ -0,0 +1,108 @@
+/*
+ * net/tipc/name_table.h: Include file for TIPC name table code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NAME_TABLE_H
+#define _TIPC_NAME_TABLE_H
+
+#include "node_subscr.h"
+
+struct subscription;
+struct port_list;
+
+/*
+ * TIPC name types reserved for internal TIPC use (both current and planned)
+ */
+
+#define TIPC_ZM_SRV 3  		/* zone master service name type */
+
+
+/**
+ * struct publication - info about a published (name or) name sequence
+ * @type: name sequence type
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @scope: scope of publication
+ * @node: network address of publishing port's node
+ * @ref: publishing port
+ * @key: publication key
+ * @subscr: subscription to "node down" event (for off-node publications only)
+ * @local_list: adjacent entries in list of publications made by this node
+ * @pport_list: adjacent entries in list of publications made by this port
+ * @node_list: next matching name seq publication with >= node scope
+ * @cluster_list: next matching name seq publication with >= cluster scope
+ * @zone_list: next matching name seq publication with >= zone scope
+ * 
+ * Note that the node list, cluster list, and zone list are circular lists.
+ */
+
+struct publication {
+	u32 type;
+	u32 lower;
+	u32 upper;
+	u32 scope;
+	u32 node;
+	u32 ref;
+	u32 key;
+	struct node_subscr subscr;
+	struct list_head local_list;
+	struct list_head pport_list;
+	struct publication *node_list_next;
+	struct publication *cluster_list_next;
+	struct publication *zone_list_next;
+};
+
+
+extern rwlock_t nametbl_lock;
+
+struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space);
+u32 nametbl_translate(u32 type, u32 instance, u32 *node);
+int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, 
+			 struct port_list *dports);
+int nametbl_publish_rsv(u32 ref, unsigned int scope, 
+			struct tipc_name_seq const *seq);
+struct publication *nametbl_publish(u32 type, u32 lower, u32 upper,
+				    u32 scope, u32 port_ref, u32 key);
+int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key);
+struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
+					u32 scope, u32 node, u32 ref, u32 key);
+struct publication *nametbl_remove_publ(u32 type, u32 lower, 
+					u32 node, u32 ref, u32 key);
+void nametbl_subscribe(struct subscription *s);
+void nametbl_unsubscribe(struct subscription *s);
+int nametbl_init(void);
+void nametbl_stop(void);
+
+#endif
diff --git a/net/tipc/net.c b/net/tipc/net.c
new file mode 100644
index 0000000..6826b49
--- /dev/null
+++ b/net/tipc/net.c
@@ -0,0 +1,311 @@
+/*
+ * net/tipc/net.c: TIPC network routing code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "bearer.h"
+#include "net.h"
+#include "zone.h"
+#include "addr.h"
+#include "name_table.h"
+#include "name_distr.h"
+#include "subscr.h"
+#include "link.h"
+#include "msg.h"
+#include "port.h"
+#include "bcast.h"
+#include "discover.h"
+#include "config.h"
+
+/* 
+ * The TIPC locking policy is designed to ensure a very fine locking
+ * granularity, permitting complete parallel access to individual
+ * port and node/link instances. The code consists of three major 
+ * locking domains, each protected with their own disjunct set of locks.
+ *
+ * 1: The routing hierarchy.
+ *    Comprises the structures 'zone', 'cluster', 'node', 'link' 
+ *    and 'bearer'. The whole hierarchy is protected by a big 
+ *    read/write lock, net_lock, to enssure that nothing is added 
+ *    or removed while code is accessing any of these structures. 
+ *    This layer must not be called from the two others while they 
+ *    hold any of their own locks.
+ *    Neither must it itself do any upcalls to the other two before
+ *    it has released net_lock and other protective locks.
+ *
+ *   Within the net_lock domain there are two sub-domains;'node' and 
+ *   'bearer', where local write operations are permitted,
+ *   provided that those are protected by individual spin_locks
+ *   per instance. Code holding net_lock(read) and a node spin_lock 
+ *   is permitted to poke around in both the node itself and its
+ *   subordinate links. I.e, it can update link counters and queues, 
+ *   change link state, send protocol messages, and alter the 
+ *   "active_links" array in the node; but it can _not_ remove a link 
+ *   or a node from the overall structure.
+ *   Correspondingly, individual bearers may change status within a 
+ *   net_lock(read), protected by an individual spin_lock ber bearer 
+ *   instance, but it needs net_lock(write) to remove/add any bearers.
+ *     
+ *
+ *  2: The transport level of the protocol. 
+ *     This consists of the structures port, (and its user level 
+ *     representations, such as user_port and tipc_sock), reference and 
+ *     tipc_user (port.c, reg.c, socket.c). 
+ *
+ *     This layer has four different locks:
+ *     - The tipc_port spin_lock. This is protecting each port instance
+ *       from parallel data access and removal. Since we can not place 
+ *       this lock in the port itself, it has been placed in the 
+ *       corresponding reference table entry, which has the same life
+ *       cycle as the module. This entry is difficult to access from 
+ *       outside the TIPC core, however, so a pointer to the lock has 
+ *       been added in the port instance, -to be used for unlocking 
+ *       only.
+ *     - A read/write lock to protect the reference table itself (teg.c). 
+ *       (Nobody is using read-only access to this, so it can just as 
+ *       well be changed to a spin_lock)
+ *     - A spin lock to protect the registry of kernel/driver users (reg.c)
+ *     - A global spin_lock (port_lock), which only task is to ensure 
+ *       consistency where more than one port is involved in an operation,
+ *       i.e., whe a port is part of a linked list of ports.
+ *       There are two such lists; 'port_list', which is used for management,
+ *       and 'wait_list', which is used to queue ports during congestion.
+ *     
+ *  3: The name table (name_table.c, name_distr.c, subscription.c)
+ *     - There is one big read/write-lock (nametbl_lock) protecting the 
+ *       overall name table structure. Nothing must be added/removed to 
+ *       this structure without holding write access to it.
+ *     - There is one local spin_lock per sub_sequence, which can be seen
+ *       as a sub-domain to the nametbl_lock domain. It is used only
+ *       for translation operations, and is needed because a translation
+ *       steps the root of the 'publication' linked list between each lookup.
+ *       This is always used within the scope of a nametbl_lock(read).
+ *     - A local spin_lock protecting the queue of subscriber events.
+*/
+
+rwlock_t net_lock = RW_LOCK_UNLOCKED;
+struct network net = { 0 };
+
+struct node *net_select_remote_node(u32 addr, u32 ref) 
+{
+	return zone_select_remote_node(net.zones[tipc_zone(addr)], addr, ref);
+}
+
+u32 net_select_router(u32 addr, u32 ref)
+{
+	return zone_select_router(net.zones[tipc_zone(addr)], addr, ref);
+}
+
+
+u32 net_next_node(u32 a)
+{
+	if (net.zones[tipc_zone(a)])
+		return zone_next_node(a);
+	return 0;
+}
+
+void net_remove_as_router(u32 router)
+{
+	u32 z_num;
+
+	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+		if (!net.zones[z_num])
+			continue;
+		zone_remove_as_router(net.zones[z_num], router);
+	}
+}
+
+void net_send_external_routes(u32 dest)
+{
+	u32 z_num;
+
+	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+		if (net.zones[z_num])
+			zone_send_external_routes(net.zones[z_num], dest);
+	}
+}
+
+int net_init(void)
+{
+	u32 sz = sizeof(struct _zone *) * (tipc_max_zones + 1);
+
+	memset(&net, 0, sizeof(net));
+	net.zones = (struct _zone **)kmalloc(sz, GFP_ATOMIC);
+	if (!net.zones) {
+		return -ENOMEM;
+	}
+	memset(net.zones, 0, sz);
+	return TIPC_OK;
+}
+
+void net_stop(void)
+{
+	u32 z_num;
+
+	if (!net.zones)
+		return;
+
+	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+		zone_delete(net.zones[z_num]);
+	}
+	kfree(net.zones);
+	net.zones = 0;
+}
+
+static void net_route_named_msg(struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	u32 dnode;
+	u32 dport;
+
+	if (!msg_named(msg)) {
+		msg_dbg(msg, "net->drop_nam:");
+		buf_discard(buf);
+		return;
+	}
+
+	dnode = addr_domain(msg_lookup_scope(msg));
+	dport = nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode);
+	dbg("net->lookup<%u,%u>-><%u,%x>\n",
+	    msg_nametype(msg), msg_nameinst(msg), dport, dnode);
+	if (dport) {
+		msg_set_destnode(msg, dnode);
+		msg_set_destport(msg, dport);
+		net_route_msg(buf);
+		return;
+	}
+	msg_dbg(msg, "net->rej:NO NAME: ");
+	tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
+}
+
+void net_route_msg(struct sk_buff *buf)
+{
+	struct tipc_msg *msg;
+	u32 dnode;
+
+	if (!buf)
+		return;
+	msg = buf_msg(buf);
+
+	msg_incr_reroute_cnt(msg);
+	if (msg_reroute_cnt(msg) > 6) {
+		if (msg_errcode(msg)) {
+			msg_dbg(msg, "NET>DISC>:");
+			buf_discard(buf);
+		} else {
+			msg_dbg(msg, "NET>REJ>:");
+			tipc_reject_msg(buf, msg_destport(msg) ? 
+					TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
+		}
+		return;
+	}
+
+	msg_dbg(msg, "net->rout: ");
+
+	/* Handle message for this node */
+	dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
+	if (in_scope(dnode, tipc_own_addr)) {
+		if (msg_isdata(msg)) {
+			if (msg_mcast(msg)) 
+				port_recv_mcast(buf, NULL);
+			else if (msg_destport(msg))
+				port_recv_msg(buf);
+			else
+				net_route_named_msg(buf);
+			return;
+		}
+		switch (msg_user(msg)) {
+		case ROUTE_DISTRIBUTOR:
+			cluster_recv_routing_table(buf);
+			break;
+		case NAME_DISTRIBUTOR:
+			named_recv(buf);
+			break;
+		case CONN_MANAGER:
+			port_recv_proto_msg(buf);
+			break;
+		default:
+			msg_dbg(msg,"DROP/NET/<REC<");
+			buf_discard(buf);
+		}
+		return;
+	}
+
+	/* Handle message for another node */
+	msg_dbg(msg, "NET>SEND>: ");
+	link_send(buf, dnode, msg_link_selector(msg));
+}
+
+int tipc_start_net(void)
+{
+	char addr_string[16];
+	int res;
+
+	if (tipc_mode != TIPC_NODE_MODE)
+		return -ENOPROTOOPT;
+
+	tipc_mode = TIPC_NET_MODE;
+	named_reinit();
+	port_reinit();
+
+	if ((res = bearer_init()) ||
+	    (res = net_init()) ||
+	    (res = cluster_init()) ||
+	    (res = bclink_init())) {
+		return res;
+	}
+        subscr_stop();
+	cfg_stop();
+	k_signal((Handler)subscr_start, 0);
+	k_signal((Handler)cfg_init, 0);
+	info("Started in network mode\n");
+	info("Own node address %s, network identity %u\n",
+	     addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
+	return TIPC_OK;
+}
+
+void tipc_stop_net(void)
+{
+	if (tipc_mode != TIPC_NET_MODE)
+		return;
+        write_lock_bh(&net_lock);
+	bearer_stop();
+	tipc_mode = TIPC_NODE_MODE;
+	bclink_stop();
+	net_stop();
+        write_unlock_bh(&net_lock);
+	info("Left network mode \n");
+}
+
diff --git a/net/tipc/net.h b/net/tipc/net.h
new file mode 100644
index 0000000..948c6d42
--- /dev/null
+++ b/net/tipc/net.h
@@ -0,0 +1,66 @@
+/*
+ * net/tipc/net.h: Include file for TIPC network routing code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NET_H
+#define _TIPC_NET_H
+
+struct _zone;
+
+/**
+ * struct network - TIPC network structure
+ * @zones: array of pointers to all zones within network
+ */
+ 
+struct network {
+	struct _zone **zones;
+};
+
+
+extern struct network net;
+extern rwlock_t net_lock;
+
+int net_init(void);
+void net_stop(void);
+void net_remove_as_router(u32 router);
+void net_send_external_routes(u32 dest);
+void net_route_msg(struct sk_buff *buf);
+struct node *net_select_remote_node(u32 addr, u32 ref);
+u32 net_select_router(u32 addr, u32 ref);
+
+int tipc_start_net(void);
+void tipc_stop_net(void);
+
+#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
new file mode 100644
index 0000000..19b3f40
--- /dev/null
+++ b/net/tipc/netlink.c
@@ -0,0 +1,112 @@
+/*
+ * net/tipc/netlink.c: TIPC configuration handling
+ * 
+ * Copyright (c) 2005-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include <net/genetlink.h>
+
+static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *rep_buf;
+	struct nlmsghdr *rep_nlh;
+	struct nlmsghdr *req_nlh = info->nlhdr;
+	struct tipc_genlmsghdr *req_userhdr = info->userhdr;
+	int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+
+	if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
+		rep_buf = cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+	else
+		rep_buf = cfg_do_cmd(req_userhdr->dest,
+				     req_userhdr->cmd,
+				     NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+				     NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+				     hdr_space);
+
+	if (rep_buf) {
+		skb_push(rep_buf, hdr_space);
+		rep_nlh = (struct nlmsghdr *)rep_buf->data;
+		memcpy(rep_nlh, req_nlh, hdr_space);
+		rep_nlh->nlmsg_len = rep_buf->len;
+		genlmsg_unicast(rep_buf, req_nlh->nlmsg_pid);
+	}
+
+        return 0;
+}
+
+static struct genl_family family = {
+        .id		= GENL_ID_GENERATE,
+        .name		= TIPC_GENL_NAME,
+        .version	= TIPC_GENL_VERSION,
+        .hdrsize	= TIPC_GENL_HDRLEN,
+        .maxattr	= 0,
+};
+
+static struct genl_ops ops = {
+	.cmd		= TIPC_GENL_CMD,
+	.doit		= handle_cmd,
+};
+
+static int family_registered = 0;
+
+int netlink_start(void)
+{
+
+
+	if (genl_register_family(&family))
+		goto err;
+
+	family_registered = 1;
+
+	if (genl_register_ops(&family, &ops))
+		goto err_unregister;
+
+        return 0;
+
+ err_unregister:
+	genl_unregister_family(&family);
+	family_registered = 0;
+ err:
+	err("Failed to register netlink interface\n");
+	return -EFAULT;
+}
+
+void netlink_stop(void)
+{
+	if (family_registered) {
+		genl_unregister_family(&family);
+		family_registered = 0;
+	}
+}
diff --git a/net/tipc/node.c b/net/tipc/node.c
new file mode 100644
index 0000000..05688d0
--- /dev/null
+++ b/net/tipc/node.c
@@ -0,0 +1,679 @@
+/*
+ * net/tipc/node.c: TIPC node management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "node.h"
+#include "cluster.h"
+#include "net.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "link.h"
+#include "port.h"
+#include "bearer.h"
+#include "name_distr.h"
+#include "net.h"
+
+void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
+static void node_lost_contact(struct node *n_ptr);
+static void node_established_contact(struct node *n_ptr);
+
+struct node *nodes = NULL;	/* sorted list of nodes within cluster */
+
+u32 tipc_own_tag = 0;
+
+struct node *node_create(u32 addr)
+{
+	struct cluster *c_ptr;
+	struct node *n_ptr;
+        struct node **curr_node;
+
+	n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
+        if (n_ptr != NULL) {
+                memset(n_ptr, 0, sizeof(*n_ptr));
+                n_ptr->addr = addr;
+                n_ptr->lock =  SPIN_LOCK_UNLOCKED;	
+                INIT_LIST_HEAD(&n_ptr->nsub);
+	
+		c_ptr = cluster_find(addr);
+                if (c_ptr == NULL)
+                        c_ptr = cluster_create(addr);
+                if (c_ptr != NULL) {
+                        n_ptr->owner = c_ptr;
+                        cluster_attach_node(c_ptr, n_ptr);
+                        n_ptr->last_router = -1;
+
+                        /* Insert node into ordered list */
+                        for (curr_node = &nodes; *curr_node; 
+			     curr_node = &(*curr_node)->next) {
+                                if (addr < (*curr_node)->addr) {
+                                        n_ptr->next = *curr_node;
+                                        break;
+                                }
+                        }
+                        (*curr_node) = n_ptr;
+                } else {
+                        kfree(n_ptr);
+                        n_ptr = NULL;
+                }
+        }
+	return n_ptr;
+}
+
+void node_delete(struct node *n_ptr)
+{
+	if (!n_ptr)
+		return;
+
+#if 0
+	/* Not needed because links are already deleted via bearer_stop() */
+
+	u32 l_num;
+
+	for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
+		link_delete(n_ptr->links[l_num]);
+	}
+#endif
+
+	dbg("node %x deleted\n", n_ptr->addr);
+	kfree(n_ptr);
+}
+
+
+/**
+ * node_link_up - handle addition of link
+ * 
+ * Link becomes active (alone or shared) or standby, depending on its priority.
+ */
+
+void node_link_up(struct node *n_ptr, struct link *l_ptr)
+{
+	struct link **active = &n_ptr->active_links[0];
+
+	info("Established link <%s> on network plane %c\n",
+	     l_ptr->name, l_ptr->b_ptr->net_plane);
+	
+	if (!active[0]) {
+		dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]);
+		active[0] = active[1] = l_ptr;
+		node_established_contact(n_ptr);
+		return;
+	}
+	if (l_ptr->priority < active[0]->priority) { 
+		info("Link is standby\n");
+		return;
+	}
+	link_send_duplicate(active[0], l_ptr);
+	if (l_ptr->priority == active[0]->priority) { 
+		active[0] = l_ptr;
+		return;
+	}
+	info("Link <%s> on network plane %c becomes standby\n",
+	     active[0]->name, active[0]->b_ptr->net_plane);
+	active[0] = active[1] = l_ptr;
+}
+
+/**
+ * node_select_active_links - select active link
+ */
+
+static void node_select_active_links(struct node *n_ptr)
+{
+	struct link **active = &n_ptr->active_links[0];
+	u32 i;
+	u32 highest_prio = 0;
+
+        active[0] = active[1] = 0;
+
+	for (i = 0; i < MAX_BEARERS; i++) {
+                struct link *l_ptr = n_ptr->links[i];
+
+		if (!l_ptr || !link_is_up(l_ptr) ||
+		    (l_ptr->priority < highest_prio))
+			continue;
+
+		if (l_ptr->priority > highest_prio) {
+                        highest_prio = l_ptr->priority;
+			active[0] = active[1] = l_ptr;
+		} else {
+			active[1] = l_ptr;
+		}
+	}
+}
+
+/**
+ * node_link_down - handle loss of link
+ */
+
+void node_link_down(struct node *n_ptr, struct link *l_ptr)
+{
+	struct link **active;
+
+	if (!link_is_active(l_ptr)) {
+		info("Lost standby link <%s> on network plane %c\n",
+		     l_ptr->name, l_ptr->b_ptr->net_plane);
+		return;
+	}
+	info("Lost link <%s> on network plane %c\n",
+		l_ptr->name, l_ptr->b_ptr->net_plane);
+
+	active = &n_ptr->active_links[0];
+	if (active[0] == l_ptr)
+		active[0] = active[1];
+	if (active[1] == l_ptr)
+		active[1] = active[0];
+	if (active[0] == l_ptr)
+		node_select_active_links(n_ptr);
+	if (node_is_up(n_ptr)) 
+		link_changeover(l_ptr);
+	else 
+		node_lost_contact(n_ptr);
+}
+
+int node_has_active_links(struct node *n_ptr)
+{
+	return (n_ptr && 
+		((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
+}
+
+int node_has_redundant_links(struct node *n_ptr)
+{
+	return (node_has_active_links(n_ptr) &&
+		(n_ptr->active_links[0] != n_ptr->active_links[1]));
+}
+
+int node_has_active_routes(struct node *n_ptr)
+{
+	return (n_ptr && (n_ptr->last_router >= 0));
+}
+
+int node_is_up(struct node *n_ptr)
+{
+	return (node_has_active_links(n_ptr) || node_has_active_routes(n_ptr));
+}
+
+struct node *node_attach_link(struct link *l_ptr)
+{
+	struct node *n_ptr = node_find(l_ptr->addr);
+
+	if (!n_ptr)
+		n_ptr = node_create(l_ptr->addr);
+        if (n_ptr) {
+		u32 bearer_id = l_ptr->b_ptr->identity;
+		char addr_string[16];
+
+                assert(bearer_id < MAX_BEARERS);
+                if (n_ptr->link_cnt >= 2) {
+			char addr_string[16];
+
+                        err("Attempt to create third link to %s\n",
+			    addr_string_fill(addr_string, n_ptr->addr));
+                        return 0;
+                }
+
+                if (!n_ptr->links[bearer_id]) {
+                        n_ptr->links[bearer_id] = l_ptr;
+                        net.zones[tipc_zone(l_ptr->addr)]->links++;
+                        n_ptr->link_cnt++;
+                        return n_ptr;
+                }
+                err("Attempt to establish second link on <%s> to <%s> \n",
+                    l_ptr->b_ptr->publ.name, 
+		    addr_string_fill(addr_string, l_ptr->addr));
+        }
+	return 0;
+}
+
+void node_detach_link(struct node *n_ptr, struct link *l_ptr)
+{
+	n_ptr->links[l_ptr->b_ptr->identity] = 0;
+	net.zones[tipc_zone(l_ptr->addr)]->links--;
+	n_ptr->link_cnt--;
+}
+
+/*
+ * Routing table management - five cases to handle:
+ *
+ * 1: A link towards a zone/cluster external node comes up.
+ *    => Send a multicast message updating routing tables of all 
+ *    system nodes within own cluster that the new destination 
+ *    can be reached via this node. 
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *
+ * 2: A link towards a slave node comes up.
+ *    => Send a multicast message updating routing tables of all 
+ *    system nodes within own cluster that the new destination 
+ *    can be reached via this node. 
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *    => Send a  message to the slave node about existence 
+ *    of all system nodes within cluster:
+ *    (node.establishedContact()=>cluster.sendLocalRoutes())
+ *
+ * 3: A new cluster local system node becomes available.
+ *    => Send message(s) to this particular node containing
+ *    information about all cluster external and slave
+ *     nodes which can be reached via this node.
+ *    (node.establishedContact()==>network.sendExternalRoutes())
+ *    (node.establishedContact()==>network.sendSlaveRoutes())
+ *    => Send messages to all directly connected slave nodes 
+ *    containing information about the existence of the new node
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *    
+ * 4: The link towards a zone/cluster external node or slave
+ *    node goes down.
+ *    => Send a multcast message updating routing tables of all 
+ *    nodes within cluster that the new destination can not any
+ *    longer be reached via this node.
+ *    (node.lostAllLinks()=>cluster.bcastLostRoute())
+ *
+ * 5: A cluster local system node becomes unavailable.
+ *    => Remove all references to this node from the local
+ *    routing tables. Note: This is a completely node
+ *    local operation.
+ *    (node.lostAllLinks()=>network.removeAsRouter())
+ *    => Send messages to all directly connected slave nodes 
+ *    containing information about loss of the node
+ *    (node.establishedContact()=>cluster.multicastLostRoute())
+ *
+ */
+
+static void node_established_contact(struct node *n_ptr)
+{
+	struct cluster *c_ptr;
+
+	dbg("node_established_contact:-> %x\n", n_ptr->addr);
+	if (!node_has_active_routes(n_ptr)) { 
+		k_signal((Handler)named_node_up, n_ptr->addr);
+	}
+
+        /* Syncronize broadcast acks */
+        n_ptr->bclink.acked = bclink_get_last_sent();
+
+	if (is_slave(tipc_own_addr))
+		return;
+	if (!in_own_cluster(n_ptr->addr)) {
+		/* Usage case 1 (see above) */
+		c_ptr = cluster_find(tipc_own_addr);
+		if (!c_ptr)
+			c_ptr = cluster_create(tipc_own_addr);
+                if (c_ptr)
+                        cluster_bcast_new_route(c_ptr, n_ptr->addr, 1, 
+						tipc_max_nodes);
+		return;
+	} 
+
+	c_ptr = n_ptr->owner;
+	if (is_slave(n_ptr->addr)) {
+		/* Usage case 2 (see above) */
+		cluster_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes);
+		cluster_send_local_routes(c_ptr, n_ptr->addr);
+		return;
+	}
+
+	if (n_ptr->bclink.supported) {
+		nmap_add(&cluster_bcast_nodes, n_ptr->addr);
+		if (n_ptr->addr < tipc_own_addr)
+			tipc_own_tag++;
+	}
+
+	/* Case 3 (see above) */
+	net_send_external_routes(n_ptr->addr);
+	cluster_send_slave_routes(c_ptr, n_ptr->addr);
+	cluster_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE,
+				highest_allowed_slave);
+}
+
+static void node_lost_contact(struct node *n_ptr)
+{
+	struct cluster *c_ptr;
+	struct node_subscr *ns, *tns;
+	char addr_string[16];
+	u32 i;
+
+        /* Clean up broadcast reception remains */
+        n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
+        while (n_ptr->bclink.deferred_head) {
+                struct sk_buff* buf = n_ptr->bclink.deferred_head;
+                n_ptr->bclink.deferred_head = buf->next;
+                buf_discard(buf);
+        }
+        if (n_ptr->bclink.defragm) {
+                buf_discard(n_ptr->bclink.defragm);  
+                n_ptr->bclink.defragm = NULL;
+        }            
+        if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) { 
+                bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
+        }
+
+        /* Update routing tables */
+	if (is_slave(tipc_own_addr)) {
+		net_remove_as_router(n_ptr->addr);
+	} else {
+		if (!in_own_cluster(n_ptr->addr)) { 
+			/* Case 4 (see above) */
+			c_ptr = cluster_find(tipc_own_addr);
+			cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
+						 tipc_max_nodes);
+		} else {
+			/* Case 5 (see above) */
+			c_ptr = cluster_find(n_ptr->addr);
+			if (is_slave(n_ptr->addr)) {
+				cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
+							 tipc_max_nodes);
+			} else {
+				if (n_ptr->bclink.supported) {
+					nmap_remove(&cluster_bcast_nodes, 
+						    n_ptr->addr);
+					if (n_ptr->addr < tipc_own_addr)
+						tipc_own_tag--;
+				}
+				net_remove_as_router(n_ptr->addr);
+				cluster_bcast_lost_route(c_ptr, n_ptr->addr,
+							 LOWEST_SLAVE,
+							 highest_allowed_slave);
+			}
+		}
+	}
+	if (node_has_active_routes(n_ptr))
+		return;
+
+	info("Lost contact with %s\n", 
+	     addr_string_fill(addr_string, n_ptr->addr));
+
+	/* Abort link changeover */
+	for (i = 0; i < MAX_BEARERS; i++) {
+		struct link *l_ptr = n_ptr->links[i];
+		if (!l_ptr) 
+			continue;
+		l_ptr->reset_checkpoint = l_ptr->next_in_no;
+		l_ptr->exp_msg_count = 0;
+		link_reset_fragments(l_ptr);
+	}
+
+	/* Notify subscribers */
+	list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
+                ns->node = 0;
+		list_del_init(&ns->nodesub_list);
+		k_signal((Handler)ns->handle_node_down,
+			 (unsigned long)ns->usr_handle);
+	}
+}
+
+/**
+ * node_select_next_hop - find the next-hop node for a message
+ * 
+ * Called by when cluster local lookup has failed.
+ */
+
+struct node *node_select_next_hop(u32 addr, u32 selector)
+{
+	struct node *n_ptr;
+	u32 router_addr;
+
+        if (!addr_domain_valid(addr))
+                return 0;
+
+	/* Look for direct link to destination processsor */
+	n_ptr = node_find(addr);
+	if (n_ptr && node_has_active_links(n_ptr))
+                return n_ptr;
+
+	/* Cluster local system nodes *must* have direct links */
+	if (!is_slave(addr) && in_own_cluster(addr))
+		return 0;
+
+	/* Look for cluster local router with direct link to node */
+	router_addr = node_select_router(n_ptr, selector);
+	if (router_addr) 
+                return node_select(router_addr, selector);
+
+	/* Slave nodes can only be accessed within own cluster via a 
+	   known router with direct link -- if no router was found,give up */
+	if (is_slave(addr))
+		return 0;
+
+	/* Inter zone/cluster -- find any direct link to remote cluster */
+	addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
+	n_ptr = net_select_remote_node(addr, selector);
+	if (n_ptr && node_has_active_links(n_ptr))
+                return n_ptr;
+
+	/* Last resort -- look for any router to anywhere in remote zone */
+	router_addr =  net_select_router(addr, selector);
+	if (router_addr) 
+                return node_select(router_addr, selector);
+
+        return 0;
+}
+
+/**
+ * node_select_router - select router to reach specified node
+ * 
+ * Uses a deterministic and fair algorithm for selecting router node. 
+ */
+
+u32 node_select_router(struct node *n_ptr, u32 ref)
+{
+	u32 ulim;
+	u32 mask;
+	u32 start;
+	u32 r;
+
+        if (!n_ptr)
+                return 0;
+
+	if (n_ptr->last_router < 0)
+		return 0;
+	ulim = ((n_ptr->last_router + 1) * 32) - 1;
+
+	/* Start entry must be random */
+	mask = tipc_max_nodes;
+	while (mask > ulim)
+		mask >>= 1;
+	start = ref & mask;
+	r = start;
+
+	/* Lookup upwards with wrap-around */
+	do {
+		if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
+			break;
+	} while (++r <= ulim);
+	if (r > ulim) {
+		r = 1;
+		do {
+			if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
+				break;
+		} while (++r < start);
+		assert(r != start);
+	}
+	assert(r && (r <= ulim));
+	return tipc_addr(own_zone(), own_cluster(), r);
+}
+
+void node_add_router(struct node *n_ptr, u32 router)
+{
+	u32 r_num = tipc_node(router);
+
+	n_ptr->routers[r_num / 32] = 
+		((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
+	n_ptr->last_router = tipc_max_nodes / 32;
+	while ((--n_ptr->last_router >= 0) && 
+	       !n_ptr->routers[n_ptr->last_router]);
+}
+
+void node_remove_router(struct node *n_ptr, u32 router)
+{
+	u32 r_num = tipc_node(router);
+
+	if (n_ptr->last_router < 0)
+		return;		/* No routes */
+
+	n_ptr->routers[r_num / 32] =
+		((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32]));
+	n_ptr->last_router = tipc_max_nodes / 32;
+	while ((--n_ptr->last_router >= 0) && 
+	       !n_ptr->routers[n_ptr->last_router]);
+
+	if (!node_is_up(n_ptr))
+		node_lost_contact(n_ptr);
+}
+
+#if 0
+void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
+{
+	u32 i;
+
+	tipc_printf(buf, "\n\n%s", str);
+	for (i = 0; i < MAX_BEARERS; i++) {
+		if (!n_ptr->links[i]) 
+			continue;
+		tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
+	}
+	tipc_printf(buf, "Active links: [%x,%x]\n",
+		    n_ptr->active_links[0], n_ptr->active_links[1]);
+}
+#endif
+
+u32 tipc_available_nodes(const u32 domain)
+{
+	struct node *n_ptr;
+	u32 cnt = 0;
+
+	for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+		if (!in_scope(domain, n_ptr->addr))
+			continue;
+		if (node_is_up(n_ptr))
+			cnt++;
+	}
+	return cnt;
+}
+
+struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space)
+{
+	u32 domain;
+	struct sk_buff *buf;
+	struct node *n_ptr;
+        struct tipc_node_info node_info;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	domain = *(u32 *)TLV_DATA(req_tlv_area);
+	domain = ntohl(domain);
+	if (!addr_domain_valid(domain))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (network address)");
+
+        if (!nodes)
+                return cfg_reply_none();
+
+	/* For now, get space for all other nodes 
+	   (will need to modify this when slave nodes are supported */
+
+	buf = cfg_reply_alloc(TLV_SPACE(sizeof(node_info)) *
+			    (tipc_max_nodes - 1));
+	if (!buf)
+		return NULL;
+
+	/* Add TLVs for all nodes in scope */
+
+	for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+		if (!in_scope(domain, n_ptr->addr))
+			continue;
+                node_info.addr = htonl(n_ptr->addr);
+                node_info.up = htonl(node_is_up(n_ptr));
+		cfg_append_tlv(buf, TIPC_TLV_NODE_INFO, 
+			       &node_info, sizeof(node_info));
+	}
+
+	return buf;
+}
+
+struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space)
+{
+	u32 domain;
+	struct sk_buff *buf;
+	struct node *n_ptr;
+        struct tipc_link_info link_info;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	domain = *(u32 *)TLV_DATA(req_tlv_area);
+	domain = ntohl(domain);
+	if (!addr_domain_valid(domain))
+		return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+					      " (network address)");
+
+        if (!nodes)
+                return cfg_reply_none();
+
+	/* For now, get space for 2 links to all other nodes + bcast link 
+	   (will need to modify this when slave nodes are supported */
+
+	buf = cfg_reply_alloc(TLV_SPACE(sizeof(link_info)) *
+			    (2 * (tipc_max_nodes - 1) + 1));
+	if (!buf)
+		return NULL;
+
+	/* Add TLV for broadcast link */
+
+        link_info.dest = tipc_own_addr & 0xfffff00;
+	link_info.dest = htonl(link_info.dest);
+        link_info.up = htonl(1);
+        sprintf(link_info.str, bc_link_name);
+	cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
+
+	/* Add TLVs for any other links in scope */
+
+	for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+                u32 i;
+
+		if (!in_scope(domain, n_ptr->addr))
+			continue;
+                for (i = 0; i < MAX_BEARERS; i++) {
+                        if (!n_ptr->links[i]) 
+                                continue;
+                        link_info.dest = htonl(n_ptr->addr);
+                        link_info.up = htonl(link_is_up(n_ptr->links[i]));
+                        strcpy(link_info.str, n_ptr->links[i]->name);
+			cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, 
+				       &link_info, sizeof(link_info));
+                }
+	}
+
+	return buf;
+}
diff --git a/net/tipc/node.h b/net/tipc/node.h
new file mode 100644
index 0000000..b39442b
--- /dev/null
+++ b/net/tipc/node.h
@@ -0,0 +1,144 @@
+/*
+ * net/tipc/node.h: Include file for TIPC node management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NODE_H
+#define _TIPC_NODE_H
+
+#include "node_subscr.h"
+#include "addr.h"
+#include "cluster.h"
+#include "bearer.h"
+
+/**
+ * struct node - TIPC node structure
+ * @addr: network address of node
+ * @lock: spinlock governing access to structure
+ * @owner: pointer to cluster that node belongs to
+ * @next: pointer to next node in sorted list of cluster's nodes
+ * @nsub: list of "node down" subscriptions monitoring node
+ * @active_links: pointers to active links to node
+ * @links: pointers to all links to node
+ * @link_cnt: number of links to node
+ * @permit_changeover: non-zero if node has redundant links to this system
+ * @routers: bitmap (used for multicluster communication)
+ * @last_router: (used for multicluster communication)
+ * @bclink: broadcast-related info
+ *    @supported: non-zero if node supports TIPC b'cast capability
+ *    @acked: sequence # of last outbound b'cast message acknowledged by node
+ *    @last_in: sequence # of last in-sequence b'cast message received from node
+ *    @gap_after: sequence # of last message not requiring a NAK request
+ *    @gap_to: sequence # of last message requiring a NAK request
+ *    @nack_sync: counter that determines when NAK requests should be sent
+ *    @deferred_head: oldest OOS b'cast message received from node
+ *    @deferred_tail: newest OOS b'cast message received from node
+ *    @defragm: list of partially reassembled b'cast message fragments from node
+ */
+ 
+struct node {
+	u32 addr;
+	spinlock_t lock;
+	struct cluster *owner;
+	struct node *next;
+	struct list_head nsub;
+	struct link *active_links[2];
+	struct link *links[MAX_BEARERS];
+	int link_cnt;
+	int permit_changeover;
+	u32 routers[512/32];
+	int last_router;
+	struct {
+		int supported;
+		u32 acked;
+		u32 last_in;
+		u32 gap_after; 
+		u32 gap_to; 
+		u32 nack_sync;
+		struct sk_buff *deferred_head;
+		struct sk_buff *deferred_tail;
+		struct sk_buff *defragm;
+	} bclink;
+};
+
+extern struct node *nodes;
+extern u32 tipc_own_tag;
+
+struct node *node_create(u32 addr);
+void node_delete(struct node *n_ptr);
+struct node *node_attach_link(struct link *l_ptr);
+void node_detach_link(struct node *n_ptr, struct link *l_ptr);
+void node_link_down(struct node *n_ptr, struct link *l_ptr);
+void node_link_up(struct node *n_ptr, struct link *l_ptr);
+int node_has_active_links(struct node *n_ptr);
+int node_has_redundant_links(struct node *n_ptr);
+u32 node_select_router(struct node *n_ptr, u32 ref);
+struct node *node_select_next_hop(u32 addr, u32 selector);
+int node_is_up(struct node *n_ptr);
+void node_add_router(struct node *n_ptr, u32 router);
+void node_remove_router(struct node *n_ptr, u32 router);
+struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space);
+
+static inline struct node *node_find(u32 addr)
+{
+	if (likely(in_own_cluster(addr)))
+		return local_nodes[tipc_node(addr)];
+	else if (addr_domain_valid(addr)) {
+		struct cluster *c_ptr = cluster_find(addr);
+
+		if (c_ptr)
+			return c_ptr->nodes[tipc_node(addr)];
+	}
+	return 0;
+}
+
+static inline struct node *node_select(u32 addr, u32 selector)
+{
+	if (likely(in_own_cluster(addr)))
+		return local_nodes[tipc_node(addr)];
+	return node_select_next_hop(addr, selector);
+}
+
+static inline void node_lock(struct node *n_ptr)
+{
+	spin_lock_bh(&n_ptr->lock);
+}
+
+static inline void node_unlock(struct node *n_ptr)
+{
+	spin_unlock_bh(&n_ptr->lock);
+}
+
+#endif
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
new file mode 100644
index 0000000..7937592
--- /dev/null
+++ b/net/tipc/node_subscr.c
@@ -0,0 +1,79 @@
+/*
+ * net/tipc/node_subscr.c: TIPC "node down" subscription handling
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "node_subscr.h"
+#include "node.h"
+#include "addr.h"
+
+/**
+ * nodesub_subscribe - create "node down" subscription for specified node
+ */
+
+void nodesub_subscribe(struct node_subscr *node_sub, u32 addr, 
+		       void *usr_handle, net_ev_handler handle_down)
+{
+	node_sub->node = 0;
+	if (addr == tipc_own_addr)
+		return;
+	if (!addr_node_valid(addr)) {
+		warn("node_subscr with illegal %x\n", addr);
+		return;
+	}
+
+	node_sub->handle_node_down = handle_down;
+	node_sub->usr_handle = usr_handle;
+	node_sub->node = node_find(addr);
+	assert(node_sub->node);
+	node_lock(node_sub->node);
+	list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
+	node_unlock(node_sub->node);
+}
+
+/**
+ * nodesub_unsubscribe - cancel "node down" subscription (if any)
+ */
+
+void nodesub_unsubscribe(struct node_subscr *node_sub)
+{
+	if (!node_sub->node)
+		return;
+
+	node_lock(node_sub->node);
+	list_del_init(&node_sub->nodesub_list);
+	node_unlock(node_sub->node);
+}
diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h
new file mode 100644
index 0000000..a3b87ac
--- /dev/null
+++ b/net/tipc/node_subscr.h
@@ -0,0 +1,63 @@
+/*
+ * net/tipc/node_subscr.h: Include file for TIPC "node down" subscription handling
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NODE_SUBSCR_H
+#define _TIPC_NODE_SUBSCR_H
+
+#include "addr.h"
+
+typedef void (*net_ev_handler) (void *usr_handle);
+
+/**
+ * struct node_subscr - "node down" subscription entry
+ * @node: ptr to node structure of interest (or NULL, if none)
+ * @handle_node_down: routine to invoke when node fails
+ * @usr_handle: argument to pass to routine when node fails
+ * @nodesub_list: adjacent entries in list of subscriptions for the node
+ */
+
+struct node_subscr {
+	struct node *node;
+	net_ev_handler handle_node_down;
+	void *usr_handle;
+	struct list_head nodesub_list;
+};
+
+void nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+		       void *usr_handle, net_ev_handler handle_down);
+void nodesub_unsubscribe(struct node_subscr *node_sub);
+
+#endif
diff --git a/net/tipc/port.c b/net/tipc/port.c
new file mode 100644
index 0000000..66caca7
--- /dev/null
+++ b/net/tipc/port.c
@@ -0,0 +1,1708 @@
+/*
+ * net/tipc/port.c: TIPC port code
+ * 
+ * Copyright (c) 1992-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "port.h"
+#include "addr.h"
+#include "link.h"
+#include "node.h"
+#include "port.h"
+#include "name_table.h"
+#include "user_reg.h"
+#include "msg.h"
+#include "bcast.h"
+
+/* Connection management: */
+#define PROBING_INTERVAL 3600000	/* [ms] => 1 h */
+#define CONFIRMED 0
+#define PROBING 1
+
+#define MAX_REJECT_SIZE 1024
+
+static struct sk_buff *msg_queue_head = 0;
+static struct sk_buff *msg_queue_tail = 0;
+
+spinlock_t port_list_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
+
+LIST_HEAD(ports);
+static void port_handle_node_down(unsigned long ref);
+static struct sk_buff* port_build_self_abort_msg(struct port *,u32 err);
+static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err);
+static void port_timeout(unsigned long ref);
+
+
+static inline u32 port_peernode(struct port *p_ptr)
+{
+	return msg_destnode(&p_ptr->publ.phdr);
+}
+
+static inline u32 port_peerport(struct port *p_ptr)
+{
+	return msg_destport(&p_ptr->publ.phdr);
+}
+
+static inline u32 port_out_seqno(struct port *p_ptr)
+{
+	return msg_transp_seqno(&p_ptr->publ.phdr);
+}
+
+static inline void port_set_out_seqno(struct port *p_ptr, u32 seqno) 
+{
+	msg_set_transp_seqno(&p_ptr->publ.phdr,seqno);
+}
+
+static inline void port_incr_out_seqno(struct port *p_ptr)
+{
+	struct tipc_msg *m = &p_ptr->publ.phdr;
+
+	if (likely(!msg_routed(m)))
+		return;
+	msg_set_transp_seqno(m, (msg_transp_seqno(m) + 1));
+}
+
+/**
+ * tipc_multicast - send a multicast message to local and remote destinations
+ */
+
+int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain,
+		   u32 num_sect, struct iovec const *msg_sect)
+{
+	struct tipc_msg *hdr;
+	struct sk_buff *buf;
+	struct sk_buff *ibuf = NULL;
+	struct port_list dports = {0, NULL, };
+	struct port *oport = port_deref(ref);
+	int ext_targets;
+	int res;
+
+	if (unlikely(!oport))
+		return -EINVAL;
+
+	/* Create multicast message */
+
+	hdr = &oport->publ.phdr;
+	msg_set_type(hdr, TIPC_MCAST_MSG);
+	msg_set_nametype(hdr, seq->type);
+	msg_set_namelower(hdr, seq->lower);
+	msg_set_nameupper(hdr, seq->upper);
+	msg_set_hdr_sz(hdr, MCAST_H_SIZE);
+	res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
+			!oport->user_port, &buf);
+	if (unlikely(!buf))
+		return res;
+
+	/* Figure out where to send multicast message */
+
+	ext_targets = nametbl_mc_translate(seq->type, seq->lower, seq->upper,
+					   TIPC_NODE_SCOPE, &dports);
+	
+	/* Send message to destinations (duplicate it only if necessary) */ 
+
+	if (ext_targets) {
+		if (dports.count != 0) {
+			ibuf = skb_copy(buf, GFP_ATOMIC);
+			if (ibuf == NULL) {
+				port_list_free(&dports);
+				buf_discard(buf);
+				return -ENOMEM;
+			}
+		}
+		res = bclink_send_msg(buf);
+		if ((res < 0) && (dports.count != 0)) {
+			buf_discard(ibuf);
+		}
+	} else {
+		ibuf = buf;
+	}
+
+	if (res >= 0) {
+		if (ibuf)
+			port_recv_mcast(ibuf, &dports);
+	} else {
+		port_list_free(&dports);
+	}
+	return res;
+}
+
+/**
+ * port_recv_mcast - deliver multicast message to all destination ports
+ * 
+ * If there is no port list, perform a lookup to create one
+ */
+
+void port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
+{
+	struct tipc_msg* msg;
+	struct port_list dports = {0, NULL, };
+	struct port_list *item = dp;
+	int cnt = 0;
+
+	assert(buf);
+	msg = buf_msg(buf);
+
+	/* Create destination port list, if one wasn't supplied */
+
+	if (dp == NULL) {
+		nametbl_mc_translate(msg_nametype(msg),
+				     msg_namelower(msg),
+				     msg_nameupper(msg),
+				     TIPC_CLUSTER_SCOPE,
+				     &dports);
+		item = dp = &dports;
+	}
+
+	/* Deliver a copy of message to each destination port */
+
+	if (dp->count != 0) {
+		if (dp->count == 1) {
+			msg_set_destport(msg, dp->ports[0]);
+			port_recv_msg(buf);
+			port_list_free(dp);
+			return;
+		}
+		for (; cnt < dp->count; cnt++) {
+			int index = cnt % PLSIZE;
+			struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
+
+			if (b == NULL) {
+				warn("Buffer allocation failure\n");
+				msg_dbg(msg, "LOST:");
+				goto exit;
+			}
+			if ((index == 0) && (cnt != 0)) {
+				item = item->next;
+			}
+			msg_set_destport(buf_msg(b),item->ports[index]);
+			port_recv_msg(b);
+		}
+	}
+exit:
+	buf_discard(buf);
+	port_list_free(dp);
+}
+
+/**
+ * tipc_createport_raw - create a native TIPC port
+ * 
+ * Returns local port reference
+ */
+
+u32 tipc_createport_raw(void *usr_handle,
+			u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
+			void (*wakeup)(struct tipc_port *),
+			const u32 importance)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	u32 ref;
+
+	p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC);
+	if (p_ptr == NULL) {
+		warn("Memory squeeze; failed to create port\n");
+		return 0;
+	}
+	memset(p_ptr, 0, sizeof(*p_ptr));
+	ref = ref_acquire(p_ptr, &p_ptr->publ.lock);
+	if (!ref) {
+		warn("Reference Table Exhausted\n");
+		kfree(p_ptr);
+		return 0;
+	}
+
+	port_lock(ref);
+	p_ptr->publ.ref = ref;
+	msg = &p_ptr->publ.phdr;
+	msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
+	msg_set_orignode(msg, tipc_own_addr);
+	msg_set_prevnode(msg, tipc_own_addr);
+	msg_set_origport(msg, ref);
+	msg_set_importance(msg,importance);
+	p_ptr->last_in_seqno = 41;
+	p_ptr->sent = 1;
+	p_ptr->publ.usr_handle = usr_handle;
+	INIT_LIST_HEAD(&p_ptr->wait_list);
+	INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
+	p_ptr->congested_link = 0;
+	p_ptr->max_pkt = MAX_PKT_DEFAULT;
+	p_ptr->dispatcher = dispatcher;
+	p_ptr->wakeup = wakeup;
+	p_ptr->user_port = 0;
+	k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
+	spin_lock_bh(&port_list_lock);
+	INIT_LIST_HEAD(&p_ptr->publications);
+	INIT_LIST_HEAD(&p_ptr->port_list);
+	list_add_tail(&p_ptr->port_list, &ports);
+	spin_unlock_bh(&port_list_lock);
+	port_unlock(p_ptr);
+	return ref;
+}
+
+int tipc_deleteport(u32 ref)
+{
+	struct port *p_ptr;
+	struct sk_buff *buf = 0;
+
+	tipc_withdraw(ref, 0, 0);
+	p_ptr = port_lock(ref);
+	if (!p_ptr) 
+		return -EINVAL;
+
+	ref_discard(ref);
+	port_unlock(p_ptr);
+
+	k_cancel_timer(&p_ptr->timer);
+	if (p_ptr->publ.connected) {
+		buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
+		nodesub_unsubscribe(&p_ptr->subscription);
+	}
+	if (p_ptr->user_port) {
+		reg_remove_port(p_ptr->user_port);
+		kfree(p_ptr->user_port);
+	}
+
+	spin_lock_bh(&port_list_lock);
+	list_del(&p_ptr->port_list);
+	list_del(&p_ptr->wait_list);
+	spin_unlock_bh(&port_list_lock);
+	k_term_timer(&p_ptr->timer);
+	kfree(p_ptr);
+	dbg("Deleted port %u\n", ref);
+	net_route_msg(buf);
+	return TIPC_OK;
+}
+
+/**
+ * tipc_get_port() - return port associated with 'ref'
+ * 
+ * Note: Port is not locked.
+ */
+
+struct tipc_port *tipc_get_port(const u32 ref)
+{
+	return (struct tipc_port *)ref_deref(ref);
+}
+
+/**
+ * tipc_get_handle - return user handle associated to port 'ref'
+ */
+
+void *tipc_get_handle(const u32 ref)
+{
+	struct port *p_ptr;
+	void * handle;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return 0;
+	handle = p_ptr->publ.usr_handle;
+	port_unlock(p_ptr);
+	return handle;
+}
+
+static inline int port_unreliable(struct port *p_ptr)
+{
+	return msg_src_droppable(&p_ptr->publ.phdr);
+}
+
+int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	*isunreliable = port_unreliable(p_ptr);
+	spin_unlock_bh(p_ptr->publ.lock);
+	return TIPC_OK;
+}
+
+int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	msg_set_src_droppable(&p_ptr->publ.phdr, (isunreliable != 0));
+	port_unlock(p_ptr);
+	return TIPC_OK;
+}
+
+static inline int port_unreturnable(struct port *p_ptr)
+{
+	return msg_dest_droppable(&p_ptr->publ.phdr);
+}
+
+int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	*isunrejectable = port_unreturnable(p_ptr);
+	spin_unlock_bh(p_ptr->publ.lock);
+	return TIPC_OK;
+}
+
+int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	msg_set_dest_droppable(&p_ptr->publ.phdr, (isunrejectable != 0));
+	port_unlock(p_ptr);
+	return TIPC_OK;
+}
+
+/* 
+ * port_build_proto_msg(): build a port level protocol 
+ * or a connection abortion message. Called with 
+ * tipc_port lock on.
+ */
+static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
+					    u32 origport, u32 orignode,
+					    u32 usr, u32 type, u32 err, 
+					    u32 seqno, u32 ack)
+{
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	
+	buf = buf_acquire(LONG_H_SIZE);
+	if (buf) {
+		msg = buf_msg(buf);
+		msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
+		msg_set_destport(msg, destport);
+		msg_set_origport(msg, origport);
+		msg_set_destnode(msg, destnode);
+		msg_set_orignode(msg, orignode);
+		msg_set_transp_seqno(msg, seqno);
+		msg_set_msgcnt(msg, ack);
+		msg_dbg(msg, "PORT>SEND>:");
+	}
+	return buf;
+}
+
+int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
+{
+	msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
+	msg_set_options(&tp_ptr->phdr, opt, sz);
+	return TIPC_OK;
+}
+
+int tipc_reject_msg(struct sk_buff *buf, u32 err)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	struct sk_buff *rbuf;
+	struct tipc_msg *rmsg;
+	int hdr_sz;
+	u32 imp = msg_importance(msg);
+	u32 data_sz = msg_data_sz(msg);
+
+	if (data_sz > MAX_REJECT_SIZE)
+		data_sz = MAX_REJECT_SIZE;
+	if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE))
+		imp++;
+	msg_dbg(msg, "port->rej: ");
+
+	/* discard rejected message if it shouldn't be returned to sender */
+	if (msg_errcode(msg) || msg_dest_droppable(msg)) {
+		buf_discard(buf);
+		return data_sz;
+	}
+
+	/* construct rejected message */
+	if (msg_mcast(msg))
+		hdr_sz = MCAST_H_SIZE;
+	else
+		hdr_sz = LONG_H_SIZE;
+	rbuf = buf_acquire(data_sz + hdr_sz);
+	if (rbuf == NULL) {
+		buf_discard(buf);
+		return data_sz;
+	}
+	rmsg = buf_msg(rbuf);
+	msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
+	msg_set_destport(rmsg, msg_origport(msg));
+	msg_set_prevnode(rmsg, tipc_own_addr);
+	msg_set_origport(rmsg, msg_destport(msg));
+	if (msg_short(msg))
+		msg_set_orignode(rmsg, tipc_own_addr);
+	else
+		msg_set_orignode(rmsg, msg_destnode(msg));
+	msg_set_size(rmsg, data_sz + hdr_sz); 
+	msg_set_nametype(rmsg, msg_nametype(msg));
+	msg_set_nameinst(rmsg, msg_nameinst(msg));
+	memcpy(rbuf->data + hdr_sz, msg_data(msg), data_sz);
+
+	/* send self-abort message when rejecting on a connected port */
+	if (msg_connected(msg)) {
+		struct sk_buff *abuf = 0;
+		struct port *p_ptr = port_lock(msg_destport(msg));
+
+		if (p_ptr) {
+			if (p_ptr->publ.connected)
+				abuf = port_build_self_abort_msg(p_ptr, err);
+			port_unlock(p_ptr);
+		}
+		net_route_msg(abuf);
+	}
+
+	/* send rejected message */
+	buf_discard(buf);
+	net_route_msg(rbuf);
+	return data_sz;
+}
+
+int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
+			 struct iovec const *msg_sect, u32 num_sect,
+			 int err)
+{
+	struct sk_buff *buf;
+	int res;
+
+	res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, 
+			!p_ptr->user_port, &buf);
+	if (!buf)
+		return res;
+
+	return tipc_reject_msg(buf, err);
+}
+
+static void port_timeout(unsigned long ref)
+{
+	struct port *p_ptr = port_lock(ref);
+	struct sk_buff *buf = 0;
+
+	if (!p_ptr || !p_ptr->publ.connected)
+		return;
+
+	/* Last probe answered ? */
+	if (p_ptr->probing_state == PROBING) {
+		buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
+	} else {
+		buf = port_build_proto_msg(port_peerport(p_ptr),
+					   port_peernode(p_ptr),
+					   p_ptr->publ.ref,
+					   tipc_own_addr,
+					   CONN_MANAGER,
+					   CONN_PROBE,
+					   TIPC_OK, 
+					   port_out_seqno(p_ptr),
+					   0);
+		port_incr_out_seqno(p_ptr);
+		p_ptr->probing_state = PROBING;
+		k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
+	}
+	port_unlock(p_ptr);
+	net_route_msg(buf);
+}
+
+
+static void port_handle_node_down(unsigned long ref)
+{
+	struct port *p_ptr = port_lock(ref);
+	struct sk_buff* buf = 0;
+
+	if (!p_ptr)
+		return;
+	buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
+	port_unlock(p_ptr);
+	net_route_msg(buf);
+}
+
+
+static struct sk_buff *port_build_self_abort_msg(struct port *p_ptr, u32 err)
+{
+	u32 imp = msg_importance(&p_ptr->publ.phdr);
+
+	if (!p_ptr->publ.connected)
+		return 0;
+	if (imp < TIPC_CRITICAL_IMPORTANCE)
+		imp++;
+	return port_build_proto_msg(p_ptr->publ.ref,
+				    tipc_own_addr,
+				    port_peerport(p_ptr),
+				    port_peernode(p_ptr),
+				    imp,
+				    TIPC_CONN_MSG,
+				    err, 
+				    p_ptr->last_in_seqno + 1,
+				    0);
+}
+
+
+static struct sk_buff *port_build_peer_abort_msg(struct port *p_ptr, u32 err)
+{
+	u32 imp = msg_importance(&p_ptr->publ.phdr);
+
+	if (!p_ptr->publ.connected)
+		return 0;
+	if (imp < TIPC_CRITICAL_IMPORTANCE)
+		imp++;
+	return port_build_proto_msg(port_peerport(p_ptr),
+				    port_peernode(p_ptr),
+				    p_ptr->publ.ref,
+				    tipc_own_addr,
+				    imp,
+				    TIPC_CONN_MSG,
+				    err, 
+				    port_out_seqno(p_ptr),
+				    0);
+}
+
+void port_recv_proto_msg(struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	struct port *p_ptr = port_lock(msg_destport(msg));
+	u32 err = TIPC_OK;
+	struct sk_buff *r_buf = 0;
+	struct sk_buff *abort_buf = 0;
+
+	msg_dbg(msg, "PORT<RECV<:");
+
+	if (!p_ptr) {
+		err = TIPC_ERR_NO_PORT;
+	} else if (p_ptr->publ.connected) {
+		if (port_peernode(p_ptr) != msg_orignode(msg))
+			err = TIPC_ERR_NO_PORT;
+		if (port_peerport(p_ptr) != msg_origport(msg))
+			err = TIPC_ERR_NO_PORT;
+		if (!err && msg_routed(msg)) {
+			u32 seqno = msg_transp_seqno(msg);
+			u32 myno =  ++p_ptr->last_in_seqno;
+			if (seqno != myno) {
+				err = TIPC_ERR_NO_PORT;
+				abort_buf = port_build_self_abort_msg(p_ptr, err);
+			}
+		}
+		if (msg_type(msg) == CONN_ACK) {
+			int wakeup = port_congested(p_ptr) && 
+				     p_ptr->publ.congested &&
+				     p_ptr->wakeup;
+			p_ptr->acked += msg_msgcnt(msg);
+			if (port_congested(p_ptr))
+				goto exit;
+			p_ptr->publ.congested = 0;
+			if (!wakeup)
+				goto exit;
+			p_ptr->wakeup(&p_ptr->publ);
+			goto exit;
+		}
+	} else if (p_ptr->publ.published) {
+		err = TIPC_ERR_NO_PORT;
+	}
+	if (err) {
+		r_buf = port_build_proto_msg(msg_origport(msg),
+					     msg_orignode(msg), 
+					     msg_destport(msg), 
+					     tipc_own_addr,
+					     DATA_HIGH,
+					     TIPC_CONN_MSG,
+					     err,
+					     0,
+					     0);
+		goto exit;
+	}
+
+	/* All is fine */
+	if (msg_type(msg) == CONN_PROBE) {
+		r_buf = port_build_proto_msg(msg_origport(msg), 
+					     msg_orignode(msg), 
+					     msg_destport(msg), 
+					     tipc_own_addr, 
+					     CONN_MANAGER,
+					     CONN_PROBE_REPLY,
+					     TIPC_OK,
+					     port_out_seqno(p_ptr),
+					     0);
+	}
+	p_ptr->probing_state = CONFIRMED;
+	port_incr_out_seqno(p_ptr);
+exit:
+	if (p_ptr)
+		port_unlock(p_ptr);
+	net_route_msg(r_buf);
+	net_route_msg(abort_buf);
+	buf_discard(buf);
+}
+
+static void port_print(struct port *p_ptr, struct print_buf *buf, int full_id)
+{
+        struct publication *publ;
+
+	if (full_id)
+		tipc_printf(buf, "<%u.%u.%u:%u>:", 
+			    tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
+                            tipc_node(tipc_own_addr), p_ptr->publ.ref);
+	else
+		tipc_printf(buf, "%-10u:", p_ptr->publ.ref);
+
+        if (p_ptr->publ.connected) {
+                u32 dport = port_peerport(p_ptr);
+                u32 destnode = port_peernode(p_ptr);
+
+                tipc_printf(buf, " connected to <%u.%u.%u:%u>",
+                            tipc_zone(destnode), tipc_cluster(destnode),
+                            tipc_node(destnode), dport);
+                if (p_ptr->publ.conn_type != 0)
+                        tipc_printf(buf, " via {%u,%u}",
+                                    p_ptr->publ.conn_type,
+                                    p_ptr->publ.conn_instance);
+        }
+        else if (p_ptr->publ.published) {
+                tipc_printf(buf, " bound to");
+                list_for_each_entry(publ, &p_ptr->publications, pport_list) {
+			if (publ->lower == publ->upper)
+				tipc_printf(buf, " {%u,%u}", publ->type,
+					    publ->lower);
+			else
+				tipc_printf(buf, " {%u,%u,%u}", publ->type, 
+					    publ->lower, publ->upper);
+                }
+        }
+        tipc_printf(buf, "\n");
+}
+
+#define MAX_PORT_QUERY 32768
+
+struct sk_buff *port_get_ports(void)
+{
+	struct sk_buff *buf;
+	struct tlv_desc *rep_tlv;
+	struct print_buf pb;
+	struct port *p_ptr;
+	int str_len;
+
+	buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
+	if (!buf)
+		return NULL;
+	rep_tlv = (struct tlv_desc *)buf->data;
+
+	printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
+	spin_lock_bh(&port_list_lock);
+	list_for_each_entry(p_ptr, &ports, port_list) {
+		spin_lock_bh(p_ptr->publ.lock);
+		port_print(p_ptr, &pb, 0);
+		spin_unlock_bh(p_ptr->publ.lock);
+	}
+	spin_unlock_bh(&port_list_lock);
+	str_len = printbuf_validate(&pb);
+
+	skb_put(buf, TLV_SPACE(str_len));
+	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+	return buf;
+}
+
+#if 0
+
+#define MAX_PORT_STATS 2000
+
+struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space)
+{
+	u32 ref;
+	struct port *p_ptr;
+	struct sk_buff *buf;
+	struct tlv_desc *rep_tlv;
+	struct print_buf pb;
+	int str_len;
+
+	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_PORT_REF))
+		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+	ref = *(u32 *)TLV_DATA(req_tlv_area);
+	ref = ntohl(ref);
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return cfg_reply_error_string("port not found");
+
+	buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_STATS));
+	if (!buf) {
+		port_unlock(p_ptr);
+		return NULL;
+	}
+	rep_tlv = (struct tlv_desc *)buf->data;
+
+	printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_STATS);
+	port_print(p_ptr, &pb, 1);
+	/* NEED TO FILL IN ADDITIONAL PORT STATISTICS HERE */
+	port_unlock(p_ptr);
+	str_len = printbuf_validate(&pb);
+
+	skb_put(buf, TLV_SPACE(str_len));
+	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+	return buf;
+}
+
+#endif
+
+void port_reinit(void)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+
+	spin_lock_bh(&port_list_lock);
+	list_for_each_entry(p_ptr, &ports, port_list) {
+		msg = &p_ptr->publ.phdr;
+		if (msg_orignode(msg) == tipc_own_addr)
+			break;
+		msg_set_orignode(msg, tipc_own_addr);
+	}
+	spin_unlock_bh(&port_list_lock);
+}
+
+
+/*
+ *  port_dispatcher_sigh(): Signal handler for messages destinated
+ *                          to the tipc_port interface.
+ */
+
+static void port_dispatcher_sigh(void *dummy)
+{
+	struct sk_buff *buf;
+
+	spin_lock_bh(&queue_lock);
+	buf = msg_queue_head;
+	msg_queue_head = 0;
+	spin_unlock_bh(&queue_lock);
+
+	while (buf) {
+		struct port *p_ptr;
+		struct user_port *up_ptr;
+		struct tipc_portid orig;
+		struct tipc_name_seq dseq;
+		void *usr_handle;
+		int connected;
+		int published;
+
+		struct sk_buff *next = buf->next;
+		struct tipc_msg *msg = buf_msg(buf);
+		u32 dref = msg_destport(msg);
+		
+		p_ptr = port_lock(dref);
+		if (!p_ptr) {
+			/* Port deleted while msg in queue */
+			tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+			buf = next;
+			continue;
+		}
+		orig.ref = msg_origport(msg);
+		orig.node = msg_orignode(msg);
+		up_ptr = p_ptr->user_port;
+		usr_handle = up_ptr->usr_handle;
+		connected = p_ptr->publ.connected;
+		published = p_ptr->publ.published;
+
+		if (unlikely(msg_errcode(msg)))
+			goto err;
+
+		switch (msg_type(msg)) {
+		
+		case TIPC_CONN_MSG:{
+				tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
+				u32 peer_port = port_peerport(p_ptr);
+				u32 peer_node = port_peernode(p_ptr);
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (unlikely(!connected)) {
+					if (unlikely(published))
+						goto reject;
+					tipc_connect2port(dref,&orig);
+				}
+				if (unlikely(msg_origport(msg) != peer_port))
+					goto reject;
+				if (unlikely(msg_orignode(msg) != peer_node))
+					goto reject;
+				if (unlikely(!cb))
+					goto reject;
+				if (unlikely(++p_ptr->publ.conn_unacked >= 
+					     TIPC_FLOW_CONTROL_WIN))
+					tipc_acknowledge(dref, 
+							 p_ptr->publ.conn_unacked);
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg),
+				   msg_data_sz(msg));
+				break;
+			}
+		case TIPC_DIRECT_MSG:{
+				tipc_msg_event cb = up_ptr->msg_cb;
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (unlikely(connected))
+					goto reject;
+				if (unlikely(!cb))
+					goto reject;
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg), 
+				   msg_data_sz(msg), msg_importance(msg),
+				   &orig);
+				break;
+			}
+		case TIPC_NAMED_MSG:{
+				tipc_named_msg_event cb = up_ptr->named_msg_cb;
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (unlikely(connected))
+					goto reject;
+				if (unlikely(!cb))
+					goto reject;
+				if (unlikely(!published))
+					goto reject;
+				dseq.type =  msg_nametype(msg);
+				dseq.lower = msg_nameinst(msg);
+				dseq.upper = dseq.lower;
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg), 
+				   msg_data_sz(msg), msg_importance(msg),
+				   &orig, &dseq);
+				break;
+			}
+		}
+		if (buf)
+			buf_discard(buf);
+		buf = next;
+		continue;
+err:
+		switch (msg_type(msg)) {
+		
+		case TIPC_CONN_MSG:{
+				tipc_conn_shutdown_event cb = 
+					up_ptr->conn_err_cb;
+				u32 peer_port = port_peerport(p_ptr);
+				u32 peer_node = port_peernode(p_ptr);
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (!connected || !cb)
+					break;
+				if (msg_origport(msg) != peer_port)
+					break;
+				if (msg_orignode(msg) != peer_node)
+					break;
+				tipc_disconnect(dref);
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg),
+				   msg_data_sz(msg), msg_errcode(msg));
+				break;
+			}
+		case TIPC_DIRECT_MSG:{
+				tipc_msg_err_event cb = up_ptr->err_cb;
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (connected || !cb)
+					break;
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg),
+				   msg_data_sz(msg), msg_errcode(msg), &orig);
+				break;
+			}
+		case TIPC_NAMED_MSG:{
+				tipc_named_msg_err_event cb = 
+					up_ptr->named_err_cb;
+
+				spin_unlock_bh(p_ptr->publ.lock);
+				if (connected || !cb)
+					break;
+				dseq.type =  msg_nametype(msg);
+				dseq.lower = msg_nameinst(msg);
+				dseq.upper = dseq.lower;
+				skb_pull(buf, msg_hdr_sz(msg));
+				cb(usr_handle, dref, &buf, msg_data(msg), 
+				   msg_data_sz(msg), msg_errcode(msg), &dseq);
+				break;
+			}
+		}
+		if (buf)
+			buf_discard(buf);
+		buf = next;
+		continue;
+reject:
+		tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+		buf = next;
+	}
+}
+
+/*
+ *  port_dispatcher(): Dispatcher for messages destinated
+ *  to the tipc_port interface. Called with port locked.
+ */
+
+static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
+{
+	buf->next = NULL;
+	spin_lock_bh(&queue_lock);
+	if (msg_queue_head) {
+		msg_queue_tail->next = buf;
+		msg_queue_tail = buf;
+	} else {
+		msg_queue_tail = msg_queue_head = buf;
+		k_signal((Handler)port_dispatcher_sigh, 0);
+	}
+	spin_unlock_bh(&queue_lock);
+	return TIPC_OK;
+}
+
+/* 
+ * Wake up port after congestion: Called with port locked,
+ *                                
+ */
+
+static void port_wakeup_sh(unsigned long ref)
+{
+	struct port *p_ptr;
+	struct user_port *up_ptr;
+	tipc_continue_event cb = 0;
+	void *uh = 0;
+
+	p_ptr = port_lock(ref);
+	if (p_ptr) {
+		up_ptr = p_ptr->user_port;
+		if (up_ptr) {
+			cb = up_ptr->continue_event_cb;
+			uh = up_ptr->usr_handle;
+		}
+		port_unlock(p_ptr);
+	}
+	if (cb)
+		cb(uh, ref);
+}
+
+
+static void port_wakeup(struct tipc_port *p_ptr)
+{
+	k_signal((Handler)port_wakeup_sh, p_ptr->ref);
+}
+
+void tipc_acknowledge(u32 ref, u32 ack)
+{
+	struct port *p_ptr;
+	struct sk_buff *buf = 0;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return;
+	if (p_ptr->publ.connected) {
+		p_ptr->publ.conn_unacked -= ack;
+		buf = port_build_proto_msg(port_peerport(p_ptr),
+					   port_peernode(p_ptr),
+					   ref,
+					   tipc_own_addr,
+					   CONN_MANAGER,
+					   CONN_ACK,
+					   TIPC_OK, 
+					   port_out_seqno(p_ptr),
+					   ack);
+	}
+	port_unlock(p_ptr);
+	net_route_msg(buf);
+}
+
+/*
+ * tipc_createport(): user level call. Will add port to
+ *                    registry if non-zero user_ref.
+ */
+
+int tipc_createport(u32 user_ref, 
+		    void *usr_handle, 
+		    unsigned int importance, 
+		    tipc_msg_err_event error_cb, 
+		    tipc_named_msg_err_event named_error_cb, 
+		    tipc_conn_shutdown_event conn_error_cb, 
+		    tipc_msg_event msg_cb, 
+		    tipc_named_msg_event named_msg_cb, 
+		    tipc_conn_msg_event conn_msg_cb, 
+		    tipc_continue_event continue_event_cb,/* May be zero */
+		    u32 *portref)
+{
+	struct user_port *up_ptr;
+	struct port *p_ptr; 
+	u32 ref;
+
+	up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
+	if (up_ptr == NULL) {
+		return -ENOMEM;
+	}
+	ref = tipc_createport_raw(0, port_dispatcher, port_wakeup, importance);
+	p_ptr = port_lock(ref);
+	if (!p_ptr) {
+		kfree(up_ptr);
+		return -ENOMEM;
+	}
+
+	p_ptr->user_port = up_ptr;
+	up_ptr->user_ref = user_ref;
+	up_ptr->usr_handle = usr_handle;
+	up_ptr->ref = p_ptr->publ.ref;
+	up_ptr->err_cb = error_cb;
+	up_ptr->named_err_cb = named_error_cb;
+	up_ptr->conn_err_cb = conn_error_cb;
+	up_ptr->msg_cb = msg_cb;
+	up_ptr->named_msg_cb = named_msg_cb;
+	up_ptr->conn_msg_cb = conn_msg_cb;
+	up_ptr->continue_event_cb = continue_event_cb;
+	INIT_LIST_HEAD(&up_ptr->uport_list);
+	reg_add_port(up_ptr);
+	*portref = p_ptr->publ.ref;
+	dbg(" tipc_createport: %x with ref %u\n", p_ptr, p_ptr->publ.ref);        
+	port_unlock(p_ptr);
+	return TIPC_OK;
+}
+
+int tipc_ownidentity(u32 ref, struct tipc_portid *id)
+{
+	id->ref = ref;
+	id->node = tipc_own_addr;
+	return TIPC_OK;
+}
+
+int tipc_portimportance(u32 ref, unsigned int *importance)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	*importance = (unsigned int)msg_importance(&p_ptr->publ.phdr);
+	spin_unlock_bh(p_ptr->publ.lock);
+	return TIPC_OK;
+}
+
+int tipc_set_portimportance(u32 ref, unsigned int imp)
+{
+	struct port *p_ptr;
+
+	if (imp > TIPC_CRITICAL_IMPORTANCE)
+		return -EINVAL;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	msg_set_importance(&p_ptr->publ.phdr, (u32)imp);
+	spin_unlock_bh(p_ptr->publ.lock);
+	return TIPC_OK;
+}
+
+
+int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
+{
+	struct port *p_ptr;
+	struct publication *publ;
+	u32 key;
+	int res = -EINVAL;
+
+	p_ptr = port_lock(ref);
+	dbg("tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, "
+	    "lower = %u, upper = %u\n",
+	    ref, p_ptr, p_ptr->publ.connected, scope, seq->lower, seq->upper);
+	if (!p_ptr)
+		return -EINVAL;
+	if (p_ptr->publ.connected)
+		goto exit;
+	if (seq->lower > seq->upper)
+		goto exit;
+	if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
+		goto exit;
+	key = ref + p_ptr->pub_count + 1;
+	if (key == ref) {
+		res = -EADDRINUSE;
+		goto exit;
+	}
+	publ = nametbl_publish(seq->type, seq->lower, seq->upper,
+			       scope, p_ptr->publ.ref, key);
+	if (publ) {
+		list_add(&publ->pport_list, &p_ptr->publications);
+		p_ptr->pub_count++;
+		p_ptr->publ.published = 1;
+		res = TIPC_OK;
+	}
+exit:
+	port_unlock(p_ptr);
+	return res;
+}
+
+int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
+{
+	struct port *p_ptr;
+	struct publication *publ;
+	struct publication *tpubl;
+	int res = -EINVAL;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	if (!p_ptr->publ.published)
+		goto exit;
+	if (!seq) {
+		list_for_each_entry_safe(publ, tpubl, 
+					 &p_ptr->publications, pport_list) {
+			nametbl_withdraw(publ->type, publ->lower, 
+					 publ->ref, publ->key);
+		}
+		res = TIPC_OK;
+	} else {
+		list_for_each_entry_safe(publ, tpubl, 
+					 &p_ptr->publications, pport_list) {
+			if (publ->scope != scope)
+				continue;
+			if (publ->type != seq->type)
+				continue;
+			if (publ->lower != seq->lower)
+				continue;
+			if (publ->upper != seq->upper)
+				break;
+			nametbl_withdraw(publ->type, publ->lower, 
+					 publ->ref, publ->key);
+			res = TIPC_OK;
+			break;
+		}
+	}
+	if (list_empty(&p_ptr->publications))
+		p_ptr->publ.published = 0;
+exit:
+	port_unlock(p_ptr);
+	return res;
+}
+
+int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	int res = -EINVAL;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	if (p_ptr->publ.published || p_ptr->publ.connected)
+		goto exit;
+	if (!peer->ref)
+		goto exit;
+
+	msg = &p_ptr->publ.phdr;
+	msg_set_destnode(msg, peer->node);
+	msg_set_destport(msg, peer->ref);
+	msg_set_orignode(msg, tipc_own_addr);
+	msg_set_origport(msg, p_ptr->publ.ref);
+	msg_set_transp_seqno(msg, 42);
+	msg_set_type(msg, TIPC_CONN_MSG);
+	if (!may_route(peer->node))
+		msg_set_hdr_sz(msg, SHORT_H_SIZE);
+	else
+		msg_set_hdr_sz(msg, LONG_H_SIZE);
+
+	p_ptr->probing_interval = PROBING_INTERVAL;
+	p_ptr->probing_state = CONFIRMED;
+	p_ptr->publ.connected = 1;
+	k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
+
+	nodesub_subscribe(&p_ptr->subscription,peer->node,
+			  (void *)(unsigned long)ref,
+			  (net_ev_handler)port_handle_node_down);
+	res = TIPC_OK;
+exit:
+	port_unlock(p_ptr);
+	p_ptr->max_pkt = link_get_max_pkt(peer->node, ref);
+	return res;
+}
+
+/*
+ * tipc_disconnect(): Disconnect port form peer.
+ *                    This is a node local operation.
+ */
+
+int tipc_disconnect(u32 ref)
+{
+	struct port *p_ptr;
+	int res = -ENOTCONN;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	if (p_ptr->publ.connected) {
+		p_ptr->publ.connected = 0;
+		/* let timer expire on it's own to avoid deadlock! */
+		nodesub_unsubscribe(&p_ptr->subscription);
+		res = TIPC_OK;
+	}
+	port_unlock(p_ptr);
+	return res;
+}
+
+/*
+ * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
+ */
+int tipc_shutdown(u32 ref)
+{
+	struct port *p_ptr;
+	struct sk_buff *buf = 0;
+
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+
+	if (p_ptr->publ.connected) {
+		u32 imp = msg_importance(&p_ptr->publ.phdr);
+		if (imp < TIPC_CRITICAL_IMPORTANCE)
+			imp++;
+		buf = port_build_proto_msg(port_peerport(p_ptr),
+					   port_peernode(p_ptr),
+					   ref,
+					   tipc_own_addr,
+					   imp,
+					   TIPC_CONN_MSG,
+					   TIPC_CONN_SHUTDOWN, 
+					   port_out_seqno(p_ptr),
+					   0);
+	}
+	port_unlock(p_ptr);
+	net_route_msg(buf);
+	return tipc_disconnect(ref);
+}
+
+int tipc_isconnected(u32 ref, int *isconnected)
+{
+	struct port *p_ptr;
+	
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	*isconnected = p_ptr->publ.connected;
+	port_unlock(p_ptr);
+	return TIPC_OK;
+}
+
+int tipc_peer(u32 ref, struct tipc_portid *peer)
+{
+	struct port *p_ptr;
+	int res;
+	 
+	p_ptr = port_lock(ref);
+	if (!p_ptr)
+		return -EINVAL;
+	if (p_ptr->publ.connected) {
+		peer->ref = port_peerport(p_ptr);
+		peer->node = port_peernode(p_ptr);
+		res = TIPC_OK;
+	} else
+		res = -ENOTCONN;
+	port_unlock(p_ptr);
+	return res;
+}
+
+int tipc_ref_valid(u32 ref)
+{
+	/* Works irrespective of type */
+	return !!ref_deref(ref);
+}
+
+
+/*
+ *  port_recv_sections(): Concatenate and deliver sectioned
+ *                        message for this node.
+ */
+
+int port_recv_sections(struct port *sender, unsigned int num_sect,
+		       struct iovec const *msg_sect)
+{
+	struct sk_buff *buf;
+	int res;
+	 
+	res = msg_build(&sender->publ.phdr, msg_sect, num_sect,
+			MAX_MSG_SIZE, !sender->user_port, &buf);
+	if (likely(buf))
+		port_recv_msg(buf);
+	return res;
+}
+
+/**
+ * tipc_send - send message sections on connection
+ */
+
+int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
+{
+	struct port *p_ptr;
+	u32 destnode;
+	int res;
+
+	p_ptr = port_deref(ref);
+	if (!p_ptr || !p_ptr->publ.connected)
+		return -EINVAL;
+
+	p_ptr->publ.congested = 1;
+	if (!port_congested(p_ptr)) {
+		destnode = port_peernode(p_ptr);
+		if (likely(destnode != tipc_own_addr))
+			res = link_send_sections_fast(p_ptr, msg_sect, num_sect,
+						      destnode);
+		else
+			res = port_recv_sections(p_ptr, num_sect, msg_sect);
+
+		if (likely(res != -ELINKCONG)) {
+			port_incr_out_seqno(p_ptr);
+			p_ptr->publ.congested = 0;
+			p_ptr->sent++;
+			return res;
+		}
+	}
+	if (port_unreliable(p_ptr)) {
+		p_ptr->publ.congested = 0;
+		/* Just calculate msg length and return */
+		return msg_calc_data_size(msg_sect, num_sect);
+	}
+	return -ELINKCONG;
+}
+
+/** 
+ * tipc_send_buf - send message buffer on connection
+ */
+
+int tipc_send_buf(u32 ref, struct sk_buff *buf, unsigned int dsz)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	u32 destnode;
+	u32 hsz;
+	u32 sz;
+	u32 res;
+	 
+	p_ptr = port_deref(ref);
+	if (!p_ptr || !p_ptr->publ.connected)
+		return -EINVAL;
+
+	msg = &p_ptr->publ.phdr;
+	hsz = msg_hdr_sz(msg);
+	sz = hsz + dsz;
+	msg_set_size(msg, sz);
+	if (skb_cow(buf, hsz))
+		return -ENOMEM;
+
+	skb_push(buf, hsz);
+	memcpy(buf->data, (unchar *)msg, hsz);
+	destnode = msg_destnode(msg);
+	p_ptr->publ.congested = 1;
+	if (!port_congested(p_ptr)) {
+		if (likely(destnode != tipc_own_addr))
+			res = tipc_send_buf_fast(buf, destnode);
+		else {
+			port_recv_msg(buf);
+			res = sz;
+		}
+		if (likely(res != -ELINKCONG)) {
+			port_incr_out_seqno(p_ptr);
+			p_ptr->sent++;
+			p_ptr->publ.congested = 0;
+			return res;
+		}
+	}
+	if (port_unreliable(p_ptr)) {
+		p_ptr->publ.congested = 0;
+		return dsz;
+	}
+	return -ELINKCONG;
+}
+
+/**
+ * tipc_forward2name - forward message sections to port name
+ */
+
+int tipc_forward2name(u32 ref, 
+		      struct tipc_name const *name, 
+		      u32 domain,
+		      u32 num_sect, 
+		      struct iovec const *msg_sect,
+		      struct tipc_portid const *orig, 
+		      unsigned int importance)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	u32 destnode = domain;
+	u32 destport = 0;
+	int res;
+
+	p_ptr = port_deref(ref);
+	if (!p_ptr || p_ptr->publ.connected)
+		return -EINVAL;
+
+	msg = &p_ptr->publ.phdr;
+	msg_set_type(msg, TIPC_NAMED_MSG);
+	msg_set_orignode(msg, orig->node);
+	msg_set_origport(msg, orig->ref);
+	msg_set_hdr_sz(msg, LONG_H_SIZE);
+	msg_set_nametype(msg, name->type);
+	msg_set_nameinst(msg, name->instance);
+	msg_set_lookup_scope(msg, addr_scope(domain));
+	if (importance <= TIPC_CRITICAL_IMPORTANCE)
+		msg_set_importance(msg,importance);
+	destport = nametbl_translate(name->type, name->instance, &destnode);
+	msg_set_destnode(msg, destnode);
+	msg_set_destport(msg, destport);
+
+	if (likely(destport || destnode)) {
+		p_ptr->sent++;
+		if (likely(destnode == tipc_own_addr))
+			return port_recv_sections(p_ptr, num_sect, msg_sect);
+		res = link_send_sections_fast(p_ptr, msg_sect, num_sect, 
+					      destnode);
+		if (likely(res != -ELINKCONG))
+			return res;
+		if (port_unreliable(p_ptr)) {
+			/* Just calculate msg length and return */
+			return msg_calc_data_size(msg_sect, num_sect);
+		}
+		return -ELINKCONG;
+	}
+	return port_reject_sections(p_ptr, msg, msg_sect, num_sect, 
+				    TIPC_ERR_NO_NAME);
+}
+
+/**
+ * tipc_send2name - send message sections to port name
+ */
+
+int tipc_send2name(u32 ref, 
+		   struct tipc_name const *name,
+		   unsigned int domain, 
+		   unsigned int num_sect, 
+		   struct iovec const *msg_sect)
+{
+	struct tipc_portid orig;
+
+	orig.ref = ref;
+	orig.node = tipc_own_addr;
+	return tipc_forward2name(ref, name, domain, num_sect, msg_sect, &orig,
+				 TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward_buf2name - forward message buffer to port name
+ */
+
+int tipc_forward_buf2name(u32 ref,
+			  struct tipc_name const *name,
+			  u32 domain,
+			  struct sk_buff *buf,
+			  unsigned int dsz,
+			  struct tipc_portid const *orig,
+			  unsigned int importance)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	u32 destnode = domain;
+	u32 destport = 0;
+	int res;
+
+	p_ptr = (struct port *)ref_deref(ref);
+	if (!p_ptr || p_ptr->publ.connected)
+		return -EINVAL;
+
+	msg = &p_ptr->publ.phdr;
+	if (importance <= TIPC_CRITICAL_IMPORTANCE)
+		msg_set_importance(msg, importance);
+	msg_set_type(msg, TIPC_NAMED_MSG);
+	msg_set_orignode(msg, orig->node);
+	msg_set_origport(msg, orig->ref);
+	msg_set_nametype(msg, name->type);
+	msg_set_nameinst(msg, name->instance);
+	msg_set_lookup_scope(msg, addr_scope(domain));
+	msg_set_hdr_sz(msg, LONG_H_SIZE);
+	msg_set_size(msg, LONG_H_SIZE + dsz);
+	destport = nametbl_translate(name->type, name->instance, &destnode);
+	msg_set_destnode(msg, destnode);
+	msg_set_destport(msg, destport);
+	msg_dbg(msg, "forw2name ==> ");
+	if (skb_cow(buf, LONG_H_SIZE))
+		return -ENOMEM;
+	skb_push(buf, LONG_H_SIZE);
+	memcpy(buf->data, (unchar *)msg, LONG_H_SIZE);
+	msg_dbg(buf_msg(buf),"PREP:");
+	if (likely(destport || destnode)) {
+		p_ptr->sent++;
+		if (destnode == tipc_own_addr)
+			return port_recv_msg(buf);
+		res = tipc_send_buf_fast(buf, destnode);
+		if (likely(res != -ELINKCONG))
+			return res;
+		if (port_unreliable(p_ptr))
+			return dsz;
+		return -ELINKCONG;
+	}
+	return tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
+}
+
+/** 
+ * tipc_send_buf2name - send message buffer to port name
+ */
+
+int tipc_send_buf2name(u32 ref, 
+		       struct tipc_name const *dest, 
+		       u32 domain,
+		       struct sk_buff *buf, 
+		       unsigned int dsz)
+{
+	struct tipc_portid orig;
+
+	orig.ref = ref;
+	orig.node = tipc_own_addr;
+	return tipc_forward_buf2name(ref, dest, domain, buf, dsz, &orig,
+				     TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward2port - forward message sections to port identity
+ */
+
+int tipc_forward2port(u32 ref,
+		      struct tipc_portid const *dest,
+		      unsigned int num_sect, 
+		      struct iovec const *msg_sect,
+		      struct tipc_portid const *orig, 
+		      unsigned int importance)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	int res;
+
+	p_ptr = port_deref(ref);
+	if (!p_ptr || p_ptr->publ.connected)
+		return -EINVAL;
+
+	msg = &p_ptr->publ.phdr;
+	msg_set_type(msg, TIPC_DIRECT_MSG);
+	msg_set_orignode(msg, orig->node);
+	msg_set_origport(msg, orig->ref);
+	msg_set_destnode(msg, dest->node);
+	msg_set_destport(msg, dest->ref);
+	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
+	if (importance <= TIPC_CRITICAL_IMPORTANCE)
+		msg_set_importance(msg, importance);
+	p_ptr->sent++;
+	if (dest->node == tipc_own_addr)
+		return port_recv_sections(p_ptr, num_sect, msg_sect);
+	res = link_send_sections_fast(p_ptr, msg_sect, num_sect, dest->node);
+	if (likely(res != -ELINKCONG))
+		return res;
+	if (port_unreliable(p_ptr)) {
+		/* Just calculate msg length and return */
+		return msg_calc_data_size(msg_sect, num_sect);
+	}
+	return -ELINKCONG;
+}
+
+/** 
+ * tipc_send2port - send message sections to port identity 
+ */
+
+int tipc_send2port(u32 ref, 
+		   struct tipc_portid const *dest,
+		   unsigned int num_sect, 
+		   struct iovec const *msg_sect)
+{
+	struct tipc_portid orig;
+
+	orig.ref = ref;
+	orig.node = tipc_own_addr;
+	return tipc_forward2port(ref, dest, num_sect, msg_sect, &orig, 
+				 TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward_buf2port - forward message buffer to port identity
+ */
+int tipc_forward_buf2port(u32 ref,
+			  struct tipc_portid const *dest,
+			  struct sk_buff *buf,
+			  unsigned int dsz,
+			  struct tipc_portid const *orig,
+			  unsigned int importance)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg;
+	int res;
+
+	p_ptr = (struct port *)ref_deref(ref);
+	if (!p_ptr || p_ptr->publ.connected)
+		return -EINVAL;
+
+	msg = &p_ptr->publ.phdr;
+	msg_set_type(msg, TIPC_DIRECT_MSG);
+	msg_set_orignode(msg, orig->node);
+	msg_set_origport(msg, orig->ref);
+	msg_set_destnode(msg, dest->node);
+	msg_set_destport(msg, dest->ref);
+	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
+	if (importance <= TIPC_CRITICAL_IMPORTANCE)
+		msg_set_importance(msg, importance);
+	msg_set_size(msg, DIR_MSG_H_SIZE + dsz);
+	if (skb_cow(buf, DIR_MSG_H_SIZE))
+		return -ENOMEM;
+
+	skb_push(buf, DIR_MSG_H_SIZE);
+	memcpy(buf->data, (unchar *)msg, DIR_MSG_H_SIZE);
+	msg_dbg(msg, "buf2port: ");
+	p_ptr->sent++;
+	if (dest->node == tipc_own_addr)
+		return port_recv_msg(buf);
+	res = tipc_send_buf_fast(buf, dest->node);
+	if (likely(res != -ELINKCONG))
+		return res;
+	if (port_unreliable(p_ptr))
+		return dsz;
+	return -ELINKCONG;
+}
+
+/** 
+ * tipc_send_buf2port - send message buffer to port identity
+ */
+
+int tipc_send_buf2port(u32 ref, 
+		       struct tipc_portid const *dest,
+		       struct sk_buff *buf, 
+		       unsigned int dsz)
+{
+	struct tipc_portid orig;
+
+	orig.ref = ref;
+	orig.node = tipc_own_addr;
+	return tipc_forward_buf2port(ref, dest, buf, dsz, &orig, 
+				     TIPC_PORT_IMPORTANCE);
+}
+
diff --git a/net/tipc/port.h b/net/tipc/port.h
new file mode 100644
index 0000000..e829a99
--- /dev/null
+++ b/net/tipc/port.h
@@ -0,0 +1,209 @@
+/*
+ * net/tipc/port.h: Include file for TIPC port code
+ * 
+ * Copyright (c) 1994-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_PORT_H
+#define _TIPC_PORT_H
+
+#include <net/tipc/tipc_port.h>
+#include "ref.h"
+#include "net.h"
+#include "msg.h"
+#include "dbg.h"
+#include "node_subscr.h"
+
+/**
+ * struct user_port - TIPC user port (used with native API)
+ * @user_ref: id of user who created user port
+ * @usr_handle: user-specified field
+ * @ref: object reference to associated TIPC port
+ * <various callback routines>
+ * @uport_list: adjacent user ports in list of ports held by user
+ */
+ 
+struct user_port {
+	u32 user_ref;
+	void *usr_handle; 
+	u32 ref;
+	tipc_msg_err_event err_cb; 
+	tipc_named_msg_err_event named_err_cb; 
+	tipc_conn_shutdown_event conn_err_cb; 
+	tipc_msg_event msg_cb; 
+	tipc_named_msg_event named_msg_cb; 
+	tipc_conn_msg_event conn_msg_cb; 
+	tipc_continue_event continue_event_cb;
+	struct list_head uport_list;
+};
+
+/**
+ * struct port - TIPC port structure
+ * @publ: TIPC port info available to privileged users
+ * @port_list: adjacent ports in TIPC's global list of ports
+ * @dispatcher: ptr to routine which handles received messages
+ * @wakeup: ptr to routine to call when port is no longer congested
+ * @user_port: ptr to user port associated with port (if any)
+ * @wait_list: adjacent ports in list of ports waiting on link congestion
+ * @congested_link: ptr to congested link port is waiting on
+ * @waiting_pkts:
+ * @sent:
+ * @acked:
+ * @publications: list of publications for port
+ * @pub_count: total # of publications port has made during its lifetime
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
+ * @probing_state:
+ * @probing_interval:
+ * @last_in_seqno:
+ * @timer_ref:
+ * @subscription: "node down" subscription used to terminate failed connections
+ */
+
+struct port {
+	struct tipc_port publ;
+	struct list_head port_list;
+	u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
+	void (*wakeup)(struct tipc_port *);
+	struct user_port *user_port;
+	struct list_head wait_list;
+	struct link *congested_link;
+	u32 waiting_pkts;
+	u32 sent;
+	u32 acked;
+	struct list_head publications;
+	u32 pub_count;
+	u32 max_pkt;
+	u32 probing_state;
+	u32 probing_interval;
+	u32 last_in_seqno;
+	struct timer_list timer;
+	struct node_subscr subscription;
+};
+
+extern spinlock_t port_list_lock;
+struct port_list;
+
+int port_recv_sections(struct port *p_ptr, u32 num_sect, 
+		       struct iovec const *msg_sect);
+int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
+			 struct iovec const *msg_sect, u32 num_sect,
+			 int err);
+struct sk_buff *port_get_ports(void);
+struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space);
+void port_recv_proto_msg(struct sk_buff *buf);
+void port_recv_mcast(struct sk_buff *buf, struct port_list *dp);
+void port_reinit(void);
+
+/**
+ * port_lock - lock port instance referred to and return its pointer
+ */
+
+static inline struct port *port_lock(u32 ref)
+{
+	return (struct port *)ref_lock(ref);
+}
+
+/** 
+ * port_unlock - unlock a port instance
+ * 
+ * Can use pointer instead of ref_unlock() since port is already locked.
+ */
+
+static inline void port_unlock(struct port *p_ptr)
+{
+	spin_unlock_bh(p_ptr->publ.lock);
+}
+
+static inline struct port* port_deref(u32 ref)
+{
+	return (struct port *)ref_deref(ref);
+}
+
+static inline u32 peer_port(struct port *p_ptr)
+{
+	return msg_destport(&p_ptr->publ.phdr);
+}
+
+static inline u32 peer_node(struct port *p_ptr)
+{
+	return msg_destnode(&p_ptr->publ.phdr);
+}
+
+static inline int port_congested(struct port *p_ptr)
+{
+	return((p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2));
+}
+
+/** 
+ * port_recv_msg - receive message from lower layer and deliver to port user
+ */
+
+static inline int port_recv_msg(struct sk_buff *buf)
+{
+	struct port *p_ptr;
+	struct tipc_msg *msg = buf_msg(buf);
+	u32 destport = msg_destport(msg);
+	u32 dsz = msg_data_sz(msg);
+	u32 err;
+	
+	/* forward unresolved named message */
+	if (unlikely(!destport)) {
+		net_route_msg(buf);
+		return dsz;
+	}
+
+	/* validate destination & pass to port, otherwise reject message */
+	p_ptr = port_lock(destport);
+	if (likely(p_ptr)) {
+		if (likely(p_ptr->publ.connected)) {
+			if ((unlikely(msg_origport(msg) != peer_port(p_ptr))) ||
+			    (unlikely(msg_orignode(msg) != peer_node(p_ptr))) ||
+			    (unlikely(!msg_connected(msg)))) {
+				err = TIPC_ERR_NO_PORT;
+				port_unlock(p_ptr);
+				goto reject;
+			}
+		}
+		err = p_ptr->dispatcher(&p_ptr->publ, buf);
+		port_unlock(p_ptr);
+		if (likely(!err))
+			return dsz;
+	} else {
+		err = TIPC_ERR_NO_PORT;
+	}
+reject:
+	dbg("port->rejecting, err = %x..\n",err);
+	return tipc_reject_msg(buf, err);
+}
+
+#endif
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
new file mode 100644
index 0000000..944093f
--- /dev/null
+++ b/net/tipc/ref.c
@@ -0,0 +1,189 @@
+/*
+ * net/tipc/ref.c: TIPC object registry code
+ * 
+ * Copyright (c) 1991-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "ref.h"
+#include "port.h"
+#include "subscr.h"
+#include "name_distr.h"
+#include "name_table.h"
+#include "config.h"
+#include "discover.h"
+#include "bearer.h"
+#include "node.h"
+#include "bcast.h"
+
+/*
+ * Object reference table consists of 2**N entries.
+ *
+ * A used entry has object ptr != 0, reference == XXXX|own index
+ *				     (XXXX changes each time entry is acquired) 
+ * A free entry has object ptr == 0, reference == YYYY|next free index
+ *				     (YYYY is one more than last used XXXX)
+ *
+ * Free list is initially chained from entry (2**N)-1 to entry 1. 
+ * Entry 0 is not used to allow index 0 to indicate the end of the free list.
+ *
+ * Note: Any accidental reference of the form XXXX|0--0 won't match entry 0
+ * because entry 0's reference field has the form XXXX|1--1.
+ */
+
+struct ref_table ref_table = { 0 };
+
+rwlock_t reftbl_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * ref_table_init - create reference table for objects
+ */
+
+int ref_table_init(u32 requested_size, u32 start)
+{
+	struct reference *table;
+	u32 sz = 1 << 4;
+	u32 index_mask;
+	int i;
+
+	while (sz < requested_size) {
+		sz <<= 1;
+	}
+	table = (struct reference *)vmalloc(sz * sizeof(struct reference));
+	if (table == NULL)
+		return -ENOMEM;
+
+	write_lock_bh(&reftbl_lock);
+	index_mask = sz - 1;
+	for (i = sz - 1; i >= 0; i--) {
+		table[i].object = 0;
+		table[i].lock = SPIN_LOCK_UNLOCKED;
+		table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
+	}
+	ref_table.entries = table;
+	ref_table.index_mask = index_mask;
+	ref_table.first_free = sz - 1;
+	ref_table.last_free = 1;
+	write_unlock_bh(&reftbl_lock);
+	return TIPC_OK;
+}
+
+/**
+ * ref_table_stop - destroy reference table for objects
+ */
+
+void ref_table_stop(void)
+{
+	if (!ref_table.entries)
+		return;
+
+	vfree(ref_table.entries);
+	ref_table.entries = 0;
+}
+
+/**
+ * ref_acquire - create reference to an object
+ * 
+ * Return a unique reference value which can be translated back to the pointer
+ * 'object' at a later time.  Also, pass back a pointer to the lock protecting 
+ * the object, but without locking it.
+ */
+
+u32 ref_acquire(void *object, spinlock_t **lock)
+{
+	struct reference *entry;
+	u32 index;
+	u32 index_mask;
+	u32 next_plus_upper;
+	u32 reference = 0;
+
+	assert(ref_table.entries && object);
+
+	write_lock_bh(&reftbl_lock);
+	if (ref_table.first_free) {
+		index = ref_table.first_free;
+		entry = &(ref_table.entries[index]);
+		index_mask = ref_table.index_mask;
+		/* take lock in case a previous user of entry still holds it */ 
+		spin_lock_bh(&entry->lock);  
+		next_plus_upper = entry->data.next_plus_upper;
+		ref_table.first_free = next_plus_upper & index_mask;
+		reference = (next_plus_upper & ~index_mask) + index;
+		entry->data.reference = reference;
+		entry->object = object;
+                if (lock != 0)
+                        *lock = &entry->lock;
+		spin_unlock_bh(&entry->lock);
+	}
+	write_unlock_bh(&reftbl_lock);
+	return reference;
+}
+
+/**
+ * ref_discard - invalidate references to an object
+ * 
+ * Disallow future references to an object and free up the entry for re-use.
+ * Note: The entry's spin_lock may still be busy after discard
+ */
+
+void ref_discard(u32 ref)
+{
+	struct reference *entry;
+	u32 index; 
+	u32 index_mask;
+
+	assert(ref_table.entries);
+	assert(ref != 0);
+
+	write_lock_bh(&reftbl_lock);
+	index_mask = ref_table.index_mask;
+	index = ref & index_mask;
+	entry = &(ref_table.entries[index]);
+	assert(entry->object != 0);
+	assert(entry->data.reference == ref);
+
+	/* mark entry as unused */
+	entry->object = 0;
+	if (ref_table.first_free == 0)
+		ref_table.first_free = index;
+	else
+		/* next_plus_upper is always XXXX|0--0 for last free entry */
+		ref_table.entries[ref_table.last_free].data.next_plus_upper 
+			|= index;
+	ref_table.last_free = index;
+
+	/* increment upper bits of entry to invalidate subsequent references */
+	entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
+	write_unlock_bh(&reftbl_lock);
+}
+
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
new file mode 100644
index 0000000..429cde5
--- /dev/null
+++ b/net/tipc/ref.h
@@ -0,0 +1,131 @@
+/*
+ * net/tipc/ref.h: Include file for TIPC object registry code
+ * 
+ * Copyright (c) 1991-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_REF_H
+#define _TIPC_REF_H
+
+/**
+ * struct reference - TIPC object reference entry
+ * @object: pointer to object associated with reference entry
+ * @lock: spinlock controlling access to object
+ * @data: reference value associated with object (or link to next unused entry)
+ */
+ 
+struct reference {
+	void *object;
+	spinlock_t lock;
+	union {
+		u32 next_plus_upper;
+		u32 reference;
+	} data;
+};
+
+/**
+ * struct ref_table - table of TIPC object reference entries
+ * @entries: pointer to array of reference entries
+ * @index_mask: bitmask for array index portion of reference values
+ * @first_free: array index of first unused object reference entry
+ * @last_free: array index of last unused object reference entry
+ */
+
+struct ref_table {
+	struct reference *entries;
+	u32 index_mask;
+	u32 first_free;
+	u32 last_free;
+};
+
+extern struct ref_table ref_table;
+
+int ref_table_init(u32 requested_size, u32 start);
+void ref_table_stop(void);
+
+u32 ref_acquire(void *object, spinlock_t **lock);
+void ref_discard(u32 ref);
+
+
+/**
+ * ref_lock - lock referenced object and return pointer to it
+ */
+
+static inline void *ref_lock(u32 ref)
+{
+	if (likely(ref_table.entries)) {
+		struct reference *r =
+			&ref_table.entries[ref & ref_table.index_mask];
+
+		spin_lock_bh(&r->lock);
+		if (likely(r->data.reference == ref))
+			return r->object;
+		spin_unlock_bh(&r->lock);
+	}
+	return 0;
+}
+
+/**
+ * ref_unlock - unlock referenced object 
+ */
+
+static inline void ref_unlock(u32 ref)
+{
+	if (likely(ref_table.entries)) {
+		struct reference *r =
+			&ref_table.entries[ref & ref_table.index_mask];
+
+		if (likely(r->data.reference == ref))
+			spin_unlock_bh(&r->lock);
+		else
+			err("ref_unlock() invoked using obsolete reference\n");
+	}
+}
+
+/**
+ * ref_deref - return pointer referenced object (without locking it)
+ */
+
+static inline void *ref_deref(u32 ref)
+{
+	if (likely(ref_table.entries)) {
+		struct reference *r = 
+			&ref_table.entries[ref & ref_table.index_mask];
+
+		if (likely(r->data.reference == ref))
+			return r->object;
+	}
+	return 0;
+}
+
+#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
new file mode 100644
index 0000000..d21f8c0
--- /dev/null
+++ b/net/tipc/socket.c
@@ -0,0 +1,1726 @@
+/*
+ * net/tipc/socket.c: TIPC socket API
+ * 
+ * Copyright (c) 2001-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/fcntl.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/string.h>
+#include <asm/atomic.h>
+#include <net/sock.h>
+
+#include <linux/tipc.h>
+#include <linux/tipc_config.h>
+#include <net/tipc/tipc_msg.h>
+#include <net/tipc/tipc_port.h>
+
+#include "core.h"
+
+#define SS_LISTENING	-1	/* socket is listening */
+#define SS_READY	-2	/* socket is connectionless */
+
+#define OVERLOAD_LIMIT_BASE    5000
+
+struct tipc_sock {
+	struct sock sk;
+	struct tipc_port *p;
+	struct semaphore sem;
+};
+
+#define tipc_sk(sk) ((struct tipc_sock*)sk)
+
+static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
+static void wakeupdispatch(struct tipc_port *tport);
+
+static struct proto_ops packet_ops;
+static struct proto_ops stream_ops;
+static struct proto_ops msg_ops;
+
+static struct proto tipc_proto;
+
+static int sockets_enabled = 0;
+
+static atomic_t tipc_queue_size = ATOMIC_INIT(0);
+
+
+/* 
+ * sock_lock(): Lock a port/socket pair. lock_sock() can 
+ * not be used here, since the same lock must protect ports 
+ * with non-socket interfaces.
+ * See net.c for description of locking policy.
+ */
+static inline void sock_lock(struct tipc_sock* tsock)
+{
+        spin_lock_bh(tsock->p->lock);       
+}
+
+/* 
+ * sock_unlock(): Unlock a port/socket pair
+ */
+static inline void sock_unlock(struct tipc_sock* tsock)
+{
+        spin_unlock_bh(tsock->p->lock);
+}
+
+/**
+ * pollmask - determine the current set of poll() events for a socket
+ * @sock: socket structure
+ * 
+ * TIPC sets the returned events as follows:
+ * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
+ *    or if a connection-oriented socket is does not have an active connection
+ *    (i.e. a read operation will not block).
+ * b) POLLOUT is set except when a socket's connection has been terminated
+ *    (i.e. a write operation will not block).
+ * c) POLLHUP is set when a socket's connection has been terminated.
+ *
+ * IMPORTANT: The fact that a read or write operation will not block does NOT
+ * imply that the operation will succeed!
+ * 
+ * Returns pollmask value
+ */
+
+static inline u32 pollmask(struct socket *sock)
+{
+	u32 mask;
+
+	if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) ||
+	    (sock->state == SS_UNCONNECTED) ||
+	    (sock->state == SS_DISCONNECTING))
+		mask = (POLLRDNORM | POLLIN);
+	else
+		mask = 0;
+
+	if (sock->state == SS_DISCONNECTING) 
+		mask |= POLLHUP;
+	else
+		mask |= POLLOUT;
+
+	return mask;
+}
+
+
+/**
+ * advance_queue - discard first buffer in queue
+ * @tsock: TIPC socket
+ */
+
+static inline void advance_queue(struct tipc_sock *tsock)
+{
+        sock_lock(tsock);
+	buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue));
+        sock_unlock(tsock);
+	atomic_dec(&tipc_queue_size);
+}
+
+/**
+ * tipc_create - create a TIPC socket
+ * @sock: pre-allocated socket structure
+ * @protocol: protocol indicator (must be 0)
+ * 
+ * This routine creates and attaches a 'struct sock' to the 'struct socket',
+ * then create and attaches a TIPC port to the 'struct sock' part.
+ *
+ * Returns 0 on success, errno otherwise
+ */
+static int tipc_create(struct socket *sock, int protocol)
+{
+	struct tipc_sock *tsock;
+	struct tipc_port *port;
+	struct sock *sk;
+        u32 ref;
+
+	if ((sock->type != SOCK_STREAM) && 
+	    (sock->type != SOCK_SEQPACKET) &&
+	    (sock->type != SOCK_DGRAM) &&
+	    (sock->type != SOCK_RDM))
+		return -EPROTOTYPE;
+
+	if (unlikely(protocol != 0))
+		return -EPROTONOSUPPORT;
+
+	ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE);
+	if (unlikely(!ref))
+		return -ENOMEM;
+
+	sock->state = SS_UNCONNECTED;
+
+	switch (sock->type) {
+	case SOCK_STREAM:
+		sock->ops = &stream_ops;
+		break;
+	case SOCK_SEQPACKET:
+		sock->ops = &packet_ops;
+		break;
+	case SOCK_DGRAM:
+		tipc_set_portunreliable(ref, 1);
+		/* fall through */
+	case SOCK_RDM:
+		tipc_set_portunreturnable(ref, 1);
+		sock->ops = &msg_ops;
+		sock->state = SS_READY;
+		break;
+	}
+
+	sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
+	if (!sk) {
+		tipc_deleteport(ref);
+		return -ENOMEM;
+	}
+
+	sock_init_data(sock, sk);
+	init_waitqueue_head(sk->sk_sleep);
+	sk->sk_rcvtimeo = 8 * HZ;   /* default connect timeout = 8s */
+
+	tsock = tipc_sk(sk);
+	port = tipc_get_port(ref);
+
+	tsock->p = port;
+	port->usr_handle = tsock;
+
+	init_MUTEX(&tsock->sem);
+
+	dbg("sock_create: %x\n",tsock);
+
+	atomic_inc(&tipc_user_count);
+
+	return 0;
+}
+
+/**
+ * release - destroy a TIPC socket
+ * @sock: socket to destroy
+ *
+ * This routine cleans up any messages that are still queued on the socket.
+ * For DGRAM and RDM socket types, all queued messages are rejected.
+ * For SEQPACKET and STREAM socket types, the first message is rejected
+ * and any others are discarded.  (If the first message on a STREAM socket
+ * is partially-read, it is discarded and the next one is rejected instead.)
+ * 
+ * NOTE: Rejected messages are not necessarily returned to the sender!  They
+ * are returned or discarded according to the "destination droppable" setting
+ * specified for the message by the sender.
+ *
+ * Returns 0 on success, errno otherwise
+ */
+
+static int release(struct socket *sock)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sock *sk = sock->sk;
+	int res = TIPC_OK;
+	struct sk_buff *buf;
+
+        dbg("sock_delete: %x\n",tsock);
+	if (!tsock)
+		return 0;
+	down_interruptible(&tsock->sem);
+	if (!sock->sk) {
+		up(&tsock->sem);
+		return 0;
+	}
+	
+	/* Reject unreceived messages, unless no longer connected */
+
+	while (sock->state != SS_DISCONNECTING) {
+		sock_lock(tsock);
+		buf = skb_dequeue(&sk->sk_receive_queue);
+		if (!buf)
+			tsock->p->usr_handle = 0;
+		sock_unlock(tsock);
+		if (!buf)
+			break;
+		if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf)))
+			buf_discard(buf);
+		else
+			tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+		atomic_dec(&tipc_queue_size);
+	}
+
+	/* Delete TIPC port */
+
+	res = tipc_deleteport(tsock->p->ref);
+	sock->sk = NULL;
+
+	/* Discard any remaining messages */
+
+	while ((buf = skb_dequeue(&sk->sk_receive_queue))) {
+		buf_discard(buf);
+		atomic_dec(&tipc_queue_size);
+	}
+
+	up(&tsock->sem);
+
+	sock_put(sk);
+
+        atomic_dec(&tipc_user_count);
+	return res;
+}
+
+/**
+ * bind - associate or disassocate TIPC name(s) with a socket
+ * @sock: socket structure
+ * @uaddr: socket address describing name(s) and desired operation
+ * @uaddr_len: size of socket address data structure
+ * 
+ * Name and name sequence binding is indicated using a positive scope value;
+ * a negative scope value unbinds the specified name.  Specifying no name
+ * (i.e. a socket address length of 0) unbinds all names from the socket.
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
+	int res;
+
+	if (down_interruptible(&tsock->sem))
+		return -ERESTARTSYS;
+	
+	if (unlikely(!uaddr_len)) {
+		res = tipc_withdraw(tsock->p->ref, 0, 0);
+		goto exit;
+	}
+
+	if (uaddr_len < sizeof(struct sockaddr_tipc)) {
+		res = -EINVAL;
+		goto exit;
+	}
+
+	if (addr->family != AF_TIPC) {
+		res = -EAFNOSUPPORT;
+		goto exit;
+	}
+	if (addr->addrtype == TIPC_ADDR_NAME)
+		addr->addr.nameseq.upper = addr->addr.nameseq.lower;
+	else if (addr->addrtype != TIPC_ADDR_NAMESEQ) {
+		res = -EAFNOSUPPORT;
+		goto exit;
+	}
+        
+       	if (addr->scope > 0)
+		res = tipc_publish(tsock->p->ref, addr->scope,
+				   &addr->addr.nameseq);
+	else
+		res = tipc_withdraw(tsock->p->ref, -addr->scope,
+				    &addr->addr.nameseq);
+exit:
+	up(&tsock->sem);
+	return res;
+}
+
+/** 
+ * get_name - get port ID of socket or peer socket
+ * @sock: socket structure
+ * @uaddr: area for returned socket address
+ * @uaddr_len: area for returned length of socket address
+ * @peer: 0 to obtain socket name, 1 to obtain peer socket name
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int get_name(struct socket *sock, struct sockaddr *uaddr, 
+		    int *uaddr_len, int peer)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
+	u32 res;
+
+	if (down_interruptible(&tsock->sem))
+		return -ERESTARTSYS;
+
+	*uaddr_len = sizeof(*addr);
+	addr->addrtype = TIPC_ADDR_ID;
+	addr->family = AF_TIPC;
+	addr->scope = 0;
+	if (peer)
+		res = tipc_peer(tsock->p->ref, &addr->addr.id);
+	else
+		res = tipc_ownidentity(tsock->p->ref, &addr->addr.id);
+	addr->addr.name.domain = 0;
+
+	up(&tsock->sem);
+	return res;
+}
+
+/**
+ * poll - read and possibly block on pollmask
+ * @file: file structure associated with the socket
+ * @sock: socket for which to calculate the poll bits
+ * @wait: ???
+ *
+ * Returns the pollmask
+ */
+
+static unsigned int poll(struct file *file, struct socket *sock, 
+			 poll_table *wait)
+{
+	poll_wait(file, sock->sk->sk_sleep, wait);
+	/* NEED LOCK HERE? */
+	return pollmask(sock);
+}
+
+/** 
+ * dest_name_check - verify user is permitted to send to specified port name
+ * @dest: destination address
+ * @m: descriptor for message to be sent
+ * 
+ * Prevents restricted configuration commands from being issued by
+ * unauthorized users.
+ * 
+ * Returns 0 if permission is granted, otherwise errno
+ */
+
+static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
+{
+	struct tipc_cfg_msg_hdr hdr;
+
+        if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES))
+                return 0;
+        if (likely(dest->addr.name.name.type == TIPC_TOP_SRV))
+                return 0;
+
+        if (likely(dest->addr.name.name.type != TIPC_CFG_SRV))
+                return -EACCES;
+
+        if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
+		return -EFAULT;
+	if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN)))
+		return -EACCES;
+        
+	return 0;
+}
+
+/**
+ * send_msg - send message in connectionless manner
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: message to send
+ * @total_len: (unused)
+ * 
+ * Message must have an destination specified explicitly.
+ * Used for SOCK_RDM and SOCK_DGRAM messages, 
+ * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections.
+ * (Note: 'SYN+' is prohibited on SOCK_STREAM.)
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+static int send_msg(struct kiocb *iocb, struct socket *sock,
+		    struct msghdr *m, size_t total_len)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+        struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
+	struct sk_buff *buf;
+	int needs_conn;
+	int res = -EINVAL;
+
+	if (unlikely(!dest))
+		return -EDESTADDRREQ;
+	if (unlikely(dest->family != AF_TIPC))
+		return -EINVAL;
+
+	needs_conn = (sock->state != SS_READY);
+	if (unlikely(needs_conn)) {
+		if (sock->state == SS_LISTENING)
+			return -EPIPE;
+		if (sock->state != SS_UNCONNECTED)
+			return -EISCONN;
+		if ((tsock->p->published) ||
+		    ((sock->type == SOCK_STREAM) && (total_len != 0)))
+			return -EOPNOTSUPP;
+	}
+
+	if (down_interruptible(&tsock->sem))
+		return -ERESTARTSYS;
+
+	if (needs_conn) {
+
+		/* Abort any pending connection attempts (very unlikely) */
+
+		while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+			tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+			atomic_dec(&tipc_queue_size);
+		}
+
+		sock->state = SS_CONNECTING;
+	}
+
+        do {
+                if (dest->addrtype == TIPC_ADDR_NAME) {
+                        if ((res = dest_name_check(dest, m)))
+                                goto exit;
+                        res = tipc_send2name(tsock->p->ref,
+                                             &dest->addr.name.name,
+                                             dest->addr.name.domain, 
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                else if (dest->addrtype == TIPC_ADDR_ID) {
+                        res = tipc_send2port(tsock->p->ref,
+                                             &dest->addr.id,
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                else if (dest->addrtype == TIPC_ADDR_MCAST) {
+			if (needs_conn) {
+				res = -EOPNOTSUPP;
+				goto exit;
+			}
+                        if ((res = dest_name_check(dest, m)))
+                                goto exit;
+                        res = tipc_multicast(tsock->p->ref,
+                                             &dest->addr.nameseq,
+                                             0,
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                if (likely(res != -ELINKCONG)) {
+exit:                                
+                        up(&tsock->sem);
+                        return res;
+                }
+		if (m->msg_flags & MSG_DONTWAIT) {
+			res = -EWOULDBLOCK;
+			goto exit;
+		}
+                if (wait_event_interruptible(*sock->sk->sk_sleep,
+                                             !tsock->p->congested)) {
+                    res = -ERESTARTSYS;
+                    goto exit;
+                }
+        } while (1);
+}
+
+/** 
+ * send_packet - send a connection-oriented message
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: message to send
+ * @total_len: (unused)
+ * 
+ * Used for SOCK_SEQPACKET messages and SOCK_STREAM data.
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+static int send_packet(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *m, size_t total_len)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+        struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
+	int res;
+
+	/* Handle implied connection establishment */
+
+	if (unlikely(dest))
+		return send_msg(iocb, sock, m, total_len);
+
+	if (down_interruptible(&tsock->sem)) {
+		return -ERESTARTSYS;
+        }
+
+        if (unlikely(sock->state != SS_CONNECTED)) {
+                if (sock->state == SS_DISCONNECTING)
+                        res = -EPIPE;   
+                else
+                        res = -ENOTCONN;
+                goto exit;
+        }
+
+        do {
+                res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
+                if (likely(res != -ELINKCONG)) {
+exit:
+                        up(&tsock->sem);
+                        return res;
+                }
+		if (m->msg_flags & MSG_DONTWAIT) {
+			res = -EWOULDBLOCK;
+			goto exit;
+		}
+                if (wait_event_interruptible(*sock->sk->sk_sleep,
+                                             !tsock->p->congested)) {
+                    res = -ERESTARTSYS;
+                    goto exit;
+                }
+        } while (1);
+}
+
+/** 
+ * send_stream - send stream-oriented data
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: data to send
+ * @total_len: total length of data to be sent
+ * 
+ * Used for SOCK_STREAM data.
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+
+static int send_stream(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *m, size_t total_len)
+{
+	struct msghdr my_msg;
+	struct iovec my_iov;
+	struct iovec *curr_iov;
+	int curr_iovlen;
+	char __user *curr_start;
+	int curr_left;
+	int bytes_to_send;
+	int res;
+	
+	if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
+		return send_packet(iocb, sock, m, total_len);
+
+	/* Can only send large data streams if already connected */
+
+        if (unlikely(sock->state != SS_CONNECTED)) {
+                if (sock->state == SS_DISCONNECTING)
+                        return -EPIPE;   
+                else
+                        return -ENOTCONN;
+        }
+
+	/* 
+	 * Send each iovec entry using one or more messages
+	 *
+	 * Note: This algorithm is good for the most likely case 
+	 * (i.e. one large iovec entry), but could be improved to pass sets
+	 * of small iovec entries into send_packet().
+	 */
+
+	my_msg = *m;
+	curr_iov = my_msg.msg_iov;
+	curr_iovlen = my_msg.msg_iovlen;
+	my_msg.msg_iov = &my_iov;
+	my_msg.msg_iovlen = 1;
+
+	while (curr_iovlen--) {
+		curr_start = curr_iov->iov_base;
+		curr_left = curr_iov->iov_len;
+
+		while (curr_left) {
+			bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE)
+				? curr_left : TIPC_MAX_USER_MSG_SIZE;
+			my_iov.iov_base = curr_start;
+			my_iov.iov_len = bytes_to_send;
+                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0)
+                                return res;
+			curr_left -= bytes_to_send;
+			curr_start += bytes_to_send;
+		}
+
+		curr_iov++;
+	}
+
+	return total_len;
+}
+
+/**
+ * auto_connect - complete connection setup to a remote port
+ * @sock: socket structure
+ * @tsock: TIPC-specific socket structure
+ * @msg: peer's response message
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int auto_connect(struct socket *sock, struct tipc_sock *tsock, 
+			struct tipc_msg *msg)
+{
+	struct tipc_portid peer;
+
+	if (msg_errcode(msg)) {
+		sock->state = SS_DISCONNECTING;
+		return -ECONNREFUSED;
+	}
+
+	peer.ref = msg_origport(msg);
+	peer.node = msg_orignode(msg);
+	tipc_connect2port(tsock->p->ref, &peer);
+	tipc_set_portimportance(tsock->p->ref, msg_importance(msg));
+	sock->state = SS_CONNECTED;
+	return 0;
+}
+
+/**
+ * set_orig_addr - capture sender's address for received message
+ * @m: descriptor for message info
+ * @msg: received message header
+ * 
+ * Note: Address is not captured if not requested by receiver.
+ */
+
+static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
+{
+        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;
+
+        if (addr) {
+		addr->family = AF_TIPC;
+		addr->addrtype = TIPC_ADDR_ID;
+		addr->addr.id.ref = msg_origport(msg);
+		addr->addr.id.node = msg_orignode(msg);
+		addr->addr.name.domain = 0;   	/* could leave uninitialized */
+		addr->scope = 0;   		/* could leave uninitialized */
+		m->msg_namelen = sizeof(struct sockaddr_tipc);
+	}
+}
+
+/**
+ * anc_data_recv - optionally capture ancillary data for received message 
+ * @m: descriptor for message info
+ * @msg: received message header
+ * @tport: TIPC port associated with message
+ * 
+ * Note: Ancillary data is not captured if not requested by receiver.
+ * 
+ * Returns 0 if successful, otherwise errno
+ */
+
+static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, 
+				struct tipc_port *tport)
+{
+	u32 anc_data[3];
+	u32 err;
+	u32 dest_type;
+	int res;
+
+	if (likely(m->msg_controllen == 0))
+		return 0;
+
+	/* Optionally capture errored message object(s) */
+
+	err = msg ? msg_errcode(msg) : 0;
+	if (unlikely(err)) {
+		anc_data[0] = err;
+		anc_data[1] = msg_data_sz(msg);
+		if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data)))
+			return res;
+		if (anc_data[1] &&
+		    (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], 
+				    msg_data(msg))))
+			return res;
+	}
+
+	/* Optionally capture message destination object */
+
+	dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
+	switch (dest_type) {
+	case TIPC_NAMED_MSG:
+		anc_data[0] = msg_nametype(msg);
+		anc_data[1] = msg_namelower(msg);
+		anc_data[2] = msg_namelower(msg);
+		break;
+	case TIPC_MCAST_MSG:
+		anc_data[0] = msg_nametype(msg);
+		anc_data[1] = msg_namelower(msg);
+		anc_data[2] = msg_nameupper(msg);
+		break;
+	case TIPC_CONN_MSG:
+		anc_data[0] = tport->conn_type;
+		anc_data[1] = tport->conn_instance;
+		anc_data[2] = tport->conn_instance;
+		break;
+	default:
+		anc_data[0] = 0;
+	}
+	if (anc_data[0] &&
+	    (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data)))
+		return res;
+
+	return 0;
+}
+
+/** 
+ * recv_msg - receive packet-oriented message
+ * @iocb: (unused)
+ * @m: descriptor for message info
+ * @buf_len: total size of user buffer area
+ * @flags: receive flags
+ * 
+ * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
+ * If the complete message doesn't fit in user area, truncate it.
+ *
+ * Returns size of returned message data, errno otherwise
+ */
+
+static int recv_msg(struct kiocb *iocb, struct socket *sock,
+		    struct msghdr *m, size_t buf_len, int flags)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	unsigned int q_len;
+	unsigned int sz;
+	u32 err;
+	int res;
+
+	/* Currently doesn't support receiving into multiple iovec entries */
+
+	if (m->msg_iovlen != 1)
+		return -EOPNOTSUPP;
+
+	/* Catch invalid receive attempts */
+
+	if (unlikely(!buf_len))
+		return -EINVAL;
+
+	if (sock->type == SOCK_SEQPACKET) {
+		if (unlikely(sock->state == SS_UNCONNECTED))
+			return -ENOTCONN;
+		if (unlikely((sock->state == SS_DISCONNECTING) && 
+			     (skb_queue_len(&sock->sk->sk_receive_queue) == 0)))
+		       	return -ENOTCONN;
+	}
+
+	/* Look for a message in receive queue; wait if necessary */
+
+	if (unlikely(down_interruptible(&tsock->sem)))
+		return -ERESTARTSYS;
+
+restart:
+	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+		     (flags & MSG_DONTWAIT))) {
+		res = -EWOULDBLOCK;
+		goto exit;
+	}
+
+	if ((res = wait_event_interruptible(
+		*sock->sk->sk_sleep, 
+		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+		 (sock->state == SS_DISCONNECTING))) )) {
+		goto exit;
+	}
+
+	/* Catch attempt to receive on an already terminated connection */
+	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
+
+	if (!q_len) {
+		res = -ENOTCONN;
+		goto exit;
+	}
+
+	/* Get access to first message in receive queue */
+
+	buf = skb_peek(&sock->sk->sk_receive_queue);
+	msg = buf_msg(buf);
+	sz = msg_data_sz(msg);
+	err = msg_errcode(msg);
+
+	/* Complete connection setup for an implied connect */
+
+	if (unlikely(sock->state == SS_CONNECTING)) {
+		if ((res = auto_connect(sock, tsock, msg)))
+			goto exit;
+	}
+
+	/* Discard an empty non-errored message & try again */
+
+	if ((!sz) && (!err)) {
+		advance_queue(tsock);
+		goto restart;
+	}
+
+	/* Capture sender's address (optional) */
+
+	set_orig_addr(m, msg);
+
+	/* Capture ancillary data (optional) */
+
+	if ((res = anc_data_recv(m, msg, tsock->p)))
+		goto exit;
+
+	/* Capture message data (if valid) & compute return value (always) */
+	
+	if (!err) {
+		if (unlikely(buf_len < sz)) {
+			sz = buf_len;
+			m->msg_flags |= MSG_TRUNC;
+		}
+		if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg),
+					  sz))) {
+			res = -EFAULT;
+			goto exit;
+		}
+		res = sz;
+	} else {
+		if ((sock->state == SS_READY) ||
+		    ((err == TIPC_CONN_SHUTDOWN) || m->msg_control))
+			res = 0;
+		else
+			res = -ECONNRESET;
+	}
+
+	/* Consume received message (optional) */
+
+	if (likely(!(flags & MSG_PEEK))) {
+                if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                        tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
+		advance_queue(tsock);
+        }
+exit:
+	up(&tsock->sem);
+	return res;
+}
+
+/** 
+ * recv_stream - receive stream-oriented data
+ * @iocb: (unused)
+ * @m: descriptor for message info
+ * @buf_len: total size of user buffer area
+ * @flags: receive flags
+ * 
+ * Used for SOCK_STREAM messages only.  If not enough data is available 
+ * will optionally wait for more; never truncates data.
+ *
+ * Returns size of returned message data, errno otherwise
+ */
+
+static int recv_stream(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *m, size_t buf_len, int flags)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sk_buff *buf;
+	struct tipc_msg *msg;
+	unsigned int q_len;
+	unsigned int sz;
+	int sz_to_copy;
+	int sz_copied = 0;
+	int needed;
+	char *crs = m->msg_iov->iov_base;
+	unsigned char *buf_crs;
+	u32 err;
+	int res;
+
+	/* Currently doesn't support receiving into multiple iovec entries */
+
+	if (m->msg_iovlen != 1)
+		return -EOPNOTSUPP;
+
+	/* Catch invalid receive attempts */
+
+	if (unlikely(!buf_len))
+		return -EINVAL;
+
+	if (unlikely(sock->state == SS_DISCONNECTING)) {
+		if (skb_queue_len(&sock->sk->sk_receive_queue) == 0)
+			return -ENOTCONN;
+	} else if (unlikely(sock->state != SS_CONNECTED))
+		return -ENOTCONN;
+
+	/* Look for a message in receive queue; wait if necessary */
+
+	if (unlikely(down_interruptible(&tsock->sem)))
+		return -ERESTARTSYS;
+
+restart:
+	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+		     (flags & MSG_DONTWAIT))) {
+		res = (sz_copied == 0) ? -EWOULDBLOCK : 0;
+		goto exit;
+	}
+
+	if ((res = wait_event_interruptible(
+		*sock->sk->sk_sleep, 
+		((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+		 (sock->state == SS_DISCONNECTING))) )) {
+		goto exit;
+	}
+
+	/* Catch attempt to receive on an already terminated connection */
+	/* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
+
+	if (!q_len) {
+		res = -ENOTCONN;
+		goto exit;
+	}
+
+	/* Get access to first message in receive queue */
+
+	buf = skb_peek(&sock->sk->sk_receive_queue);
+	msg = buf_msg(buf);
+	sz = msg_data_sz(msg);
+	err = msg_errcode(msg);
+
+	/* Discard an empty non-errored message & try again */
+
+	if ((!sz) && (!err)) {
+		advance_queue(tsock);
+		goto restart;
+	}
+
+	/* Optionally capture sender's address & ancillary data of first msg */
+
+	if (sz_copied == 0) {
+		set_orig_addr(m, msg);
+		if ((res = anc_data_recv(m, msg, tsock->p)))
+			goto exit;
+	}
+
+	/* Capture message data (if valid) & compute return value (always) */
+	
+	if (!err) {
+		buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);
+		sz = buf->tail - buf_crs;
+
+		needed = (buf_len - sz_copied);
+		sz_to_copy = (sz <= needed) ? sz : needed;
+		if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {
+			res = -EFAULT;
+			goto exit;
+		}
+		sz_copied += sz_to_copy;
+
+		if (sz_to_copy < sz) {
+			if (!(flags & MSG_PEEK))
+				TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy;
+			goto exit;
+		}
+
+		crs += sz_to_copy;
+	} else {
+		if (sz_copied != 0)
+			goto exit; /* can't add error msg to valid data */
+
+		if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)
+			res = 0;
+		else
+			res = -ECONNRESET;
+	}
+
+	/* Consume received message (optional) */
+
+	if (likely(!(flags & MSG_PEEK))) {
+                if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                        tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
+		advance_queue(tsock);
+        }
+
+	/* Loop around if more data is required */
+
+	if ((sz_copied < buf_len)    /* didn't get all requested data */ 
+	    && (flags & MSG_WAITALL) /* ... and need to wait for more */
+	    && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */
+	    && (!err)                /* ... and haven't reached a FIN */
+	    )
+		goto restart;
+
+exit:
+	up(&tsock->sem);
+	return res ? res : sz_copied;
+}
+
+/**
+ * queue_overloaded - test if queue overload condition exists
+ * @queue_size: current size of queue
+ * @base: nominal maximum size of queue
+ * @msg: message to be added to queue
+ * 
+ * Returns 1 if queue is currently overloaded, 0 otherwise
+ */
+
+static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg)
+{
+	u32 threshold;
+	u32 imp = msg_importance(msg);
+
+	if (imp == TIPC_LOW_IMPORTANCE)
+		threshold = base;
+	else if (imp == TIPC_MEDIUM_IMPORTANCE)
+		threshold = base * 2;
+	else if (imp == TIPC_HIGH_IMPORTANCE)
+		threshold = base * 100;
+	else
+		return 0;
+
+	if (msg_connected(msg))
+		threshold *= 4;
+
+	return (queue_size > threshold);
+}
+
+/** 
+ * async_disconnect - wrapper function used to disconnect port
+ * @portref: TIPC port reference (passed as pointer-sized value)
+ */
+
+static void async_disconnect(unsigned long portref)
+{
+	tipc_disconnect((u32)portref);
+}
+
+/** 
+ * dispatch - handle arriving message
+ * @tport: TIPC port that received message
+ * @buf: message
+ * 
+ * Called with port locked.  Must not take socket lock to avoid deadlock risk.
+ * 
+ * Returns TIPC error status code (TIPC_OK if message is not to be rejected)
+ */
+
+static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
+{
+	struct tipc_msg *msg = buf_msg(buf);
+	struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
+	struct socket *sock;
+	u32 recv_q_len;
+
+	/* Reject message if socket is closing */
+
+	if (!tsock)
+		return TIPC_ERR_NO_PORT;
+
+	/* Reject message if it is wrong sort of message for socket */
+
+	/*
+	 * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD?
+	 * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY
+	 * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC
+	 */
+	sock = tsock->sk.sk_socket;
+	if (sock->state == SS_READY) {
+		if (msg_connected(msg)) {
+			msg_dbg(msg, "dispatch filter 1\n");
+			return TIPC_ERR_NO_PORT;
+		}
+	} else {
+		if (msg_mcast(msg)) {
+			msg_dbg(msg, "dispatch filter 2\n");
+			return TIPC_ERR_NO_PORT;
+		}
+		if (sock->state == SS_CONNECTED) {
+			if (!msg_connected(msg)) {
+				msg_dbg(msg, "dispatch filter 3\n");
+				return TIPC_ERR_NO_PORT;
+			}
+		}
+		else if (sock->state == SS_CONNECTING) {
+			if (!msg_connected(msg) && (msg_errcode(msg) == 0)) {
+				msg_dbg(msg, "dispatch filter 4\n");
+				return TIPC_ERR_NO_PORT;
+			}
+		} 
+		else if (sock->state == SS_LISTENING) {
+			if (msg_connected(msg) || msg_errcode(msg)) {
+				msg_dbg(msg, "dispatch filter 5\n");
+				return TIPC_ERR_NO_PORT;
+			}
+		} 
+		else if (sock->state == SS_DISCONNECTING) {
+			msg_dbg(msg, "dispatch filter 6\n");
+			return TIPC_ERR_NO_PORT;
+		}
+		else /* (sock->state == SS_UNCONNECTED) */ {
+			if (msg_connected(msg) || msg_errcode(msg)) {
+				msg_dbg(msg, "dispatch filter 7\n");
+				return TIPC_ERR_NO_PORT;
+			}
+		}
+	}
+
+	/* Reject message if there isn't room to queue it */
+
+	if (unlikely((u32)atomic_read(&tipc_queue_size) > 
+		     OVERLOAD_LIMIT_BASE)) {
+		if (queue_overloaded(atomic_read(&tipc_queue_size), 
+				     OVERLOAD_LIMIT_BASE, msg))
+			return TIPC_ERR_OVERLOAD;
+        }
+	recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue);
+	if (unlikely(recv_q_len > (OVERLOAD_LIMIT_BASE / 2))) {
+		if (queue_overloaded(recv_q_len, 
+				     OVERLOAD_LIMIT_BASE / 2, msg)) 
+			return TIPC_ERR_OVERLOAD;
+        }
+
+	/* Initiate connection termination for an incoming 'FIN' */
+
+	if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) {
+		sock->state = SS_DISCONNECTING;
+		/* Note: Use signal since port lock is already taken! */
+		k_signal((Handler)async_disconnect, tport->ref);
+	}
+
+	/* Enqueue message (finally!) */
+
+	msg_dbg(msg,"<DISP<: ");
+	TIPC_SKB_CB(buf)->handle = msg_data(msg);
+	atomic_inc(&tipc_queue_size);
+	skb_queue_tail(&sock->sk->sk_receive_queue, buf);
+
+        wake_up_interruptible(sock->sk->sk_sleep);
+	return TIPC_OK;
+}
+
+/** 
+ * wakeupdispatch - wake up port after congestion
+ * @tport: port to wakeup
+ * 
+ * Called with port lock on.
+ */
+
+static void wakeupdispatch(struct tipc_port *tport)
+{
+	struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
+
+        wake_up_interruptible(tsock->sk.sk_sleep);
+}
+
+/**
+ * connect - establish a connection to another TIPC port
+ * @sock: socket structure
+ * @dest: socket address for destination port
+ * @destlen: size of socket address data structure
+ * @flags: (unused)
+ *
+ * Returns 0 on success, errno otherwise
+ */
+
+static int connect(struct socket *sock, struct sockaddr *dest, int destlen, 
+		   int flags)
+{
+   struct tipc_sock *tsock = tipc_sk(sock->sk);
+   struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
+   struct msghdr m = {0,};
+   struct sk_buff *buf;
+   struct tipc_msg *msg;
+   int res;
+
+   /* For now, TIPC does not allow use of connect() with DGRAM or RDM types */
+
+   if (sock->state == SS_READY)
+	   return -EOPNOTSUPP;
+
+   /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */
+   if (sock->state == SS_LISTENING)
+	   return -EOPNOTSUPP;
+   if (sock->state == SS_CONNECTING)
+	   return -EALREADY;
+   if (sock->state != SS_UNCONNECTED)
+           return -EISCONN;
+
+   if ((dst->family != AF_TIPC) ||
+       ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID)))
+           return -EINVAL;
+
+   /* Send a 'SYN-' to destination */
+
+   m.msg_name = dest;
+   if ((res = send_msg(0, sock, &m, 0)) < 0) {
+	   sock->state = SS_DISCONNECTING;
+	   return res;
+   }
+
+   if (down_interruptible(&tsock->sem)) 
+           return -ERESTARTSYS;
+	
+   /* Wait for destination's 'ACK' response */
+
+   res = wait_event_interruptible_timeout(*sock->sk->sk_sleep,
+                                          skb_queue_len(&sock->sk->sk_receive_queue),
+					  sock->sk->sk_rcvtimeo);
+   buf = skb_peek(&sock->sk->sk_receive_queue);
+   if (res > 0) {
+	   msg = buf_msg(buf);
+           res = auto_connect(sock, tsock, msg);
+           if (!res) {
+		   if (dst->addrtype == TIPC_ADDR_NAME) {
+			   tsock->p->conn_type = dst->addr.name.name.type;
+			   tsock->p->conn_instance = dst->addr.name.name.instance;
+		   }
+		   if (!msg_data_sz(msg))
+			   advance_queue(tsock);
+	   }
+   } else {
+	   if (res == 0) {
+		   res = -ETIMEDOUT;
+	   } else
+	           { /* leave "res" unchanged */ }
+	   sock->state = SS_DISCONNECTING;
+   }
+
+   up(&tsock->sem);
+   return res;
+}
+
+/** 
+ * listen - allow socket to listen for incoming connections
+ * @sock: socket structure
+ * @len: (unused)
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int listen(struct socket *sock, int len)
+{
+	/* REQUIRES SOCKET LOCKING OF SOME SORT? */
+
+	if (sock->state == SS_READY)
+		return -EOPNOTSUPP;
+	if (sock->state != SS_UNCONNECTED)
+		return -EINVAL;
+	sock->state = SS_LISTENING;
+        return 0;
+}
+
+/** 
+ * accept - wait for connection request
+ * @sock: listening socket
+ * @newsock: new socket that is to be connected
+ * @flags: file-related flags associated with socket
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	struct sk_buff *buf;
+	int res = -EFAULT;
+
+	if (sock->state == SS_READY)
+		return -EOPNOTSUPP;
+	if (sock->state != SS_LISTENING)
+		return -EINVAL;
+	
+	if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && 
+		     (flags & O_NONBLOCK)))
+		return -EWOULDBLOCK;
+
+	if (down_interruptible(&tsock->sem))
+		return -ERESTARTSYS;
+
+	if (wait_event_interruptible(*sock->sk->sk_sleep, 
+				     skb_queue_len(&sock->sk->sk_receive_queue))) {
+		res = -ERESTARTSYS;
+		goto exit;
+	}
+	buf = skb_peek(&sock->sk->sk_receive_queue);
+
+	res = tipc_create(newsock, 0);
+	if (!res) {
+		struct tipc_sock *new_tsock = tipc_sk(newsock->sk);
+		struct tipc_portid id;
+		struct tipc_msg *msg = buf_msg(buf);
+		u32 new_ref = new_tsock->p->ref;
+
+		id.ref = msg_origport(msg);
+		id.node = msg_orignode(msg);
+		tipc_connect2port(new_ref, &id);
+		newsock->state = SS_CONNECTED;
+
+		tipc_set_portimportance(new_ref, msg_importance(msg));
+		if (msg_named(msg)) {
+			new_tsock->p->conn_type = msg_nametype(msg);
+			new_tsock->p->conn_instance = msg_nameinst(msg);
+		}
+
+               /* 
+		 * Respond to 'SYN-' by discarding it & returning 'ACK'-.
+		 * Respond to 'SYN+' by queuing it on new socket.
+		 */
+
+		msg_dbg(msg,"<ACC<: ");
+                if (!msg_data_sz(msg)) {
+                        struct msghdr m = {0,};
+
+                        send_packet(0, newsock, &m, 0);      
+                        advance_queue(tsock);
+                } else {
+			sock_lock(tsock);
+			skb_dequeue(&sock->sk->sk_receive_queue);
+			sock_unlock(tsock);
+			skb_queue_head(&newsock->sk->sk_receive_queue, buf);
+		}
+	}
+exit:
+	up(&tsock->sem);
+	return res;
+}
+
+/**
+ * shutdown - shutdown socket connection
+ * @sock: socket structure
+ * @how: direction to close (always treated as read + write)
+ *
+ * Terminates connection (if necessary), then purges socket's receive queue.
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int shutdown(struct socket *sock, int how)
+{
+	struct tipc_sock* tsock = tipc_sk(sock->sk);
+	struct sk_buff *buf;
+	int res;
+
+	/* Could return -EINVAL for an invalid "how", but why bother? */
+
+	if (down_interruptible(&tsock->sem))
+		return -ERESTARTSYS;
+
+	sock_lock(tsock);
+
+	switch (sock->state) {
+	case SS_CONNECTED:
+
+		/* Send 'FIN+' or 'FIN-' message to peer */
+
+		sock_unlock(tsock);
+restart:
+		if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+			atomic_dec(&tipc_queue_size);
+			if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) {
+				buf_discard(buf);
+				goto restart;
+			}
+			tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);
+		}
+		else {
+			tipc_shutdown(tsock->p->ref);
+		}
+		sock_lock(tsock);
+
+		/* fall through */
+
+	case SS_DISCONNECTING:
+
+		/* Discard any unreceived messages */
+
+		while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+			atomic_dec(&tipc_queue_size);
+			buf_discard(buf);
+		}
+		tsock->p->conn_unacked = 0;
+
+		/* fall through */
+
+	case SS_CONNECTING:
+		sock->state = SS_DISCONNECTING;
+		res = 0;
+		break;
+
+	default:
+		res = -ENOTCONN;
+	}
+
+	sock_unlock(tsock);
+
+	up(&tsock->sem);
+	return res;
+}
+
+/**
+ * setsockopt - set socket option
+ * @sock: socket structure
+ * @lvl: option level
+ * @opt: option identifier
+ * @ov: pointer to new option value
+ * @ol: length of option value
+ * 
+ * For stream sockets only, accepts and ignores all IPPROTO_TCP options 
+ * (to ease compatibility).
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+	u32 value;
+	int res;
+
+        if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
+                return 0;
+	if (lvl != SOL_TIPC)
+		return -ENOPROTOOPT;
+	if (ol < sizeof(value))
+		return -EINVAL;
+        if ((res = get_user(value, (u32 *)ov)))
+		return res;
+
+	if (down_interruptible(&tsock->sem)) 
+		return -ERESTARTSYS;
+	
+	switch (opt) {
+	case TIPC_IMPORTANCE:
+		res = tipc_set_portimportance(tsock->p->ref, value);
+		break;
+	case TIPC_SRC_DROPPABLE:
+		if (sock->type != SOCK_STREAM)
+			res = tipc_set_portunreliable(tsock->p->ref, value);
+		else 
+			res = -ENOPROTOOPT;
+		break;
+	case TIPC_DEST_DROPPABLE:
+		res = tipc_set_portunreturnable(tsock->p->ref, value);
+		break;
+	case TIPC_CONN_TIMEOUT:
+		sock->sk->sk_rcvtimeo = (value * HZ / 1000);
+		break;
+	default:
+		res = -EINVAL;
+	}
+
+	up(&tsock->sem);
+	return res;
+}
+
+/**
+ * getsockopt - get socket option
+ * @sock: socket structure
+ * @lvl: option level
+ * @opt: option identifier
+ * @ov: receptacle for option value
+ * @ol: receptacle for length of option value
+ * 
+ * For stream sockets only, returns 0 length result for all IPPROTO_TCP options 
+ * (to ease compatibility).
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol)
+{
+	struct tipc_sock *tsock = tipc_sk(sock->sk);
+        int len;
+	u32 value;
+        int res;
+
+        if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
+                return put_user(0, ol);
+	if (lvl != SOL_TIPC)
+		return -ENOPROTOOPT;
+        if ((res = get_user(len, ol)))
+                return res;
+
+	if (down_interruptible(&tsock->sem)) 
+		return -ERESTARTSYS;
+
+	switch (opt) {
+	case TIPC_IMPORTANCE:
+		res = tipc_portimportance(tsock->p->ref, &value);
+		break;
+	case TIPC_SRC_DROPPABLE:
+		res = tipc_portunreliable(tsock->p->ref, &value);
+		break;
+	case TIPC_DEST_DROPPABLE:
+		res = tipc_portunreturnable(tsock->p->ref, &value);
+		break;
+	case TIPC_CONN_TIMEOUT:
+		value = (sock->sk->sk_rcvtimeo * 1000) / HZ;
+		break;
+	default:
+		res = -EINVAL;
+	}
+
+	if (res) {
+		/* "get" failed */
+	}
+	else if (len < sizeof(value)) {
+		res = -EINVAL;
+	}
+	else if ((res = copy_to_user(ov, &value, sizeof(value)))) {
+		/* couldn't return value */
+	}
+	else {
+		res = put_user(sizeof(value), ol);
+	}
+
+        up(&tsock->sem);
+	return res;
+}
+
+/**
+ * Placeholders for non-implemented functionality
+ * 
+ * Returns error code (POSIX-compliant where defined)
+ */
+
+static int ioctl(struct socket *s, u32 cmd, unsigned long arg)
+{
+        return -EINVAL;
+}
+
+static int no_mmap(struct file *file, struct socket *sock,
+                   struct vm_area_struct *vma)
+{
+        return -EINVAL;
+}
+static ssize_t no_sendpage(struct socket *sock, struct page *page,
+                           int offset, size_t size, int flags)
+{
+        return -EINVAL;
+}
+
+static int no_skpair(struct socket *s1, struct socket *s2)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
+ * Protocol switches for the various types of TIPC sockets
+ */
+
+static struct proto_ops msg_ops = {
+	.owner 		= THIS_MODULE,
+	.family		= AF_TIPC,
+	.release	= release,
+	.bind		= bind,
+	.connect	= connect,
+	.socketpair	= no_skpair,
+	.accept		= accept,
+	.getname	= get_name,
+	.poll		= poll,
+	.ioctl		= ioctl,
+	.listen		= listen,
+	.shutdown	= shutdown,
+	.setsockopt	= setsockopt,
+	.getsockopt	= getsockopt,
+	.sendmsg	= send_msg,
+	.recvmsg	= recv_msg,
+        .mmap		= no_mmap,
+        .sendpage	= no_sendpage
+};
+
+static struct proto_ops packet_ops = {
+	.owner 		= THIS_MODULE,
+	.family		= AF_TIPC,
+	.release	= release,
+	.bind		= bind,
+	.connect	= connect,
+	.socketpair	= no_skpair,
+	.accept		= accept,
+	.getname	= get_name,
+	.poll		= poll,
+	.ioctl		= ioctl,
+	.listen		= listen,
+	.shutdown	= shutdown,
+	.setsockopt	= setsockopt,
+	.getsockopt	= getsockopt,
+	.sendmsg	= send_packet,
+	.recvmsg	= recv_msg,
+        .mmap		= no_mmap,
+        .sendpage	= no_sendpage
+};
+
+static struct proto_ops stream_ops = {
+	.owner 		= THIS_MODULE,
+	.family		= AF_TIPC,
+	.release	= release,
+	.bind		= bind,
+	.connect	= connect,
+	.socketpair	= no_skpair,
+	.accept		= accept,
+	.getname	= get_name,
+	.poll		= poll,
+	.ioctl		= ioctl,
+	.listen		= listen,
+	.shutdown	= shutdown,
+	.setsockopt	= setsockopt,
+	.getsockopt	= getsockopt,
+	.sendmsg	= send_stream,
+	.recvmsg	= recv_stream,
+        .mmap		= no_mmap,
+        .sendpage	= no_sendpage
+};
+
+static struct net_proto_family tipc_family_ops = {
+	.owner 		= THIS_MODULE,
+	.family		= AF_TIPC,
+	.create		= tipc_create
+};
+
+static struct proto tipc_proto = {
+	.name		= "TIPC",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct tipc_sock)
+};
+
+/**
+ * socket_init - initialize TIPC socket interface
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+int socket_init(void)
+{
+	int res;
+
+        res = proto_register(&tipc_proto, 1);
+	if (res) {
+		err("Failed to register TIPC protocol type\n");
+		goto out;
+	}
+
+	res = sock_register(&tipc_family_ops);
+	if (res) {
+		err("Failed to register TIPC socket type\n");
+		proto_unregister(&tipc_proto);
+		goto out;
+	}
+
+	sockets_enabled = 1;
+ out:
+	return res;
+}
+
+/**
+ * sock_stop - stop TIPC socket interface
+ */
+void socket_stop(void)
+{
+	if (!sockets_enabled)
+		return;
+
+	sockets_enabled = 0;
+	sock_unregister(tipc_family_ops.family);
+	proto_unregister(&tipc_proto);
+}
+
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
new file mode 100644
index 0000000..80e219b
--- /dev/null
+++ b/net/tipc/subscr.c
@@ -0,0 +1,527 @@
+/*
+ * net/tipc/subscr.c: TIPC subscription service
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "subscr.h"
+#include "name_table.h"
+#include "ref.h"
+
+/**
+ * struct subscriber - TIPC network topology subscriber
+ * @ref: object reference to subscriber object itself
+ * @lock: pointer to spinlock controlling access to subscriber object
+ * @subscriber_list: adjacent subscribers in top. server's list of subscribers
+ * @subscription_list: list of subscription objects for this subscriber
+ * @port_ref: object reference to port used to communicate with subscriber
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ */
+ 
+struct subscriber {
+	u32 ref;
+        spinlock_t *lock;
+	struct list_head subscriber_list;
+	struct list_head subscription_list;
+	u32 port_ref;
+	int swap;
+};
+
+/**
+ * struct top_srv - TIPC network topology subscription service
+ * @user_ref: TIPC userid of subscription service
+ * @setup_port: reference to TIPC port that handles subscription requests
+ * @subscription_count: number of active subscriptions (not subscribers!)
+ * @subscriber_list: list of ports subscribing to service
+ * @lock: spinlock govering access to subscriber list
+ */
+
+struct top_srv {
+	u32 user_ref;
+	u32 setup_port;
+	atomic_t subscription_count;
+	struct list_head subscriber_list;
+	spinlock_t lock;
+};
+
+static struct top_srv topsrv = { 0 };
+
+/**
+ * htohl - convert value to endianness used by destination
+ * @in: value to convert
+ * @swap: non-zero if endianness must be reversed
+ * 
+ * Returns converted value
+ */
+
+static inline u32 htohl(u32 in, int swap)
+{
+	char *c = (char *)&in;
+
+	return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+}
+
+/**
+ * subscr_send_event - send a message containing a tipc_event to the subscriber
+ */
+
+static void subscr_send_event(struct subscription *sub, 
+			      u32 found_lower, 
+			      u32 found_upper,
+			      u32 event, 
+			      u32 port_ref, 
+			      u32 node)
+{
+	struct iovec msg_sect;
+
+	msg_sect.iov_base = (void *)&sub->evt;
+	msg_sect.iov_len = sizeof(struct tipc_event);
+
+	sub->evt.event = htohl(event, sub->owner->swap);
+	sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
+	sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
+	sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
+	sub->evt.port.node = htohl(node, sub->owner->swap);
+	tipc_send(sub->owner->port_ref, 1, &msg_sect);
+}
+
+/**
+ * subscr_overlap - test for subscription overlap with the given values
+ *
+ * Returns 1 if there is overlap, otherwise 0.
+ */
+
+int subscr_overlap(struct subscription *sub, 
+		   u32 found_lower, 
+		   u32 found_upper)
+
+{
+	if (found_lower < sub->seq.lower)
+		found_lower = sub->seq.lower;
+	if (found_upper > sub->seq.upper)
+		found_upper = sub->seq.upper;
+	if (found_lower > found_upper)
+		return 0;
+	return 1;
+}
+
+/**
+ * subscr_report_overlap - issue event if there is subscription overlap
+ * 
+ * Protected by nameseq.lock in name_table.c
+ */
+
+void subscr_report_overlap(struct subscription *sub, 
+			   u32 found_lower, 
+			   u32 found_upper,
+			   u32 event, 
+			   u32 port_ref, 
+			   u32 node,
+			   int must)
+{
+	dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
+	    sub->seq.upper, found_lower, found_upper);
+	if (!subscr_overlap(sub, found_lower, found_upper))
+		return;
+	if (!must && (sub->filter != TIPC_SUB_PORTS))
+		return;
+	subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+}
+
+/**
+ * subscr_timeout - subscription timeout has occurred
+ */
+
+static void subscr_timeout(struct subscription *sub)
+{
+	struct subscriber *subscriber;
+	u32 subscriber_ref;
+
+	/* Validate subscriber reference (in case subscriber is terminating) */
+
+	subscriber_ref = sub->owner->ref;
+	subscriber = (struct subscriber *)ref_lock(subscriber_ref);
+	if (subscriber == NULL)
+		return;
+
+	/* Unlink subscription from name table */
+
+	nametbl_unsubscribe(sub);
+
+	/* Notify subscriber of timeout, then unlink subscription */
+
+	subscr_send_event(sub, 
+			  sub->evt.s.seq.lower, 
+			  sub->evt.s.seq.upper,
+			  TIPC_SUBSCR_TIMEOUT, 
+			  0, 
+			  0);
+	list_del(&sub->subscription_list);
+
+	/* Now destroy subscription */
+
+	ref_unlock(subscriber_ref);
+	k_term_timer(&sub->timer);
+	kfree(sub);
+	atomic_dec(&topsrv.subscription_count);
+}
+
+/**
+ * subscr_terminate - terminate communication with a subscriber
+ * 
+ * Called with subscriber locked.  Routine must temporarily release this lock
+ * to enable subscription timeout routine(s) to finish without deadlocking; 
+ * the lock is then reclaimed to allow caller to release it upon return.
+ * (This should work even in the unlikely event some other thread creates 
+ * a new object reference in the interim that uses this lock; this routine will
+ * simply wait for it to be released, then claim it.)
+ */
+
+static void subscr_terminate(struct subscriber *subscriber)
+{
+	struct subscription *sub;
+	struct subscription *sub_temp;
+
+	/* Invalidate subscriber reference */
+
+	ref_discard(subscriber->ref);
+	spin_unlock_bh(subscriber->lock);
+
+	/* Destroy any existing subscriptions for subscriber */
+	
+	list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
+				 subscription_list) {
+		if (sub->timeout != TIPC_WAIT_FOREVER) {
+			k_cancel_timer(&sub->timer);
+			k_term_timer(&sub->timer);
+		}
+		nametbl_unsubscribe(sub);
+		list_del(&sub->subscription_list);
+		dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
+		    sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
+		kfree(sub);
+		atomic_dec(&topsrv.subscription_count);
+	}
+
+	/* Sever connection to subscriber */
+
+	tipc_shutdown(subscriber->port_ref);
+	tipc_deleteport(subscriber->port_ref);
+
+	/* Remove subscriber from topology server's subscriber list */
+
+	spin_lock_bh(&topsrv.lock);
+	list_del(&subscriber->subscriber_list);
+	spin_unlock_bh(&topsrv.lock);
+
+	/* Now destroy subscriber */
+
+	spin_lock_bh(subscriber->lock);
+	kfree(subscriber);
+}
+
+/**
+ * subscr_subscribe - create subscription for subscriber
+ * 
+ * Called with subscriber locked
+ */
+
+static void subscr_subscribe(struct tipc_subscr *s,
+			     struct subscriber *subscriber)
+{
+	struct subscription *sub;
+
+	/* Refuse subscription if global limit exceeded */
+
+	if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
+		warn("Failed: max %u subscriptions\n", tipc_max_subscriptions);
+		subscr_terminate(subscriber);
+		return;
+	}
+
+	/* Allocate subscription object */
+
+	sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
+	if (sub == NULL) {
+		warn("Memory squeeze; ignoring subscription\n");
+		subscr_terminate(subscriber);
+		return;
+	}
+
+	/* Determine/update subscriber's endianness */
+
+	if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
+		subscriber->swap = 0;
+	else
+		subscriber->swap = 1;
+
+	/* Initialize subscription object */
+
+	memset(sub, 0, sizeof(*sub));
+	sub->seq.type = htohl(s->seq.type, subscriber->swap);
+	sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
+	sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
+	sub->timeout = htohl(s->timeout, subscriber->swap);
+	sub->filter = htohl(s->filter, subscriber->swap);
+	if ((((sub->filter != TIPC_SUB_PORTS) 
+	      && (sub->filter != TIPC_SUB_SERVICE)))
+	    || (sub->seq.lower > sub->seq.upper)) {
+		warn("Rejecting illegal subscription %u,%u,%u\n",
+		     sub->seq.type, sub->seq.lower, sub->seq.upper);
+		kfree(sub);
+		subscr_terminate(subscriber);
+		return;
+	}
+	memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
+	INIT_LIST_HEAD(&sub->subscription_list);
+	INIT_LIST_HEAD(&sub->nameseq_list);
+	list_add(&sub->subscription_list, &subscriber->subscription_list);
+	atomic_inc(&topsrv.subscription_count);
+	if (sub->timeout != TIPC_WAIT_FOREVER) {
+		k_init_timer(&sub->timer,
+			     (Handler)subscr_timeout, (unsigned long)sub);
+		k_start_timer(&sub->timer, sub->timeout);
+	}
+	sub->owner = subscriber;
+	nametbl_subscribe(sub);
+}
+
+/**
+ * subscr_conn_shutdown_event - handle termination request from subscriber
+ */
+
+static void subscr_conn_shutdown_event(void *usr_handle,
+				       u32 portref,
+				       struct sk_buff **buf,
+				       unsigned char const *data,
+				       unsigned int size,
+				       int reason)
+{
+	struct subscriber *subscriber;
+	spinlock_t *subscriber_lock;
+
+	subscriber = ref_lock((u32)(unsigned long)usr_handle);
+	if (subscriber == NULL)
+		return;
+
+	subscriber_lock = subscriber->lock;
+	subscr_terminate(subscriber);
+	spin_unlock_bh(subscriber_lock);
+}
+
+/**
+ * subscr_conn_msg_event - handle new subscription request from subscriber
+ */
+
+static void subscr_conn_msg_event(void *usr_handle,
+				  u32 port_ref,
+				  struct sk_buff **buf,
+				  const unchar *data,
+				  u32 size)
+{
+	struct subscriber *subscriber;
+	spinlock_t *subscriber_lock;
+
+	subscriber = ref_lock((u32)(unsigned long)usr_handle);
+	if (subscriber == NULL)
+		return;
+
+	subscriber_lock = subscriber->lock;
+	if (size != sizeof(struct tipc_subscr))
+		subscr_terminate(subscriber);
+	else
+		subscr_subscribe((struct tipc_subscr *)data, subscriber);
+	
+	spin_unlock_bh(subscriber_lock);
+}
+
+/**
+ * subscr_named_msg_event - handle request to establish a new subscriber
+ */
+
+static void subscr_named_msg_event(void *usr_handle,
+				   u32 port_ref,
+				   struct sk_buff **buf,
+				   const unchar *data,
+				   u32 size,
+				   u32 importance, 
+				   struct tipc_portid const *orig,
+				   struct tipc_name_seq const *dest)
+{
+	struct subscriber *subscriber;
+	struct iovec msg_sect = {0, 0};
+	spinlock_t *subscriber_lock;
+
+	dbg("subscr_named_msg_event: orig = %x own = %x,\n",
+	    orig->node, tipc_own_addr);
+	if (size && (size != sizeof(struct tipc_subscr))) {
+		warn("Received tipc_subscr of invalid size\n");
+		return;
+	}
+
+	/* Create subscriber object */
+
+	subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC);
+	if (subscriber == NULL) {
+		warn("Memory squeeze; ignoring subscriber setup\n");
+		return;
+	}
+	memset(subscriber, 0, sizeof(struct subscriber));
+	INIT_LIST_HEAD(&subscriber->subscription_list);
+	INIT_LIST_HEAD(&subscriber->subscriber_list);
+	subscriber->ref = ref_acquire(subscriber, &subscriber->lock);
+	if (subscriber->ref == 0) {
+		warn("Failed to acquire subscriber reference\n");
+		kfree(subscriber);
+		return;
+	}
+
+	/* Establish a connection to subscriber */
+
+	tipc_createport(topsrv.user_ref,
+			(void *)(unsigned long)subscriber->ref,
+			importance,
+			0,
+			0,
+			subscr_conn_shutdown_event,
+			0,
+			0,
+			subscr_conn_msg_event,
+			0,
+			&subscriber->port_ref);
+	if (subscriber->port_ref == 0) {
+		warn("Memory squeeze; failed to create subscription port\n");
+		ref_discard(subscriber->ref);
+		kfree(subscriber);
+		return;
+	}
+	tipc_connect2port(subscriber->port_ref, orig);
+
+
+	/* Add subscriber to topology server's subscriber list */
+
+	ref_lock(subscriber->ref);
+	spin_lock_bh(&topsrv.lock);
+	list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
+	spin_unlock_bh(&topsrv.lock);
+
+	/*
+	 * Subscribe now if message contains a subscription,
+	 * otherwise send an empty response to complete connection handshaking
+	 */
+
+	subscriber_lock = subscriber->lock;
+	if (size)
+		subscr_subscribe((struct tipc_subscr *)data, subscriber);
+	else
+		tipc_send(subscriber->port_ref, 1, &msg_sect);
+
+	spin_unlock_bh(subscriber_lock);
+}
+
+int subscr_start(void)
+{
+	struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV};
+	int res = -1;
+
+	memset(&topsrv, 0, sizeof (topsrv));
+	topsrv.lock = SPIN_LOCK_UNLOCKED;
+	INIT_LIST_HEAD(&topsrv.subscriber_list);
+
+	spin_lock_bh(&topsrv.lock);
+	res = tipc_attach(&topsrv.user_ref, 0, 0);
+	if (res) {
+		spin_unlock_bh(&topsrv.lock);
+		return res;
+	}
+
+ 	res = tipc_createport(topsrv.user_ref,
+ 			      0,
+ 			      TIPC_CRITICAL_IMPORTANCE,
+ 			      0,
+ 			      0,
+ 			      0,
+ 			      0,
+ 			      subscr_named_msg_event,
+ 			      0,
+ 			      0,
+ 			      &topsrv.setup_port);
+ 	if (res)
+		goto failed;
+
+ 	res = nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq);
+ 	if (res)
+		goto failed;
+
+	spin_unlock_bh(&topsrv.lock);
+	return 0;
+
+failed:
+	err("Failed to create subscription service\n");
+	tipc_detach(topsrv.user_ref);
+	topsrv.user_ref = 0;
+	spin_unlock_bh(&topsrv.lock);
+	return res;
+}
+
+void subscr_stop(void)
+{
+	struct subscriber *subscriber;
+	struct subscriber *subscriber_temp;
+	spinlock_t *subscriber_lock;
+
+	if (topsrv.user_ref) {
+		tipc_deleteport(topsrv.setup_port);
+		list_for_each_entry_safe(subscriber, subscriber_temp, 
+					 &topsrv.subscriber_list,
+					 subscriber_list) {
+			ref_lock(subscriber->ref);
+			subscriber_lock = subscriber->lock;
+			subscr_terminate(subscriber);
+			spin_unlock_bh(subscriber_lock);
+		}
+		tipc_detach(topsrv.user_ref);
+		topsrv.user_ref = 0;
+	}
+}
+
+
+int tipc_ispublished(struct tipc_name const *name)
+{
+	u32 domain = 0;
+
+	return(nametbl_translate(name->type, name->instance,&domain) != 0);
+}
+
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
new file mode 100644
index 0000000..ccff4ef
--- /dev/null
+++ b/net/tipc/subscr.h
@@ -0,0 +1,80 @@
+/*
+ * net/tipc/subscr.h: Include file for TIPC subscription service
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_SUBSCR_H
+#define _TIPC_SUBSCR_H
+
+/**
+ * struct subscription - TIPC network topology subscription object
+ * @seq: name sequence associated with subscription
+ * @timeout: duration of subscription (in ms)
+ * @filter: event filtering to be done for subscription
+ * @evt: template for events generated by subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @nameseq_list: adjacent subscriptions in name sequence's subscription list
+ * @timer_ref: reference to timer governing subscription duration (may be NULL)
+ * @owner: pointer to subscriber object associated with this subscription
+ */
+ 
+struct subscription {
+	struct tipc_name_seq seq;
+	u32 timeout;
+	u32 filter;
+	struct tipc_event evt;
+	struct list_head subscription_list;
+	struct list_head nameseq_list;
+	struct timer_list timer;
+	struct subscriber *owner;
+};
+
+int subscr_overlap(struct subscription * sub, 
+		   u32 found_lower, 
+		   u32 found_upper);
+
+void subscr_report_overlap(struct subscription * sub, 
+			   u32 found_lower, 
+			   u32 found_upper,
+			   u32 event, 
+			   u32 port_ref, 
+			   u32 node,
+			   int must_report);
+
+int subscr_start(void);
+
+void subscr_stop(void);
+
+
+#endif
diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c
new file mode 100644
index 0000000..35ec7dc
--- /dev/null
+++ b/net/tipc/user_reg.c
@@ -0,0 +1,265 @@
+/*
+ * net/tipc/user_reg.c: TIPC user registry code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "user_reg.h"
+
+/*
+ * TIPC user registry keeps track of users of the tipc_port interface.
+ *
+ * The registry utilizes an array of "TIPC user" entries; 
+ * a user's ID is the index of their associated array entry.
+ * Array entry 0 is not used, so userid 0 is not valid;
+ * TIPC sometimes uses this value to denote an anonymous user.
+ * The list of free entries is initially chained from last entry to entry 1.
+ */
+
+/**
+ * struct tipc_user - registered TIPC user info
+ * @next: index of next free registry entry (or -1 for an allocated entry)
+ * @callback: ptr to routine to call when TIPC mode changes (NULL if none)
+ * @usr_handle: user-defined value passed to callback routine 
+ * @ports: list of user ports owned by the user
+ */
+
+struct tipc_user {
+	int next;
+	tipc_mode_event callback;
+	void *usr_handle;
+	struct list_head ports;
+};
+
+#define MAX_USERID 64
+#define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
+
+static struct tipc_user *users = 0;
+static u32 next_free_user = MAX_USERID + 1;
+static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * reg_init - create TIPC user registry (but don't activate it)
+ * 
+ * If registry has been pre-initialized it is left "as is".
+ * NOTE: This routine may be called when TIPC is inactive.
+ */
+
+static int reg_init(void)
+{
+	u32 i;
+	
+	spin_lock_bh(&reg_lock);
+	if (!users) {
+		users = (struct tipc_user *)kmalloc(USER_LIST_SIZE, GFP_ATOMIC);
+		if (users) {
+			memset(users, 0, USER_LIST_SIZE);
+			for (i = 1; i <= MAX_USERID; i++) {
+				users[i].next = i - 1;
+			}
+			next_free_user = MAX_USERID;
+		}
+	}
+	spin_unlock_bh(&reg_lock);
+	return users ? TIPC_OK : -ENOMEM;
+}
+
+/**
+ * reg_callback - inform TIPC user about current operating mode
+ */
+
+static void reg_callback(struct tipc_user *user_ptr)
+{
+	tipc_mode_event cb;
+	void *arg;
+
+	spin_lock_bh(&reg_lock);
+	cb = user_ptr->callback;
+	arg = user_ptr->usr_handle;
+	spin_unlock_bh(&reg_lock);
+
+	if (cb)
+		cb(arg, tipc_mode, tipc_own_addr);
+}
+
+/**
+ * reg_start - activate TIPC user registry
+ */
+
+int reg_start(void)
+{
+	u32 u;
+	int res;
+
+	if ((res = reg_init()))
+		return res;
+
+	for (u = 1; u <= MAX_USERID; u++) {
+		if (users[u].callback)
+			k_signal((Handler)reg_callback,
+				 (unsigned long)&users[u]);
+	}
+	return TIPC_OK;
+}
+
+/**
+ * reg_stop - shut down & delete TIPC user registry
+ */
+
+void reg_stop(void)
+{               
+	int id;
+
+	if (!users)
+		return;
+
+	for (id = 1; id <= MAX_USERID; id++) {
+		if (users[id].callback)
+			reg_callback(&users[id]);
+	}
+	kfree(users);
+	users = 0;
+}
+
+/**
+ * tipc_attach - register a TIPC user
+ *
+ * NOTE: This routine may be called when TIPC is inactive.
+ */
+
+int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle)
+{
+	struct tipc_user *user_ptr;
+
+	if ((tipc_mode == TIPC_NOT_RUNNING) && !cb)
+		return -ENOPROTOOPT;
+	if (!users)
+		reg_init();
+
+	spin_lock_bh(&reg_lock);
+	if (!next_free_user) {
+		spin_unlock_bh(&reg_lock);
+		return -EBUSY;
+	}
+	user_ptr = &users[next_free_user];
+	*userid = next_free_user;
+	next_free_user = user_ptr->next;
+	user_ptr->next = -1; 
+	spin_unlock_bh(&reg_lock);
+
+	user_ptr->callback = cb;
+	user_ptr->usr_handle = usr_handle;
+	INIT_LIST_HEAD(&user_ptr->ports);
+	atomic_inc(&tipc_user_count);
+	
+	if (cb && (tipc_mode != TIPC_NOT_RUNNING))
+		k_signal((Handler)reg_callback, (unsigned long)user_ptr);
+	return TIPC_OK;
+}
+
+/**
+ * tipc_detach - deregister a TIPC user
+ */
+
+void tipc_detach(u32 userid)
+{
+	struct tipc_user *user_ptr;
+	struct list_head ports_temp;
+	struct user_port *up_ptr, *temp_up_ptr;
+
+	if ((userid == 0) || (userid > MAX_USERID))
+		return;
+
+	spin_lock_bh(&reg_lock);
+	if ((!users) || (users[userid].next >= 0)) {
+		spin_unlock_bh(&reg_lock);
+		return;
+	}
+
+	user_ptr = &users[userid];
+        user_ptr->callback = NULL;              
+	INIT_LIST_HEAD(&ports_temp);
+        list_splice(&user_ptr->ports, &ports_temp);
+	user_ptr->next = next_free_user;
+	next_free_user = userid;
+	spin_unlock_bh(&reg_lock);
+
+	atomic_dec(&tipc_user_count);
+
+        list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) {
+		tipc_deleteport(up_ptr->ref);
+	}
+}
+
+/**
+ * reg_add_port - register a user's driver port
+ */
+
+int reg_add_port(struct user_port *up_ptr)
+{
+	struct tipc_user *user_ptr;
+
+	if (up_ptr->user_ref == 0)
+		return TIPC_OK;
+	if (up_ptr->user_ref > MAX_USERID)
+		return -EINVAL;
+	if ((tipc_mode == TIPC_NOT_RUNNING) || !users )
+		return -ENOPROTOOPT;
+
+	spin_lock_bh(&reg_lock);
+	user_ptr = &users[up_ptr->user_ref];
+	list_add(&up_ptr->uport_list, &user_ptr->ports);
+	spin_unlock_bh(&reg_lock);
+	return TIPC_OK;
+}
+
+/**
+ * reg_remove_port - deregister a user's driver port
+ */
+
+int reg_remove_port(struct user_port *up_ptr)
+{
+	if (up_ptr->user_ref == 0)
+		return TIPC_OK;
+	if (up_ptr->user_ref > MAX_USERID)
+		return -EINVAL;
+	if (!users )
+		return -ENOPROTOOPT;
+
+	spin_lock_bh(&reg_lock);
+	list_del_init(&up_ptr->uport_list);
+	spin_unlock_bh(&reg_lock);
+	return TIPC_OK;
+}
+
diff --git a/net/tipc/user_reg.h b/net/tipc/user_reg.h
new file mode 100644
index 0000000..122ca9b
--- /dev/null
+++ b/net/tipc/user_reg.h
@@ -0,0 +1,48 @@
+/*
+ * net/tipc/user_reg.h: Include file for TIPC user registry code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_USER_REG_H
+#define _TIPC_USER_REG_H
+
+#include "port.h"
+
+int reg_start(void);
+void reg_stop(void);
+
+int reg_add_port(struct user_port *up_ptr);
+int reg_remove_port(struct user_port *up_ptr);
+
+#endif
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
new file mode 100644
index 0000000..4eaef66
--- /dev/null
+++ b/net/tipc/zone.c
@@ -0,0 +1,169 @@
+/*
+ * net/tipc/zone.c: TIPC zone management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "zone.h"
+#include "net.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "cluster.h"
+#include "node.h"
+
+struct _zone *zone_create(u32 addr)
+{
+	struct _zone *z_ptr = 0;
+	u32 z_num;
+
+	if (!addr_domain_valid(addr))
+		return 0;
+
+	z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
+	if (z_ptr != NULL) {
+		memset(z_ptr, 0, sizeof(*z_ptr));
+		z_num = tipc_zone(addr);
+		z_ptr->addr = tipc_addr(z_num, 0, 0);
+		net.zones[z_num] = z_ptr;
+	}
+	return z_ptr;
+}
+
+void zone_delete(struct _zone *z_ptr)
+{
+	u32 c_num;
+
+	if (!z_ptr)
+		return;
+	for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+		cluster_delete(z_ptr->clusters[c_num]);
+	}
+	kfree(z_ptr);
+}
+
+void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr)
+{
+	u32 c_num = tipc_cluster(c_ptr->addr);
+
+	assert(c_ptr->addr);
+	assert(c_num <= tipc_max_clusters);
+	assert(z_ptr->clusters[c_num] == 0);
+	z_ptr->clusters[c_num] = c_ptr;
+}
+
+void zone_remove_as_router(struct _zone *z_ptr, u32 router)
+{
+	u32 c_num;
+
+	for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+		if (z_ptr->clusters[c_num]) {
+			cluster_remove_as_router(z_ptr->clusters[c_num], 
+						 router);
+		}
+	}
+}
+
+void zone_send_external_routes(struct _zone *z_ptr, u32 dest)
+{
+	u32 c_num;
+
+	for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+		if (z_ptr->clusters[c_num]) {
+			if (in_own_cluster(z_ptr->addr))
+				continue;
+			cluster_send_ext_routes(z_ptr->clusters[c_num], dest);
+		}
+	}
+}
+
+struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
+{
+	struct cluster *c_ptr;
+	struct node *n_ptr;
+	u32 c_num;
+
+	if (!z_ptr)
+		return 0;
+	c_ptr = z_ptr->clusters[tipc_cluster(addr)];
+	if (!c_ptr)
+		return 0;
+	n_ptr = cluster_select_node(c_ptr, ref);
+	if (n_ptr)
+		return n_ptr;
+
+	/* Links to any other clusters within this zone ? */
+	for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+		c_ptr = z_ptr->clusters[c_num];
+		if (!c_ptr)
+			return 0;
+		n_ptr = cluster_select_node(c_ptr, ref);
+		if (n_ptr)
+			return n_ptr;
+	}
+	return 0;
+}
+
+u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
+{
+	struct cluster *c_ptr;
+	u32 c_num;
+	u32 router;
+
+	if (!z_ptr)
+		return 0;
+	c_ptr = z_ptr->clusters[tipc_cluster(addr)];
+	router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
+	if (router)
+		return router;
+
+	/* Links to any other clusters within the zone? */
+	for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+		c_ptr = z_ptr->clusters[c_num];
+		router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
+		if (router)
+			return router;
+	}
+	return 0;
+}
+
+
+u32 zone_next_node(u32 addr)
+{
+	struct cluster *c_ptr = cluster_find(addr);
+
+	if (c_ptr)
+		return cluster_next_node(c_ptr, addr);
+	return 0;
+}
+
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
new file mode 100644
index 0000000..4326f78
--- /dev/null
+++ b/net/tipc/zone.h
@@ -0,0 +1,71 @@
+/*
+ * net/tipc/zone.h: Include file for TIPC zone management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 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. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_ZONE_H
+#define _TIPC_ZONE_H
+
+#include "node_subscr.h"
+#include "net.h"
+
+
+/**
+ * struct _zone - TIPC zone structure
+ * @addr: network address of zone
+ * @clusters: array of pointers to all clusters within zone
+ * @links: (used for inter-zone communication)
+ */
+ 
+struct _zone {
+	u32 addr;
+	struct cluster *clusters[2]; /* currently limited to just 1 cluster */
+	u32 links;
+};
+
+struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
+u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
+void zone_remove_as_router(struct _zone *z_ptr, u32 router);
+void zone_send_external_routes(struct _zone *z_ptr, u32 dest);
+struct _zone *zone_create(u32 addr);
+void zone_delete(struct _zone *z_ptr);
+void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr);
+u32 zone_next_node(u32 addr);
+
+static inline struct _zone *zone_find(u32 addr)
+{
+	return net.zones[tipc_zone(addr)];
+}
+
+#endif
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 12e4fb7..53d6c7b 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -494,8 +494,7 @@
 				       char *name1, char *name2)
 {
 	if (!ipv6_addr_any(addr))
-		audit_log_format(ab, " %s=%04x:%04x:%04x:%04x:%04x:"
-				 "%04x:%04x:%04x", name1, NIP6(*addr));
+		audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr));
 	if (port)
 		audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
@@ -504,7 +503,7 @@
 				       __be16 port, char *name1, char *name2)
 {
 	if (addr)
-		audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
+		audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr));
 	if (port)
 		audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6647204..b9f8d97 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1019,7 +1019,7 @@
    has the same SID as the process.  If av is zero, then
    access to the file is not checked, e.g. for cases
    where only the descriptor is affected like seek. */
-static inline int file_has_perm(struct task_struct *tsk,
+static int file_has_perm(struct task_struct *tsk,
 				struct file *file,
 				u32 av)
 {
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
index a4ecab2f..849b59f 100644
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -515,7 +515,7 @@
 	return 0;
 }
 
-static inline int prog_dmabuf_dac(struct solo1_state *s)
+static int prog_dmabuf_dac(struct solo1_state *s)
 {
 	unsigned long va;
 	int c;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 9ffb600..3747a43 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -727,7 +727,7 @@
 	apu_data_set(chip, data);
 }
 
-static inline void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
+static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
 {
 	unsigned long flags;
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -743,7 +743,7 @@
 	return __maestro_read(chip, IDR0_DATA_PORT);
 }
 
-static inline u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
+static u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
 {
 	unsigned long flags;
 	u16 v;