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

diff -urN linux-2.4.21-bk3/Documentation/Configure.help linux-2.4.21-bk4/Documentation/Configure.help
--- linux-2.4.21-bk3/Documentation/Configure.help	2003-07-08 02:59:24.000000000 -0700
+++ linux-2.4.21-bk4/Documentation/Configure.help	2003-07-08 02:59:37.000000000 -0700
@@ -12,8 +12,8 @@
 #     <http://nevod.perm.su/service/linux/doc/kernel/Configure.help>
 #   - French, by Pierre Tane <mailto:tanep@bigfoot.com>, at
 #     <http://www.traduc.org/kernelfr/>
-#   - Polish, by Dominik Mierzejewski <mailto:dmierzej@elka.pw.edu.pl>, at
-#     <http://home.elka.pw.edu.pl/~dmierzej/linux/kernel/>
+#   - Polish, by Dominik Mierzejewski <mailto:dominik@piorunek.pl>, at
+#     <http://www.piorunek.pl/~dominik/linux/kernel/>
 #   - German, by SuSE, at <http://www.suse.de/~ke/kernel/>. This patch
 #     also includes infrastructure to support different languages.
 #   - Catalan, by Antoni Bella <mailto:bella5@teleline.es>, at
@@ -12886,10 +12886,18 @@
   If you say Y here, you will be able to set per user limits for disk
   usage (also called disk quotas). Currently, it works only for the
   ext2 file system. You need additional software in order to use quota
-  support; for details, read the Quota mini-HOWTO, available from
+  support (you can download sources from
+  <http://www.sf.net/projects/linuxquota/>). For further details, read
+  the Quota mini-HOWTO, available from
   <http://www.tldp.org/docs.html#howto>. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
+VFS v0 quota format support
+CONFIG_QFMT_V2
+  This quota format allows using quotas with 32-bit UIDs/GIDs. If you
+  need this functionality say Y here. Note that you will need latest
+  quota utilities for new quota format with this kernel.
+
 Memory Technology Device (MTD) support
 CONFIG_MTD
   Memory Technology Devices are flash, RAM and similar chips, often
diff -urN linux-2.4.21-bk3/Documentation/arm/SA1100/CERF linux-2.4.21-bk4/Documentation/arm/SA1100/CERF
--- linux-2.4.21-bk3/Documentation/arm/SA1100/CERF	2000-08-13 09:58:24.000000000 -0700
+++ linux-2.4.21-bk4/Documentation/arm/SA1100/CERF	2003-07-08 02:59:37.000000000 -0700
@@ -1,23 +1,28 @@
-The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board that measures 
-approximately 2" square. It includes an Ethernet controller, an RS232-compatible serial port, a
-USB function port, and one CompactFlash+ slot on the back. Pictures can be found at the
+The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board
+that measures approximately 2" square. It includes an Ethernet
+controller, an RS232-compatible serial port, a USB function port, and
+one CompactFlash+ slot on the back. Pictures can be found at the
 Intrinsyc website, http://www.intrinsyc.com.
 
-This document describes the support in the Linux kernel for the Intrinsyc CerfBoard as of
-version 2.4.0-test4-np1.
+This document describes the support in the Linux kernel for the
+Intrinsyc CerfBoard as of version 2.4.0-test4-np1.
 
 Supported in this version:
-   - CompactFlash+ slot (select PCMCIA in General Setup and any options that may be required)
-   - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in Network Devices)
+   - CompactFlash+ slot (select PCMCIA in General Setup and any options
+     that may be required)
+   - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in
+     Network Devices)
    - Serial ports with a serial console (hardcoded to 38400 8N1)
 
 Not supported in this version (yet):
    - LCD driver/touchscreen interface
-   - UDC (a driver exists right now, but is unstable and slow and only works with the Linux USB)
+   - UDC (a driver exists right now, but is unstable and slow and only
+     works with the Linux USB)
 
-In order to get this kernel onto your Cerf, you need a server that runs both BOOTP and
-TFTP. Detailed instructions should have come with your evaluation kit on how to use the
-bootloader. This series of commands will suffice:
+In order to get this kernel onto your Cerf, you need a server that runs
+both BOOTP and TFTP. Detailed instructions should have come with your
+evaluation kit on how to use the bootloader. This series of commands
+will suffice:
 
    make cerf_config
    make xconfig
@@ -25,10 +30,9 @@
    make zImage
    cp arch/arm/boot/zImage <TFTP directory>
 
-The default config uses a 4MB RAM disk located at 0xc0500000 as root. Setting the board to
-mount root from a NFS partition works, too.
+The default config uses a 4MB RAM disk located at 0xc0500000 as root.
+Setting the board to mount root from a NFS partition works, too.
 
 
 I-Gene Leong, Intrinsyc Software Inc.
 ileong@intrinsyc.com
-
diff -urN linux-2.4.21-bk3/Documentation/filesystems/befs.txt linux-2.4.21-bk4/Documentation/filesystems/befs.txt
--- linux-2.4.21-bk3/Documentation/filesystems/befs.txt	2002-11-28 15:53:08.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/filesystems/befs.txt	2003-07-08 02:59:37.000000000 -0700
@@ -18,32 +18,35 @@
 AUTHOR
 =====
 Current maintainer: Will Dyson <will_dyson@pobox.com>
-Has been working on the code since Aug 13, 2001. See the changelog for details.
+Has been working on the code since Aug 13, 2001. See the changelog for
+details.
 
 Original Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
-His orriginal code can still be found at: <http://hp.vector.co.jp/authors/VA008030/bfs/>
-Does anyone know of a more current email address for Makoto? He doesn't respond
-to the address given above...
+His orriginal code can still be found at:
+<http://hp.vector.co.jp/authors/VA008030/bfs/>
+Does anyone know of a more current email address for Makoto? He doesn't
+respond to the address given above...
 
 WHAT IS THIS DRIVER?
 ==================
 This module implements the native filesystem of BeOS <http://www.be.com/>
-for the linux 2.4.1 and later kernels. Currently it is a read-only implementation.
+for the linux 2.4.1 and later kernels. Currently it is a read-only
+implementation.
 
 Which is it, BFS or BEFS?
 ================
 Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS". 
-But Unixware Boot Filesystem is called bfs, too. And they are already in the
-kernel.
-Because of this nameing conflict, on Linux the BeOS filesystem is called befs.
+But Unixware Boot Filesystem is called bfs, too. And they are already in
+the kernel. Because of this nameing conflict, on Linux the BeOS
+filesystem is called befs.
 
 HOW TO INSTALL
 ==============
 step 1.  Install the BeFS  patch into the source code tree of linux.
 
 Apply the patchfile to your kernel source tree.
-Assuming that your kernel source is in /foo/bar/linux and the patchfile is called
-patch-befs-xxx, you would do the following:
+Assuming that your kernel source is in /foo/bar/linux and the patchfile
+is called patch-befs-xxx, you would do the following:
 
 	cd /foo/bar/linux
 	patch -p1 < /path/to/patch-befs-xxx
@@ -66,8 +69,9 @@
 The BeFS module is not a standard part of the linux kernel, so you must first
 enable support for experimental code under the "Code maturity level" menu.
 
-Then, under the "Filesystems" menu will be an option called "BeFS filesystem (experimental)",
-or something like that. Enable that option (it is fine to make it a module).
+Then, under the "Filesystems" menu will be an option called "BeFS
+filesystem (experimental)", or something like that. Enable that option
+(it is fine to make it a module).
 
 Save your kernel configuration and then build your kernel.
 
diff -urN linux-2.4.21-bk3/Documentation/ia64/efirtc.txt linux-2.4.21-bk4/Documentation/ia64/efirtc.txt
--- linux-2.4.21-bk3/Documentation/ia64/efirtc.txt	2001-02-08 16:32:44.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/ia64/efirtc.txt	2003-07-08 02:59:37.000000000 -0700
@@ -12,13 +12,13 @@
 to get access to the Time Service offered by EFI version 0.92.
 
 EFI provides 4 calls one can make once the OS is booted: GetTime(),
-SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this driver.
-We describe those calls as well the design of the driver in the following
-sections.
+SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this
+driver. We describe those calls as well the design of the driver in the
+following sections.
 
 II/ Design Decisions
 
-The original ideas was to provide a very simple  driver to get access to, 
+The original ideas was to provide a very simple driver to get access to, 
 at first, the time of day service. This is required in order to access, in a 
 portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock 
 to initialize the system view of the time during boot.
@@ -39,8 +39,8 @@
 without necessarily impacting any of the user applications. The decoupling
 enables flexibility and permits writing wrapper code is ncase things change.
 
-The driver exposes two interfaces, one via the device file and a set of ioctl()s.
-The other is read-only via the /proc filesystem. 
+The driver exposes two interfaces, one via the device file and a set of
+ioctl()s. The other is read-only via the /proc filesystem. 
 
 As of today we don't offer a /proc/sys interface.
 
diff -urN linux-2.4.21-bk3/Documentation/s390/c7000.txt linux-2.4.21-bk4/Documentation/s390/c7000.txt
--- linux-2.4.21-bk3/Documentation/s390/c7000.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/s390/c7000.txt	2003-07-08 02:59:37.000000000 -0700
@@ -0,0 +1,92 @@
+Cisco 7000 (CLAW) support
+
+The c7000 module provides support for a channel attached Cisco 7xxx
+family router on Linux/390.  The parameters for the module are as follows:
+
+	base0=0xYYYY	This parameter defines the base unit address of the
+			channel attached router.
+
+	lhost0=s1    	This parameter defines the local host name and
+			must match the claw directive "host-name" field
+			(first string).  The default value is "UTS".
+
+	uhost0=s2	This parameter defines the unit's name and must
+			match the claw directive "device-name" field
+			(second string).  The default value is "C7011".
+
+	lappl0=s3	This parameter defines the local application name
+			and must match the claw directive "host-app" field
+			(third string).  The default value is "TCPIP".
+
+	uappl0=s4	This parameter defines the unit application name and
+			must match the claw directive "device-app" field
+			(fourth string).  The default value is "TCPIP".
+
+	dbg=x		This parameter defines the message level.  Higher
+			numbers will result in additional diagnostic messages.
+			The default value is 0.
+
+	noauto=z	This parameter controls the automatic detection of
+			the unit base address (base0).  When set to a non
+			zero value, automatic detection of unit base addresses
+			is not done.  The default value is 0.
+
+Note that the values coded in strings s1 - s4 are case sensitive.
+
+For example, assume that the following claw directive has been coded in
+the Cisco router:
+
+claw 0100 6C 129.212.61.101 UTS C7011 TCPIP TCPIP
+
+The module can be loaded using the following command:
+
+insmod c7000 base0=0x336c lhost0="UTS" uhost0="C7011" lappl0="TCPIP" \
+uappl0="TCPIP" dbg=0 noauto=1
+
+Additional interfaces can be defined via parameters base1 - base3,
+lhost1 - lhost3, lappl1 - lappl3, uhost1 - uhost3, uappl1 - uappl3.
+The interfaces are named "ci0" - "ci3".  After loading the module, the
+ifconfig command is used to configure the interface.  For example:
+
+ifconfig ci0 129.212.61.101
+ifconfig ci0 netmask 255.255.255.0 broadcast 129.212.61.0
+ifconfig ci0
+
+The route command is used to specify the router as the default route:
+
+route add default gw 129.212.61.200
+
+The interface can be automatically activated at boot time by following this
+procedure:
+
+1) Add the following two lines to file "/etc/conf.modules":
+
+alias ci0 c7000
+options c7000 base0=0xYYYY lhost0=s1 uhost0=s2 lappl0=s3 uappl0=s4
+
+2) Edit file "/etc/sysconfig/network" as follows:
+
+NETWORKING=yes
+FORWARD_IPV4=no
+HOSTNAME=your-hostname
+GATEWAYDEV=ci0
+GATEWAY=your-gateway-ip-address
+
+Substitute your own host name and gateway IP address.
+
+3) Create a file in directory "/etc/sysconfig/network-scripts" called
+"ifcfg-ci0".  The contents are as follows:
+
+DEVICE=ci0
+USERCTL=no
+ONBOOT=yes
+BOOTPROTO=none
+BROADCAST=your-broadcast-ip-address
+NETWORK=your-network-address
+NETMASK=your-netmask
+IPADDR=your-ip-address
+
+Substitute your IP address, broadcast IP address, network address and
+network mask.
+
+4) chmod +x ifcfg-ci0
diff -urN linux-2.4.21-bk3/Documentation/sound/Introduction linux-2.4.21-bk4/Documentation/sound/Introduction
--- linux-2.4.21-bk3/Documentation/sound/Introduction	2001-02-16 15:53:08.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/sound/Introduction	2003-07-08 02:59:37.000000000 -0700
@@ -80,7 +80,7 @@
     additional features.
 
 2.  The commercial OSS driver may be obtained from the site:
-    http://www/opensound.com.  This may be used for cards that
+    http://www.opensound.com.  This may be used for cards that
     are unsupported by the kernel driver, or may be used
     by other operating systems.  
 
diff -urN linux-2.4.21-bk3/Documentation/sound/OPL3-SA linux-2.4.21-bk4/Documentation/sound/OPL3-SA
--- linux-2.4.21-bk3/Documentation/sound/OPL3-SA	2000-03-08 11:37:03.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/sound/OPL3-SA	2003-07-08 02:59:37.000000000 -0700
@@ -34,7 +34,7 @@
 	mpu_irq: This is the MPU401's IRQ.
 
 If you'd like to use the OPL3 FM Synthesizer, make sure you enable
-CONFIG_YM3812 (in 'make config'). That'll build the opl3.o module.
+CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module.
 
 Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
 
diff -urN linux-2.4.21-bk3/Documentation/sound/VIBRA16 linux-2.4.21-bk4/Documentation/sound/VIBRA16
--- linux-2.4.21-bk3/Documentation/sound/VIBRA16	1999-03-07 15:22:06.000000000 -0800
+++ linux-2.4.21-bk4/Documentation/sound/VIBRA16	2003-07-08 02:59:37.000000000 -0700
@@ -62,7 +62,7 @@
 
 	Or, take the hard way:
 
-insmod souncore
+insmod soundcore
 insmod sound
 insmod uart401
 insmod sb io=0x220 irq=5 dma=1 dma16=3
diff -urN linux-2.4.21-bk3/Makefile linux-2.4.21-bk4/Makefile
--- linux-2.4.21-bk3/Makefile	2003-07-08 02:59:25.000000000 -0700
+++ linux-2.4.21-bk4/Makefile	2003-07-08 02:59:37.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -bk3
+EXTRAVERSION = -bk4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.21-bk3/arch/i386/kernel/Makefile linux-2.4.21-bk4/arch/i386/kernel/Makefile
--- linux-2.4.21-bk3/arch/i386/kernel/Makefile	2003-07-08 02:59:25.000000000 -0700
+++ linux-2.4.21-bk4/arch/i386/kernel/Makefile	2003-07-08 02:59:38.000000000 -0700
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 
-export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o
+export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o setup.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
diff -urN linux-2.4.21-bk3/arch/i386/kernel/setup.c linux-2.4.21-bk4/arch/i386/kernel/setup.c
--- linux-2.4.21-bk3/arch/i386/kernel/setup.c	2003-07-08 02:59:25.000000000 -0700
+++ linux-2.4.21-bk4/arch/i386/kernel/setup.c	2003-07-08 02:59:38.000000000 -0700
@@ -107,6 +107,7 @@
 #include <linux/seq_file.h>
 #include <asm/processor.h>
 #include <linux/console.h>
+#include <linux/module.h>
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -175,10 +176,11 @@
 static u32 disabled_x86_caps[NCAPINTS] __initdata = { 0 };
 
 #ifdef CONFIG_ACPI_HT_ONLY
-int acpi_disabled __initdata = 1;
+int acpi_disabled = 1;
 #else
-int acpi_disabled __initdata = 0;
+int acpi_disabled = 0;
 #endif
+EXPORT_SYMBOL(acpi_disabled);
 
 extern int blk_nohighio;
 
diff -urN linux-2.4.21-bk3/arch/ia64/ia32/sys_ia32.c linux-2.4.21-bk4/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.21-bk3/arch/ia64/ia32/sys_ia32.c	2003-07-08 02:59:26.000000000 -0700
+++ linux-2.4.21-bk4/arch/ia64/ia32/sys_ia32.c	2003-07-08 02:59:38.000000000 -0700
@@ -3852,7 +3852,7 @@
 	return result;
 }
 
-struct dqblk32 {
+struct user_dqblk32 {
 	__u32 dqb_bhardlimit;
 	__u32 dqb_bsoftlimit;
 	__u32 dqb_curblocks;
@@ -3864,43 +3864,43 @@
 };
 
 asmlinkage long
-sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr)
+sys32_quotactl(int cmd, unsigned int special, int id, caddr_t addr)
 {
 	extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t);
 	int cmds = cmd >> SUBCMDSHIFT;
 	mm_segment_t old_fs;
-	struct dqblk d;
+	struct v1c_mem_dqblk d;
 	char *spec;
 	long err;
 
 	switch (cmds) {
-	      case Q_GETQUOTA:
+	case Q_V1_GETQUOTA:
 		break;
-	      case Q_SETQUOTA:
-	      case Q_SETUSE:
-	      case Q_SETQLIM:
-		if (copy_from_user (&d, addr, sizeof(struct dqblk32)))
+	case Q_V1_SETQUOTA:
+	case Q_V1_SETUSE:
+	case Q_V1_SETQLIM:
+		if (copy_from_user(&d, addr, sizeof(struct user_dqblk32)))
 			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
 		break;
-	      default:
-		return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr);
+	default:
+		return sys_quotactl(cmd, (void *)A(special), id, addr);
 	}
 	spec = getname32((void *) A(special));
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec))
 		return err;
-	old_fs = get_fs ();
+	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
 	set_fs(old_fs);
 	putname(spec);
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_V1_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user(addr, &d, sizeof(struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user(addr, &d, sizeof(struct user_dqblk32)))
 			return -EFAULT;
 	}
 	return err;
diff -urN linux-2.4.21-bk3/arch/parisc/defpalo.conf linux-2.4.21-bk4/arch/parisc/defpalo.conf
--- linux-2.4.21-bk3/arch/parisc/defpalo.conf	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/defpalo.conf	2003-07-08 02:59:39.000000000 -0700
@@ -0,0 +1,21 @@
+# This a generic Palo configuration file.  For more information about how
+# it works try 'palo -?'.
+#
+# Most people using 'make palo' want a bootable file, usable for
+# network or tape booting for example.
+--init-tape=lifimage
+--recoverykernel=vmlinux
+
+########## Pick your ROOT here! ##########
+# You need at least one 'root='!
+#
+# If you want a root ramdisk, use the next 2 lines
+#   (Edit the ramdisk image name!!!!)
+--ramdisk=ram-disk-image-file
+--commandline=0/vmlinux HOME=/ root=/dev/ram initrd=0/ramdisk
+
+# If you want NFS root, use the following command line (Edit the HOSTNAME!!!)
+#--commandline=0/vmlinux HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
+
+# If you have root on a disk partition, use this (Edit the partition name!!!)
+#--commandline=0/vmlinux HOME=/ root=/dev/sda1
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/cache.c linux-2.4.21-bk4/arch/parisc/kernel/cache.c
--- linux-2.4.21-bk3/arch/parisc/kernel/cache.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/cache.c	2003-07-08 02:59:39.000000000 -0700
@@ -194,31 +194,69 @@
 
 void disable_sr_hashing(void)
 {
-    int srhash_type;
+	int srhash_type;
 
-    if (boot_cpu_data.cpu_type == pcxl2)
-	return; /* pcxl2 doesn't support space register hashing */
+	switch (boot_cpu_data.cpu_type) {
+	case pcx: /* We shouldn't get this far.  setup.c should prevent it. */
+		BUG();
+		return;
+
+	case pcxs:
+	case pcxt:
+	case pcxt_:
+		srhash_type = SRHASH_PCXST;
+		break;
+
+	case pcxl:
+		srhash_type = SRHASH_PCXL;
+		break;
+
+	case pcxl2: /* pcxl2 doesn't support space register hashing */
+		return;
+
+	default: /* Currently all PA2.0 machines use the same ins. sequence */
+		srhash_type = SRHASH_PA20;
+		break;
+	}
 
-    switch (boot_cpu_data.cpu_type) {
-
-    case pcx:
-	BUG(); /* We shouldn't get here. code in setup.c should prevent it */
-	return;
+	disable_sr_hashing_asm(srhash_type);
+}
 
-    case pcxs:
-    case pcxt:
-    case pcxt_:
-	srhash_type = SRHASH_PCXST;
-	break;
+void __flush_dcache_page(struct page *page)
+{
+	struct mm_struct *mm = current->active_mm;
+	struct vm_area_struct *mpnt;
 
-    case pcxl:
-	srhash_type = SRHASH_PCXL;
-	break;
+	flush_kernel_dcache_page(page_address(page));
 
-    default: /* Currently all PA2.0 machines use the same ins. sequence */
-	srhash_type = SRHASH_PA20;
-	break;
-    }
+	if (!page->mapping)
+		return;
 
-    disable_sr_hashing_asm(srhash_type);
+	for (mpnt = page->mapping->i_mmap_shared;
+	     mpnt != NULL;
+	     mpnt = mpnt->vm_next_share)
+	{
+		unsigned long off;
+
+		/*
+		 * If this VMA is not in our MM, we can ignore it.
+		 */
+		if (mpnt->vm_mm != mm)
+			continue;
+
+		if (page->index < mpnt->vm_pgoff)
+			continue;
+
+		off = page->index - mpnt->vm_pgoff;
+		if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
+			continue;
+
+		flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+
+		/* All user shared mappings should be equivalently mapped,
+		 * so once we've flushed one we should be ok
+		 */
+		break;
+	}
 }
+
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/ccio-dma.c linux-2.4.21-bk4/arch/parisc/kernel/ccio-dma.c
--- linux-2.4.21-bk3/arch/parisc/kernel/ccio-dma.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/ccio-dma.c	2003-07-08 02:59:39.000000000 -0700
@@ -805,7 +805,7 @@
 
 		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents,
 			   (unsigned long)sg_dma_address(startsg), cnt,
-			   startsg->address, startsg->length
+			   sg_virt_addr(startsg), startsg->length
 		);
 
 		/*
@@ -825,7 +825,7 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long)startsg->address;
+			unsigned long vaddr = (unsigned long) sg_virt_addr(startsg);
 			ASSERT(pdirp);
 
 			/* Since multiple Vcontig blocks could make up
@@ -878,8 +878,8 @@
 		*/
 		dma_sg = vcontig_sg = startsg;
 		dma_len = vcontig_len = vcontig_end = startsg->length;
-		vcontig_end += (unsigned long) startsg->address;
-		dma_offset = (unsigned long) startsg->address & ~IOVP_MASK;
+		vcontig_end += (unsigned long) sg_virt_addr(startsg);
+		dma_offset = (unsigned long) sg_virt_addr(startsg) & ~IOVP_MASK;
 
 		/* PARANOID: clear entries */
 		sg_dma_address(startsg) = 0;
@@ -893,7 +893,7 @@
 			unsigned long startsg_end;
 
 			startsg++;
-			startsg_end = (unsigned long)startsg->address + 
+			startsg_end = (unsigned long) sg_virt_addr(startsg) + 
 				startsg->length;
 
 			/* PARANOID: clear entries */
@@ -912,7 +912,7 @@
 			/*
 			** Append the next transaction?
 			*/
-			if(vcontig_end == (unsigned long) startsg->address) {
+			if(vcontig_end == (unsigned long) sg_virt_addr(startsg)) {
 				vcontig_len += startsg->length;
 				vcontig_end += startsg->length;
 				dma_len     += startsg->length;
@@ -981,7 +981,8 @@
 
 	/* Fast path single entry scatterlists. */
 	if(nents == 1) {
-		sg_dma_address(sglist)= ccio_map_single(dev, sglist->address,
+		sg_dma_address(sglist)= ccio_map_single(dev,
+							sg_virt_addr(sglist),
 							sglist->length, 
 							direction);
 		sg_dma_len(sglist)= sglist->length;
@@ -1043,7 +1044,7 @@
 	ioc = GET_IOC(dev);
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sglist->address, sglist->length);
+		__FUNCTION__, nents, sg_virt_address(sglist), sglist->length);
 
 #ifdef CONFIG_PROC_FS
 	ioc->usg_calls++;
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/ccio-rm-dma.c linux-2.4.21-bk4/arch/parisc/kernel/ccio-rm-dma.c
--- linux-2.4.21-bk3/arch/parisc/kernel/ccio-rm-dma.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/ccio-rm-dma.c	2003-07-08 02:59:39.000000000 -0700
@@ -118,7 +118,7 @@
 
         /* KISS: map each buffer seperately. */
 	while (nents) {
-		sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
+		sg_dma_address(sglist) = ccio_map_single(dev, sg_virt_addr(sglist), sglist->length, direction);
 		sg_dma_len(sglist) = sglist->length;
 		nents--;
 		sglist++;
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/drivers.c linux-2.4.21-bk4/arch/parisc/kernel/drivers.c
--- linux-2.4.21-bk3/arch/parisc/kernel/drivers.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/drivers.c	2003-07-08 02:59:39.000000000 -0700
@@ -9,6 +9,7 @@
  * Copyright (c) 1999 The Puffin Group
  * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
  * Copyright (c) 2001 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001,2002 Ryan Bradetich 
  * 
  * The file handles registering devices and drivers, then matching them.
  * It's the closest we get to a dating agency.
@@ -23,7 +24,6 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
-#include <asm/gsc.h>
 
 /* See comments in include/asm-parisc/pci.h */
 struct pci_dma_ops *hppa_dma_ops;
@@ -416,6 +416,7 @@
 	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
 			(iodc_data[5] << 8) | iodc_data[6];
 	dev->hpa = hpa;
+
 	name = parisc_hardware_description(&dev->id);
 	if (name) {
 		strncpy(dev->name, name, sizeof(dev->name)-1);
@@ -461,30 +462,26 @@
 #define BC_PORT_MASK 0x8
 #define BC_LOWER_PORT 0x8
 
+#define IO_STATUS 	offsetof(struct bc_module, io_status)
+
 
 #define BUS_CONVERTER(dev) \
         ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
 
 #define IS_LOWER_PORT(dev) \
-        ((gsc_readl(&((struct bc_module *)dev->hpa)->io_status) \
-                & BC_PORT_MASK) == BC_LOWER_PORT)
-
-#define READ_IO_IO_LOW(dev) \
-	(dev->id.hw_type == HPHW_IOA ? \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
-
-#define READ_IO_IO_HIGH(dev) \
-	(dev->id.hw_type == HPHW_IOA ? \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high) << 16 : \
-	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high))
+        ((__raw_readl(dev->hpa + IO_STATUS) & BC_PORT_MASK) == BC_LOWER_PORT)
 
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
 
-static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, 
-			    struct parisc_device *parent);
-
-#define FLEX_MASK (unsigned long)0xfffffffffffc0000
+#define FLEX_MASK 	(unsigned long)0xfffffffffffc0000
+#define IO_IO_LOW	offsetof(struct bc_module, io_io_low)
+#define IO_IO_HIGH	offsetof(struct bc_module, io_io_high)
+#define READ_IO_IO_LOW(dev)  (unsigned long)(signed int)__raw_readl(dev->hpa + IO_IO_LOW)
+#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)__raw_readl(dev->hpa + IO_IO_HIGH)
 
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
+                            struct parisc_device *parent);
 
 void walk_lower_bus(struct parisc_device *dev)
 {
@@ -493,15 +490,17 @@
 	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
 		return;
 
-	io_io_low = ((unsigned long)(signed int)READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
-	io_io_high = ((unsigned long)(signed int)READ_IO_IO_HIGH(dev) + ~FLEX_MASK) & FLEX_MASK;
+	if(dev->id.hw_type == HPHW_IOA) {
+		io_io_low = (unsigned long)(signed int)(READ_IO_IO_LOW(dev) << 16);
+		io_io_high = io_io_low + MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET;
+	} else {
+		io_io_low = (READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
+		io_io_high = (READ_IO_IO_HIGH(dev)+ ~FLEX_MASK) & FLEX_MASK;
+	}
 
 	walk_native_bus(io_io_low, io_io_high, dev);
 }
 
-#define MAX_NATIVE_DEVICES 64
-#define NATIVE_DEVICE_OFFSET 0x1000
-
 /**
  * walk_native_bus -- Probe a bus for devices
  * @io_io_low: Base address of this bus.
@@ -515,7 +514,7 @@
  * keyboard ports).  This problem is not yet solved.
  */
 static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
-			    struct parisc_device *parent)
+                            struct parisc_device *parent)
 {
 	int i, devices_found = 0;
 	unsigned long hpa = io_io_low;
@@ -523,7 +522,7 @@
 
 	get_node_path(parent, &path);
 	do {
-		for (i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
+		for(i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
 			struct parisc_device *dev;
 
 			/* Was the device already added by Firmware? */
@@ -539,7 +538,7 @@
 			}
 			walk_lower_bus(dev);
 		}
-	} while (!devices_found && hpa < io_io_high);
+	} while(!devices_found && hpa < io_io_high);
 }
 
 #define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
@@ -552,7 +551,7 @@
  */
 void walk_central_bus(void)
 {
-	walk_native_bus(CENTRAL_BUS_ADDR, 
+	walk_native_bus(CENTRAL_BUS_ADDR,
 			CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
 			&root);
 }
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/entry.S linux-2.4.21-bk4/arch/parisc/kernel/entry.S
--- linux-2.4.21-bk3/arch/parisc/kernel/entry.S	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/entry.S	2003-07-08 02:59:39.000000000 -0700
@@ -927,11 +927,11 @@
 	ldo		-16(%r30),%r29	/* Reference param save area */
 #endif
 
-	ldil		L%intr_restore, %r2
+	ldil		L%intr_check_sig, %r2
 	copy		%r25, %r16	/* save pt_regs */
 
 	b		handle_interruption
-	ldo		R%intr_restore(%r2), %r2
+	ldo		R%intr_check_sig(%r2), %r2
 
 
 	/*
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/hardware.c linux-2.4.21-bk4/arch/parisc/kernel/hardware.c
--- linux-2.4.21-bk3/arch/parisc/kernel/hardware.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/hardware.c	2003-07-08 02:59:39.000000000 -0700
@@ -99,8 +99,8 @@
 	{HPHW_NPROC,0x481,0x4,0x81,"Wilbur (E25)"},
 	{HPHW_NPROC,0x482,0x4,0x81,"WB-80 (E35)"},
 	{HPHW_NPROC,0x483,0x4,0x81,"WB-96 (E45)"},
-	{HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-100 (811/D210,D310)"},
-	{HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-75 (801/D200)"},
+	{HPHW_NPROC,0x484,0x4,0x81,"UL Proc L-100 (811/D210,D310)"},
+	{HPHW_NPROC,0x485,0x4,0x81,"UL Proc L-75 (801/D200)"},
 	{HPHW_NPROC,0x501,0x4,0x81,"Merlin L2 132 (9000/778/B132L)"},
 	{HPHW_NPROC,0x502,0x4,0x81,"Merlin L2 160 (9000/778/B160L)"},
 	{HPHW_NPROC,0x503,0x4,0x81,"Merlin L2+ 132 (9000/778/B132L)"},
@@ -403,7 +403,7 @@
 	{HPHW_BA, 0x01B, 0x00078, 0x0, "Anole 100 VME BA"}, 
 	{HPHW_BA, 0x024, 0x00078, 0x0, "Fast Pace VME BA"}, 
 	{HPHW_BA, 0x034, 0x00078, 0x0, "Anole T VME BA"}, 
-	{HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 BME BA"}, 
+	{HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 VME BA"}, 
 	{HPHW_BA, 0x04C, 0x00078, 0x0, "Anole L2 165 VME BA"}, 
 	{HPHW_BA, 0x011, 0x00081, 0x0, "WB-96 Core BA"}, 
 	{HPHW_BA, 0x012, 0x00081, 0x0, "Orville UX Core BA"}, 
@@ -805,8 +805,8 @@
 	{HPHW_FIO, 0x04E, 0x0007B, 0x0, "Kiji L2 132 Core Audio"}, 
 	{HPHW_FIO, 0x050, 0x0007B, 0x0, "Merlin Jr 132 Core Audio"}, 
 	{HPHW_FIO, 0x051, 0x0007B, 0x0, "Firehawk Audio"}, 
-	{HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSU Core Audio"}, 
-	{HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSU Core Audio"}, 
+	{HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSI Core Audio"}, 
+	{HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSI Core Audio"}, 
 	{HPHW_FIO, 0x058, 0x0007B, 0x0, "FireHawk 200 Audio"}, 
 	{HPHW_FIO, 0x05C, 0x0007B, 0x0, "SummitHawk 230 Core Audio"}, 
 	{HPHW_FIO, 0x800, 0x0007B, 0x0, "Hitachi Tiny 64 Audio"}, 
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/head.S linux-2.4.21-bk4/arch/parisc/kernel/head.S
--- linux-2.4.21-bk3/arch/parisc/kernel/head.S	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/head.S	2003-07-08 02:59:39.000000000 -0700
@@ -74,7 +74,7 @@
 	ldo             R%PA(_end)(%r4),%r4
 $bss_loop:
 	cmpb,<<,n       %r3,%r4,$bss_loop
-	stb,ma          %r0,1(%r3)
+	stw,ma          %r0,4(%r3)
 
 	/* Save away the arguments the boot loader passed in (32 bit args) */
 
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/ioctl32.c linux-2.4.21-bk4/arch/parisc/kernel/ioctl32.c
--- linux-2.4.21-bk3/arch/parisc/kernel/ioctl32.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/ioctl32.c	2003-07-08 02:59:39.000000000 -0700
@@ -3123,6 +3123,11 @@
 COMPATIBLE_IOCTL(SIOCDRARP)
 COMPATIBLE_IOCTL(SIOCADDDLCI)
 COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/irq.c linux-2.4.21-bk4/arch/parisc/kernel/irq.c
--- linux-2.4.21-bk3/arch/parisc/kernel/irq.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/irq.c	2003-07-08 02:59:39.000000000 -0700
@@ -57,7 +57,7 @@
 /* Bits in EIEM correlate with cpu_irq_action[].
 ** Numbered *Big Endian*! (ie bit 0 is MSB)
 */
-static unsigned long cpu_eiem = 0;
+static volatile unsigned long cpu_eiem = 0;
 
 static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;  /* protect IRQ regions */
 
@@ -462,7 +462,7 @@
 
 		for (irq = 0; eirr_val && bit; bit>>=1, irq++)
 		{
-			if (!(bit&eirr_val))
+			if (!(bit&eirr_val&cpu_eiem))
 				continue;
 
 			/* clear bit in mask - can exit loop sooner */
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/parisc_ksyms.c linux-2.4.21-bk4/arch/parisc/kernel/parisc_ksyms.c
--- linux-2.4.21-bk3/arch/parisc/kernel/parisc_ksyms.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/parisc_ksyms.c	2003-07-08 02:59:39.000000000 -0700
@@ -67,6 +67,7 @@
 
 #include <linux/smp.h>
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
 #endif /* CONFIG_SMP */
 
 #include <asm/atomic.h>
@@ -127,7 +128,13 @@
 #include <asm/cache.h>
 EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
 EXPORT_SYMBOL(flush_kernel_dcache_page);
-EXPORT_SYMBOL(flush_all_caches);
+
+/* asm/pgalloc.h doesn't include all it's dependencies */
+extern void __flush_dcache_page(struct page *page);
+EXPORT_SYMBOL(__flush_dcache_page);
+
+extern void flush_cache_all_local(void);
+EXPORT_SYMBOL(flush_cache_all_local);
 
 #include <asm/unistd.h>
 extern long sys_open(const char *, int, int);
@@ -150,6 +157,8 @@
 
 #include <asm/pdc.h>
 EXPORT_SYMBOL(pdc_add_valid);
+EXPORT_SYMBOL(pdc_tod_read);
+EXPORT_SYMBOL(pdc_tod_set);
 EXPORT_SYMBOL(pdc_lan_station_id);
 EXPORT_SYMBOL(pdc_get_initiator);
 
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/pci-dma.c linux-2.4.21-bk4/arch/parisc/kernel/pci-dma.c
--- linux-2.4.21-bk3/arch/parisc/kernel/pci-dma.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/pci-dma.c	2003-07-08 02:59:39.000000000 -0700
@@ -428,9 +428,9 @@
 	    BUG();
 
 	for (i = 0; i < nents; i++, sglist++ ) {
-		sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(sglist->address);
+		sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(sg_virt_addr(sglist));
 		sg_dma_len(sglist) = sglist->length;
-		flush_kernel_dcache_range((unsigned long)sglist->address,
+		flush_kernel_dcache_range((unsigned long)sg_virt_addr(sglist),
 				sglist->length);
 	}
 	return nents;
@@ -449,7 +449,7 @@
 	/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
 
 	for (i = 0; i < nents; i++, sglist++ )
-		flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+		flush_kernel_dcache_range((unsigned long) sg_virt_addr(sglist), sglist->length);
 	return;
 }
 
@@ -468,7 +468,7 @@
 	/* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
 
 	for (i = 0; i < nents; i++, sglist++ )
-		flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+		flush_kernel_dcache_range((unsigned long) sg_virt_addr(sglist), sglist->length);
 }
 
 struct pci_dma_ops pcxl_dma_ops = {
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/perf.c linux-2.4.21-bk4/arch/parisc/kernel/perf.c
--- linux-2.4.21-bk3/arch/parisc/kernel/perf.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/perf.c	2003-07-08 02:59:39.000000000 -0700
@@ -499,6 +499,8 @@
  */
 static int __init perf_init(void)
 {
+	int ret;
+
 	/* Determine correct processor interface to use */
 	bitmask_array = perf_bitmasks;
 
@@ -517,11 +519,17 @@
 		return -ENODEV;
 	}
 
+	ret = misc_register(&perf_dev);
+	if (ret) {
+		printk(KERN_ERR "Performance monitoring counters: "
+			"cannot register misc device.\n");
+		return ret;
+	}
+
 	/* Patch the images to match the system */
     	perf_patch_images();
 
 	spin_lock_init(&perf_lock);
-	misc_register(&perf_dev);
 
 	/* TODO: this only lets us access the first cpu.. what to do for SMP? */
 	cpu_device = cpu_data[0].dev;
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/processor.c linux-2.4.21-bk4/arch/parisc/kernel/processor.c
--- linux-2.4.21-bk3/arch/parisc/kernel/processor.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/processor.c	2003-07-08 02:59:39.000000000 -0700
@@ -77,8 +77,6 @@
 	unsigned long txn_addr;
 	unsigned long cpuid;
 	struct cpuinfo_parisc *p;
-	extern struct irq_region_ops cpu_irq_ops; /* arch/parisc...irq.c */
-	extern struct irqaction cpu_irq_actions[]; /* arch/parisc...irq.c */
 
 #ifndef CONFIG_SMP
 	if (boot_cpu_data.cpu_count > 0) {
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/sba_iommu.c linux-2.4.21-bk4/arch/parisc/kernel/sba_iommu.c
--- linux-2.4.21-bk3/arch/parisc/kernel/sba_iommu.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/sba_iommu.c	2003-07-08 02:59:39.000000000 -0700
@@ -1056,7 +1056,7 @@
 			printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n",
 				nents,
 				(unsigned long) sg_dma_address(startsg), cnt,
-				sg_virt_address(startsg), startsg->length
+				sg_virt_addr(startsg), startsg->length
 		);
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n",
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/smp.c linux-2.4.21-bk4/arch/parisc/kernel/smp.c
--- linux-2.4.21-bk3/arch/parisc/kernel/smp.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/kernel/smp.c	2003-07-08 02:59:39.000000000 -0700
@@ -33,6 +33,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/reboot.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -434,25 +435,21 @@
 	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
 
 	/* Set modes and Enable floating point coprocessor */
-	(void) init_per_cpu(cpunum);
+	init_per_cpu(cpunum);
 
 	disable_sr_hashing();
-
 	mb();
 
 	/* Well, support 2.4 linux scheme as well. */
-	if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_online_map)))
-	{
-		extern void machine_halt(void); /* arch/parisc.../process.c */
-
+	if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_online_map))) {
 		printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
 		machine_halt();
-	}  
+	}
 
 	/* Initialise the idle task for this CPU */
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
-	if(current->mm)
+	if (current->mm)
 		BUG();
 	enter_lazy_tlb(&init_mm, current, cpunum);
 
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/traps.c linux-2.4.21-bk4/arch/parisc/kernel/traps.c
--- linux-2.4.21-bk3/arch/parisc/kernel/traps.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/traps.c	2003-07-08 02:59:39.000000000 -0700
@@ -455,13 +455,6 @@
 	unsigned long fault_space = 0;
 	struct siginfo si;
 
-	/* HACK! jsm is going to fix this.
-	 * entry.S will manage I-bit - only enable I-bit if it was
-	 * enabled before we took the "trap".
-	 */
-	if (code != 1)
-		local_irq_enable();
-
 	switch(code) {
 
 	case  1:
@@ -727,6 +720,7 @@
 	    }
 	}
 
+	local_irq_enable();
 	do_page_fault(regs, code, fault_address);
 }
 
diff -urN linux-2.4.21-bk3/arch/parisc/kernel/unaligned.c linux-2.4.21-bk4/arch/parisc/kernel/unaligned.c
--- linux-2.4.21-bk3/arch/parisc/kernel/unaligned.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.21-bk4/arch/parisc/kernel/unaligned.c	2003-07-08 02:59:39.000000000 -0700
@@ -3,6 +3,7 @@
  *    Unaligned memory access handler
  *
  *    Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *    Significantly tweaked by LaMont Jones <lamont@debian.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
@@ -66,28 +67,28 @@
 #define OPCODE3_MASK	OPCODE3(0x3f,1)
 #define OPCODE4_MASK    OPCODE4(0x3f)
 
-/* skip LDB (index) */
+/* skip LDB - never unaligned (index) */
 #define OPCODE_LDH_I	OPCODE1(0x03,0,0x1)
 #define OPCODE_LDW_I	OPCODE1(0x03,0,0x2)
 #define OPCODE_LDD_I	OPCODE1(0x03,0,0x3)
 #define OPCODE_LDDA_I	OPCODE1(0x03,0,0x4)
-/* skip LDCD (index) */
+#define OPCODE_LDCD_I	OPCODE1(0x03,0,0x5)
 #define OPCODE_LDWA_I	OPCODE1(0x03,0,0x6)
-/* skip LDCW (index) */
-/* skip LDB (short) */
+#define OPCODE_LDCW_I	OPCODE1(0x03,0,0x7)
+/* skip LDB - never unaligned (short) */
 #define OPCODE_LDH_S	OPCODE1(0x03,1,0x1)
 #define OPCODE_LDW_S	OPCODE1(0x03,1,0x2)
 #define OPCODE_LDD_S	OPCODE1(0x03,1,0x3)
 #define OPCODE_LDDA_S	OPCODE1(0x03,1,0x4)
-/* skip LDCD (short) */
+#define OPCODE_LDCD_S	OPCODE1(0x03,1,0x5)
 #define OPCODE_LDWA_S	OPCODE1(0x03,1,0x6)
-/* skip LDCW (short) */
-/* skip STB */
+#define OPCODE_LDCW_S	OPCODE1(0x03,1,0x7)
+/* skip STB - never unaligned */
 #define OPCODE_STH	OPCODE1(0x03,1,0x9)
 #define OPCODE_STW	OPCODE1(0x03,1,0xa)
 #define OPCODE_STD	OPCODE1(0x03,1,0xb)
-/* skip STBY */
-/* skip STDBY */
+/* skip STBY - never unaligned */
+/* skip STDBY - never unaligned */
 #define OPCODE_STWA	OPCODE1(0x03,1,0xe)
 #define OPCODE_STDA	OPCODE1(0x03,1,0xf)
 
@@ -103,129 +104,200 @@
 
 #define OPCODE_LDH_L    OPCODE4(0x11)
 #define OPCODE_LDW_L    OPCODE4(0x12)
-#define OPCODE_LDW_L2   OPCODE4(0x13)
+#define OPCODE_LDWM     OPCODE4(0x13)
 #define OPCODE_STH_L    OPCODE4(0x19)
 #define OPCODE_STW_L    OPCODE4(0x1A)
-#define OPCODE_STW_L2   OPCODE4(0x1B)
+#define OPCODE_STWM     OPCODE4(0x1B)
+
+#define MAJOR_OP(i) (((i)>>26)&0x3f)
+#define R1(i) (((i)>>21)&0x1f)
+#define R2(i) (((i)>>16)&0x1f)
+#define R3(i) ((i)&0x1f)
+#define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
+#define IM5_2(i) IM((i)>>16,5)
+#define IM5_3(i) IM((i),5)
+#define IM14(i) IM((i),14)
 
 int unaligned_enabled = 1;
 
 void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
-static int emulate_load(struct pt_regs *regs, int len, int toreg)
+static int emulate_ldh(struct pt_regs *regs, int toreg)
 {
 	unsigned long saddr = regs->ior;
 	unsigned long val = 0;
-	int ret = 0;
 
-	if (regs->isr != regs->sr[7])
-	{
-		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
-			regs->isr, regs->sr[7]);
-		return 1;
-	}
+	DPRINTF("load " RFMT ":" RFMT " to r%d for 2 bytes\n", 
+		regs->isr, regs->ior, toreg);
+
+	__asm__ __volatile__  (
+"	mtsp	%3, %%sr1\n"
+"	ldbs	0(%%sr1,%2), %%r20\n"
+"	ldbs	1(%%sr1,%2), %0\n"
+	"depw	%%r20, 23, 24, %0\n"
+	: "=r" (val)
+	: "0" (val), "r" (saddr), "r" (regs->isr)
+	: "r20" );
+
+	DPRINTF("val = 0x" RFMT "\n", val);
+
+	if (toreg)
+		regs->gr[toreg] = val;
+
+	return 0;
+}
+static int emulate_ldw(struct pt_regs *regs, int toreg)
+{
+	unsigned long saddr = regs->ior;
+	unsigned long val = 0;
 
-	DPRINTF("load " RFMT ":" RFMT " to r%d for %d bytes\n", 
-		regs->isr, regs->ior, toreg, len);
+	DPRINTF("load " RFMT ":" RFMT " to r%d for 4 bytes\n", 
+		regs->isr, regs->ior, toreg);
 
 	__asm__ __volatile__  (
-"       mfsp %%sr1, %%r20\n"
-"       mtsp %6, %%sr1\n"
-"	copy %%r0, %0\n"
-"0:	ldbs,ma	1(%%sr1,%4), %%r19\n"
-"	addi -1, %5, %5\n"
-"	cmpib,>= 0, %5, 2f\n"
-"	or %%r19, %0, %0\n"
-"	b 0b\n"
-	
-#ifdef __LP64__
-	"depd,z %0, 55, 56, %0\n"
-#else
-	"depw,z %0, 23, 24, %0\n"
-#endif
-	
-"1:	ldi	10, %1\n"
-"2:     mtsp %%r20, %%sr1\n"
-"	.section __ex_table,\"a\"\n"
+"	zdep	%2,28,2,%%r19\n"		/* r19=(ofs&3)*8 */
+"	mtsp	%3, %%sr1\n"
+"	depw	%%r0,31,2,%2\n"
+"	ldw	0(%%sr1,%2),%0\n"
+"	ldw	4(%%sr1,%2),%%r20\n"
+"	subi	32,%%r19,%%r19\n"
+"	mtctl	%%r19,11\n"
+"	vshd	%0,%%r20,%0\n"
+	: "=r" (val)
+	: "0" (val), "r" (saddr), "r" (regs->isr)
+	: "r19", "r20" );
+
+	DPRINTF("val = 0x" RFMT "\n", val);
+
+	if (toreg)
+		regs->gr[toreg] = val;
+
+	return 0;
+}
 #ifdef __LP64__
-	".dword 0b, (1b-0b)\n"
-#else
-	".word 0b, (1b-0b)\n"
-#endif
-	".previous\n" 
-	: "=r" (val), "=r" (ret)
-	: "0" (val), "1" (ret), "r" (saddr), "r" (len), "r" (regs->isr)
+static int emulate_ldd(struct pt_regs *regs, int toreg)
+{
+	unsigned long saddr = regs->ior;
+	unsigned long val = 0;
+
+	DPRINTF("load " RFMT ":" RFMT " to r%d for 8 bytes\n", 
+		regs->isr, regs->ior, toreg);
+
+	__asm__ __volatile__  (
+"	depd,z	%2,60,3,%%r19\n"		/* r19=(ofs&7)*8 */
+"	mtsp	%3, %%sr1\n"
+"	depd	%%r0,63,3,%2\n"
+"	ldd	0(%%sr1,%2),%0\n"
+"	ldd	8(%%sr1,%2),%%r20\n"
+"	subi	64,%%r19,%%r19\n"
+"	mtsar	%%r19\n"
+"	shrpd	%0,%%r20,%%sar,%0\n"
+	: "=r" (val)
+	: "0" (val), "r" (saddr), "r" (regs->isr)
 	: "r19", "r20" );
 
 	DPRINTF("val = 0x" RFMT "\n", val);
 
-	regs->gr[toreg] = val;
+	if (toreg)
+		regs->gr[toreg] = val;
 
-	return ret;
+	return 0;
 }
+#endif
 
-static int emulate_store(struct pt_regs *regs, int len, int frreg)
+static int emulate_sth(struct pt_regs *regs, int frreg)
 {
-	int ret = 0;
-#ifdef __LP64__
-	unsigned long val = regs->gr[frreg] << (64 - (len << 3));
-#else
-	unsigned long val = regs->gr[frreg] << (32 - (len << 3));
-#endif
+	unsigned long val = regs->gr[frreg];
+	if (!frreg)
+		val = 0;
 
-	if (regs->isr != regs->sr[7])
-	{
-		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
-			regs->isr, regs->sr[7]);
-		return 1;
-	}
+	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 2 bytes\n", frreg, 
+		regs->gr[frreg], regs->isr, regs->ior);
+
+	__asm__ __volatile__ (
+"	mtsp %2, %%sr1\n"
+"	extrw,u %0, 23, 8, %%r19\n"
+"	stb %0, 1(%%sr1, %1)\n"
+"	stb %%r19, 0(%%sr1, %1)\n"
+	:
+	: "r" (val), "r" (regs->ior), "r" (regs->isr)
+	: "r19" );
+
+	return 0;
+}
+static int emulate_stw(struct pt_regs *regs, int frreg)
+{
+	unsigned long val = regs->gr[frreg];
+	if (!frreg)
+		val = 0;
 
-	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for %d bytes\n", frreg, 
-		regs->gr[frreg], regs->isr, regs->ior, len);
+	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 4 bytes\n", frreg, 
+		regs->gr[frreg], regs->isr, regs->ior);
 
 
 	__asm__ __volatile__ (
-"       mfsp %%sr1, %%r20\n"		/* save sr1 */
-"       mtsp %5, %%sr1\n"
-#ifdef __LP64__
-"0:	extrd,u %2, 7, 8, %%r19\n"
-#else
-"0:	extrw,u %2, 7, 8, %%r19\n"
-#endif
-"1:	stb,ma %%r19, 1(%%sr1, %3)\n"
-"	addi -1, %4, %4\n"
-"	cmpib,>= 0, %4, 3f\n"
-	
+"	mtsp %2, %%sr1\n"
+"	zdep	%1, 28, 2, %%r19\n"
+"	dep	%%r0, 31, 2, %1\n"
+"	mtsar	%%r19\n"
+"	depwi,z	-2, %%sar, 32, %%r19\n"
+"	ldw	0(%%sr1,%1),%%r20\n"
+"	ldw	4(%%sr1,%1),%%r21\n"
+"	vshd	%%r0, %0, %%r22\n"
+"	vshd	%0, %%r0, %%r1\n"
+"	and	%%r20, %%r19, %%r20\n"
+"	andcm	%%r21, %%r19, %%r21\n"
+"	or	%%r22, %%r20, %%r20\n"
+"	or	%%r1, %%r21, %%r21\n"
+"	stw	%%r20,0(%%sr1,%1)\n"
+"	stw	%%r21,4(%%sr1,%1)\n"
+	:
+	: "r" (val), "r" (regs->ior), "r" (regs->isr)
+	: "r19", "r20", "r21", "r22", "r1" );
+
+	return 0;
+}
 #ifdef __LP64__
-	"depd,z %2, 55, 56, %2\n"
-#else
-	"depw,z %2, 23, 24, %2\n"
-#endif
+static int emulate_std(struct pt_regs *regs, int frreg)
+{
+	unsigned long val = regs->gr[frreg];
+	if (!frreg)
+		val = 0;
 
-"	b 0b\n"
-"	nop\n"
+	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 8 bytes\n", frreg, 
+		regs->gr[frreg], regs->isr, regs->ior);
 
-"2:	ldi 11, %0\n"
-"3:     mtsp %%r20, %%sr1\n"
-"	.section __ex_table,\"a\"\n"
-#ifdef __LP64__
-	".dword 1b, (2b-1b)\n"
-#else
-	".word 1b, (2b-1b)\n"
-#endif
-	".previous\n" 
-	: "=r" (ret)
-	: "0" (ret), "r" (val), "r" (regs->ior), "r" (len), "r" (regs->isr)
-	: "r19", "r20" );
 
-	return ret;
-}
+	__asm__ __volatile__ (
+"	mtsp %2, %%sr1\n"
+"	depd,z	%1, 60, 3, %%r19\n"
+"	depd	%%r0, 63, 3, %1\n"
+"	mtsar	%%r19\n"
+"	depdi,z	-2, %%sar, 64, %%r19\n"
+"	ldd	0(%%sr1,%1),%%r20\n"
+"	ldd	8(%%sr1,%1),%%r21\n"
+"	shrpd	%%r0, %0, %%sar, %%r22\n"
+"	shrpd	%0, %%r0, %%sar, %%r1\n"
+"	and	%%r20, %%r19, %%r20\n"
+"	andcm	%%r21, %%r19, %%r21\n"
+"	or	%%r22, %%r20, %%r20\n"
+"	or	%%r1, %%r21, %%r21\n"
+"	std	%%r20,0(%%sr1,%1)\n"
+"	std	%%r21,8(%%sr1,%1)\n"
+	:
+	: "r" (val), "r" (regs->ior), "r" (regs->isr)
+	: "r19", "r20", "r21", "r22", "r1" );
 
+	return 0;
+}
+#endif
 
 void handle_unaligned(struct pt_regs *regs)
 {
 	unsigned long unaligned_count = 0;
 	unsigned long last_time = 0;
+	unsigned long newbase = regs->gr[R1(regs->iir)];
+	int modify = 0;
 	int ret = -1;
 	struct siginfo si;
 
@@ -284,83 +356,169 @@
 	if (!unaligned_enabled)
 		goto force_sigbus;
 
+	/* handle modification - OK, it's ugly, see the instruction manual */
+	switch (MAJOR_OP(regs->iir))
+	{
+	case 0x03:
+	case 0x09:
+	case 0x0b:
+		if (regs->iir&0x20)
+		{
+			modify = 1;
+			if (regs->iir&0x1000)		/* short loads */
+				if (regs->iir&0x200)
+					newbase += IM5_3(regs->iir);
+				else
+					newbase += IM5_2(regs->iir);
+			else if (regs->iir&0x2000)	/* scaled indexed */
+			{
+				int shift=0;
+				switch (regs->iir & OPCODE1_MASK)
+				{
+				case OPCODE_LDH_I:
+					shift= 1; break;
+				case OPCODE_LDW_I:
+					shift= 2; break;
+				case OPCODE_LDD_I:
+				case OPCODE_LDDA_I:
+					shift= 3; break;
+				}
+				newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0)<<shift;
+			} else				/* simple indexed */
+				newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0);
+		}
+		break;
+	case 0x13:
+	case 0x1b:
+		modify = 1;
+		newbase += IM14(regs->iir);
+		break;
+	case 0x14:
+	case 0x1c:
+		if (regs->iir&8)
+		{
+			modify = 1;
+			newbase += IM14(regs->iir&~0xe);
+		}
+		break;
+	case 0x16:
+	case 0x1e:
+		modify = 1;
+		newbase += IM14(regs->iir&6);
+		break;
+	case 0x17:
+	case 0x1f:
+		if (regs->iir&4)
+		{
+			modify = 1;
+			newbase += IM14(regs->iir&~4);
+		}
+		break;
+	}
+
+	if (regs->isr != regs->sr[7])
+	{
+		printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+			regs->isr, regs->sr[7]);
+
+		/* don't kill him though, since he has appropriate access to the page, or we
+		 * would never have gotten here.
+		 */
+	}
+
 	/* TODO: make this cleaner... */
 	switch (regs->iir & OPCODE1_MASK)
 	{
 	case OPCODE_LDH_I:
 	case OPCODE_LDH_S:
-		ret = emulate_load(regs, 2, regs->iir & 0x1f);
+		ret = emulate_ldh(regs, R3(regs->iir));
 		break;
 
 	case OPCODE_LDW_I:
 	case OPCODE_LDWA_I:
 	case OPCODE_LDW_S:
 	case OPCODE_LDWA_S:
-		ret = emulate_load(regs, 4, regs->iir&0x1f);
-		break;
-
-	case OPCODE_LDD_I:
-	case OPCODE_LDDA_I:
-	case OPCODE_LDD_S:
-	case OPCODE_LDDA_S:
-		ret = emulate_load(regs, 8, regs->iir&0x1f);
+		ret = emulate_ldw(regs, R3(regs->iir));
 		break;
 
 	case OPCODE_STH:
-		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		ret = emulate_sth(regs, R2(regs->iir));
 		break;
 
 	case OPCODE_STW:
 	case OPCODE_STWA:
-		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		ret = emulate_stw(regs, R2(regs->iir));
+		break;
+
+#ifdef __LP64__
+	case OPCODE_LDD_I:
+	case OPCODE_LDDA_I:
+	case OPCODE_LDD_S:
+	case OPCODE_LDDA_S:
+		ret = emulate_ldd(regs, R3(regs->iir));
 		break;
 
 	case OPCODE_STD:
 	case OPCODE_STDA:
-		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		ret = emulate_std(regs, R2(regs->iir));
+		break;
+#endif
+
+	case OPCODE_LDCD_I:
+	case OPCODE_LDCW_I:
+	case OPCODE_LDCD_S:
+	case OPCODE_LDCW_S:
+		ret = -1;	/* "undefined", but lets kill them. */
 		break;
 	}
+#ifdef __LP64__
 	switch (regs->iir & OPCODE2_MASK)
 	{
 	case OPCODE_LDD_L:
 	case OPCODE_FLDD_L:
-		ret = emulate_load(regs, 8, (regs->iir>>16)&0x1f);
+		ret = emulate_ldd(regs, R2(regs->iir));
 		break;
 
 	case OPCODE_STD_L:
 	case OPCODE_FSTD_L:
-		ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+		ret = emulate_std(regs, R2(regs->iir));
 		break;
 	}
+#endif
 	switch (regs->iir & OPCODE3_MASK)
 	{
 	case OPCODE_LDW_M:
 	case OPCODE_FLDW_L:
-		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+		ret = emulate_ldw(regs, R2(regs->iir));
 		break;
 
 	case OPCODE_FSTW_L:
 	case OPCODE_STW_M:
-		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+		ret = emulate_stw(regs, R2(regs->iir));
 		break;
 	}
 	switch (regs->iir & OPCODE4_MASK)
 	{
 	case OPCODE_LDH_L:
-		ret = emulate_load(regs, 2, (regs->iir>>16)&0x1f);
+		ret = emulate_ldh(regs, R2(regs->iir));
 		break;
 	case OPCODE_LDW_L:
-	case OPCODE_LDW_L2:
-		ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+	case OPCODE_LDWM:
+		ret = emulate_ldw(regs, R2(regs->iir));
 		break;
 	case OPCODE_STH_L:
-		ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+		ret = emulate_sth(regs, R2(regs->iir));
 		break;
 	case OPCODE_STW_L:
-	case OPCODE_STW_L2:
-		ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+	case OPCODE_STWM:
+		ret = emulate_stw(regs, R2(regs->iir));
 		break;
 	}
+	/* XXX LJ - need to handle float load/store */
+
+	if (modify && R1(regs->iir))
+		regs->gr[R1(regs->iir)] = newbase;
+
 
 	if (ret < 0)
 		printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
@@ -424,9 +582,9 @@
 			align_mask = 1UL;
 			break;
 		case OPCODE_LDW_L:
-		case OPCODE_LDW_L2:
+		case OPCODE_LDWM:
 		case OPCODE_STW_L:
-		case OPCODE_STW_L2:
+		case OPCODE_STWM:
 			align_mask = 3UL;
 			break;
 		}
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfadd.c linux-2.4.21-bk4/arch/parisc/math-emu/dfadd.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfadd.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfadd.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfadd.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfadd.c		$Revision: $
  *
  *  Purpose:
  *	Double_add: add two double precision values.
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfcmp.c linux-2.4.21-bk4/arch/parisc/math-emu/dfcmp.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfcmp.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfcmp.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfcmp.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfcmp.c		$Revision: $
  *
  *  Purpose:
  *	dbl_cmp: compare two values
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfdiv.c linux-2.4.21-bk4/arch/parisc/math-emu/dfdiv.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfdiv.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfdiv.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfdiv.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfdiv.c		$Revision: $
  *
  *  Purpose:
  *	Double Precision Floating-point Divide
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfmpy.c linux-2.4.21-bk4/arch/parisc/math-emu/dfmpy.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfmpy.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfmpy.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfmpy.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfmpy.c		$Revision: $
  *
  *  Purpose:
  *	Double Precision Floating-point Multiply
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfrem.c linux-2.4.21-bk4/arch/parisc/math-emu/dfrem.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfrem.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfrem.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfrem.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfrem.c		$Revision: $
  *
  *  Purpose:
  *	Double Precision Floating-point Remainder
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfsqrt.c linux-2.4.21-bk4/arch/parisc/math-emu/dfsqrt.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfsqrt.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfsqrt.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfsqrt.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfsqrt.c		$Revision: $
  *
  *  Purpose:
  *	Double Floating-point Square Root
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/dfsub.c linux-2.4.21-bk4/arch/parisc/math-emu/dfsub.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/dfsub.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/dfsub.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/dfsub.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/dfsub.c		$Revision: $
  *
  *  Purpose:
  *	Double_subtract: subtract two double precision values.
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/driver.c linux-2.4.21-bk4/arch/parisc/math-emu/driver.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/driver.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/driver.c	2003-07-08 02:59:39.000000000 -0700
@@ -80,14 +80,19 @@
 int
 handle_fpe(struct pt_regs *regs)
 {
-	extern void printbinary(unsigned long x, int nbits);
+	extern int printbinary(char *buf, unsigned long x, int nbits);
 	struct siginfo si;
 	unsigned int orig_sw, sw;
 	int signalcode;
+	char buf[128];
 	/* need an intermediate copy of float regs because FPU emulation
 	 * code expects an artificial last entry which contains zero
+	 *
+	 * also, the passed in fr registers contain one word that defines
+	 * the fpu type. the fpu type information is constructed 
+	 * inside the emulation code
 	 */
-	__u64 frcopy[33];
+	__u64 frcopy[36];
 
 	memcpy(frcopy, regs->fr, sizeof regs->fr);
 	frcopy[32] = 0;
@@ -96,8 +101,8 @@
 
 	if (FPUDEBUG) {
 		printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n   ");
-		printbinary(orig_sw, 32);
-		printk(KERN_DEBUG "\n");
+		printbinary(buf, orig_sw, 32);
+		printk(KERN_DEBUG "%s\n", buf);
 	}
 
 	signalcode = decode_fpu(frcopy, 0x666);
@@ -107,8 +112,8 @@
 	if (FPUDEBUG) {
 		printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",
 			signalcode >> 24, signalcode & 0xffffff);
-		printbinary(sw, 32);
-		printk(KERN_DEBUG "\n");
+		printbinary(buf, sw, 32);
+		printk(KERN_DEBUG "%s\n", buf);
 	}
 
 	memcpy(regs->fr, frcopy, sizeof regs->fr);
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvff.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvff.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvff.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvff.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvff.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvff.c		$Revision: $
  *
  *  Purpose:
  *	Single Floating-point to Double Floating-point
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfu.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfu.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfu.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfu.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvfu.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvfu.c		$Revision: $
  *
  *  Purpose:
  *	Floating-point to Unsigned Fixed-point Converts
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfut.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfut.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfut.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfut.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvfut.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvfut.c		$Revision: $
  *
  *  Purpose:
  *	Floating-point to Unsigned Fixed-point Converts with Truncation
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfx.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfx.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfx.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfx.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvfx.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvfx.c		$Revision: $
  *
  *  Purpose:
  *	Single Floating-point to Single Fixed-point
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfxt.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfxt.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvfxt.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvfxt.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvfxt.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvfxt.c		$Revision: $
  *
  *  Purpose:
  *	Single Floating-point to Single Fixed-point /w truncated result
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvuf.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvuf.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvuf.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvuf.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvuf.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvuf.c		$Revision: $
  *
  *  Purpose:
  *	Fixed point to Floating-point Converts
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fcnvxf.c linux-2.4.21-bk4/arch/parisc/math-emu/fcnvxf.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fcnvxf.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fcnvxf.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fcnvxf.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fcnvxf.c		$Revision: $
  *
  *  Purpose:
  *	Single Fixed-point to Single Floating-point
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/float.h linux-2.4.21-bk4/arch/parisc/math-emu/float.h
--- linux-2.4.21-bk3/arch/parisc/math-emu/float.h	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/float.h	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  * 
  *  File: 
- *      @(#)	pa/spmath/float.h		$Revision: 1.2 $
+ *      @(#)	pa/spmath/float.h		$Revision: 1.1 $
  * 
  *  Purpose:
  *      <<please update with a synopis of the functionality provided by this file>>
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fmpyfadd.c linux-2.4.21-bk4/arch/parisc/math-emu/fmpyfadd.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fmpyfadd.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fmpyfadd.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/fmpyfadd.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/fmpyfadd.c		$Revision: $
  *
  *  Purpose:
  *	Double Floating-point Multiply Fused Add
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fpu.h linux-2.4.21-bk4/arch/parisc/math-emu/fpu.h
--- linux-2.4.21-bk3/arch/parisc/math-emu/fpu.h	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fpu.h	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  * 
  *  File: 
- *      @(#)	pa/fp/fpu.h		$Revision: 1.2 $
+ *      @(#)	pa/fp/fpu.h		$Revision: $
  * 
  *  Purpose:
  *      <<please update with a synopis of the functionality provided by this file>>
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/fpudispatch.c linux-2.4.21-bk4/arch/parisc/math-emu/fpudispatch.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/fpudispatch.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/fpudispatch.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/fp/fpudispatch.c		$Revision: 1.1 $
+ *	@(#)	pa/fp/fpudispatch.c		$Revision: $
  *
  *  Purpose:
  *	<<please update with a synopsis of the functionality provided by this file>>
@@ -51,6 +51,7 @@
 
 #include "float.h"
 #include "types.h"
+#include <asm/processor.h>
 /* #include <sys/debug.h> */
 /* #include <machine/sys/mdep_private.h> */
 
@@ -166,6 +167,20 @@
 
 #define VASSERT(x)
 
+static void parisc_linux_get_fpu_type(u_int fpregs[])
+{
+	/* on pa-linux the fpu type is not filled in by the
+	 * caller; it is constructed here  
+	 */ 
+	if (boot_cpu_data.cpu_type == pcxs)
+		fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG;
+	else if (boot_cpu_data.cpu_type == pcxt ||
+	         boot_cpu_data.cpu_type == pcxt_)
+		fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG;
+	else if (boot_cpu_data.cpu_type >= pcxu)
+		fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG;
+}
+
 /*
  * this routine will decode the excepting floating point instruction and
  * call the approiate emulation routine.
@@ -184,6 +199,8 @@
 	/* All FP emulation code assumes that ints are 4-bytes in length */
 	VASSERT(sizeof(int) == 4);
 
+	parisc_linux_get_fpu_type(fpregs);
+
 	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
 
 	class = get_class(ir);
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfadd.c linux-2.4.21-bk4/arch/parisc/math-emu/sfadd.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfadd.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfadd.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfadd.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfadd.c		$Revision: $
  *
  *  Purpose:
  *	Single_add: add two single precision values.
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfcmp.c linux-2.4.21-bk4/arch/parisc/math-emu/sfcmp.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfcmp.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfcmp.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfcmp.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfcmp.c		$Revision: $
  *
  *  Purpose:
  *	sgl_cmp: compare two values
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfdiv.c linux-2.4.21-bk4/arch/parisc/math-emu/sfdiv.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfdiv.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfdiv.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfdiv.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfdiv.c		$Revision: $
  *
  *  Purpose:
  *	Single Precision Floating-point Divide
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfmpy.c linux-2.4.21-bk4/arch/parisc/math-emu/sfmpy.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfmpy.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfmpy.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfmpy.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfmpy.c		$Revision: $
  *
  *  Purpose:
  *	Single Precision Floating-point Multiply
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfrem.c linux-2.4.21-bk4/arch/parisc/math-emu/sfrem.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfrem.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfrem.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfrem.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfrem.c		$Revision: $
  *
  *  Purpose:
  *	Single Precision Floating-point Remainder
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfsqrt.c linux-2.4.21-bk4/arch/parisc/math-emu/sfsqrt.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfsqrt.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfsqrt.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfsqrt.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfsqrt.c		$Revision: $
  *
  *  Purpose:
  *	Single Floating-point Square Root
diff -urN linux-2.4.21-bk3/arch/parisc/math-emu/sfsub.c linux-2.4.21-bk4/arch/parisc/math-emu/sfsub.c
--- linux-2.4.21-bk3/arch/parisc/math-emu/sfsub.c	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-bk4/arch/parisc/math-emu/sfsub.c	2003-07-08 02:59:39.000000000 -0700
@@ -22,7 +22,7 @@
  * BEGIN_DESC
  *
  *  File:
- *	@(#)	pa/spmath/sfsub.c		$Revision: 1.1 $
+ *	@(#)	pa/spmath/sfsub.c		$Revision: $
  *
  *  Purpose:
  *	Single_subtract: subtract two single precision values.
diff -urN linux-2.4.21-bk3/arch/ppc/kernel/ppc405_pci.c linux-2.4.21-bk4/arch/ppc/kernel/ppc405_pci.c
--- linux-2.4.21-bk3/arch/ppc/kernel/ppc405_pci.c	2003-07-08 02:59:27.000000000 -0700
+++ linux-2.4.21-bk4/arch/ppc/kernel/ppc405_pci.c	2003-07-08 02:59:39.000000000 -0700
@@ -29,16 +29,6 @@
  *  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.
- *
- *
- *  	:05/07/02 - Armin
- *  		converted to using ocp register & core_ocp[];
- *
- *  	: 05/24/02 - Armin 
- *  		change get_ocp_paddr to ocp_get_paddr
- *
- *  	: 05029/02 - Armin 
- *  	  added PSR_PCI_ARBIT_EN check , not all 4xx have a pin strap reg
  */
 
 #include <linux/pci.h>
diff -urN linux-2.4.21-bk3/arch/ppc64/kernel/sys_ppc32.c linux-2.4.21-bk4/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.21-bk3/arch/ppc64/kernel/sys_ppc32.c	2003-07-08 02:59:27.000000000 -0700
+++ linux-2.4.21-bk4/arch/ppc64/kernel/sys_ppc32.c	2003-07-08 02:59:40.000000000 -0700
@@ -454,7 +454,7 @@
 	return err;
 }
 
-struct dqblk32 {
+struct user_dqblk32 {
     __u32 dqb_bhardlimit;
     __u32 dqb_bsoftlimit;
     __u32 dqb_curblocks;
@@ -473,13 +473,13 @@
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
  * and the register representation of a signed int (msr in 64-bit mode) is performed.
  */
-asmlinkage long sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, unsigned long addr)
+asmlinkage long sys32_quotactl(u32 cmd_parm, const char *special, u32 id_parm, caddr_t addr)
 {
-  int cmd = (int)cmd_parm;
-  int id  = (int)id_parm;
+	int cmd = (int)cmd_parm;
+	int id  = (int)id_parm;
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	struct v1c_mem_dqblk d;
 	mm_segment_t old_fs;
 	char *spec;
 	
@@ -487,35 +487,33 @@
 		    current->pid, current, current->comm);
 
 	switch (cmds) {
-	case Q_GETQUOTA:
+	case Q_V1_GETQUOTA:
 		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
+	case Q_V1_SETQUOTA:
+	case Q_V1_SETUSE:
+	case Q_V1_SETQLIM:
+		if (copy_from_user(&d, addr, sizeof(struct user_dqblk32)))
 			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
 		break;
 	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+		return sys_quotactl(cmd, special, id, addr);
 	}
-	spec = getname (special);
+	spec = getname(special);
 	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs ();
+	if (IS_ERR(spec))
+		return err;
+	old_fs = get_fs();
 	set_fs (KERNEL_DS);
 	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
 	set_fs (old_fs);
 	putname (spec);
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_V1_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user(addr, &d, sizeof(struct user_dqblk32)))
 			return -EFAULT;
 	}
 	
diff -urN linux-2.4.21-bk3/arch/s390x/kernel/linux32.c linux-2.4.21-bk4/arch/s390x/kernel/linux32.c
--- linux-2.4.21-bk3/arch/s390x/kernel/linux32.c	2003-07-08 02:59:27.000000000 -0700
+++ linux-2.4.21-bk4/arch/s390x/kernel/linux32.c	2003-07-08 02:59:40.000000000 -0700
@@ -935,7 +935,7 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
+struct user_dqblk32 {
     __u32 dqb_bhardlimit;
     __u32 dqb_bsoftlimit;
     __u32 dqb_curblocks;
@@ -948,46 +948,45 @@
                                 
 extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
 
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	struct v1c_mem_dqblk d;
 	mm_segment_t old_fs;
 	char *spec;
 	
 	switch (cmds) {
-	case Q_GETQUOTA:
+	case Q_V1_GETQUOTA:
 		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
+	case Q_V1_SETQUOTA:
+	case Q_V1_SETUSE:
+	case Q_V1_SETQLIM:
+		if (copy_from_user(&d, addr, sizeof (struct user_dqblk32)))
 			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
 		break;
 	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+		return sys_quotactl(cmd, special, id, addr);
 	}
-	spec = getname (special);
+
+	spec = getname(special);
 	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs ();
+	if (IS_ERR(spec))
+		return err;
+	old_fs = get_fs();
 	set_fs (KERNEL_DS);
 	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
-	set_fs (old_fs);
-	putname (spec);
+	set_fs(old_fs);
+	putname(spec);
 	if (err)
 		return err;
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_V1_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user(addr, &d, sizeof (struct user_dqblk32)))
 			return -EFAULT;
 	}
 	return 0;
diff -urN linux-2.4.21-bk3/arch/sparc64/kernel/sys_sparc32.c linux-2.4.21-bk4/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.21-bk3/arch/sparc64/kernel/sys_sparc32.c	2003-07-08 02:59:28.000000000 -0700
+++ linux-2.4.21-bk4/arch/sparc64/kernel/sys_sparc32.c	2003-07-08 02:59:40.000000000 -0700
@@ -889,7 +889,7 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
+struct user_dqblk32 {
     __u32 dqb_bhardlimit;
     __u32 dqb_bsoftlimit;
     __u32 dqb_curblocks;
@@ -902,44 +902,42 @@
                                 
 extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
 
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	struct v1c_mem_dqblk d;
 	mm_segment_t old_fs;
 	char *spec;
 	
 	switch (cmds) {
-	case Q_GETQUOTA:
+	case Q_V1_GETQUOTA:
 		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
+	case Q_V1_SETQUOTA:
+	case Q_V1_SETUSE:
+	case Q_V1_SETQLIM:
+		if (copy_from_user(&d, addr, sizeof(struct user_dqblk32)))
 			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+		d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+		d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
 		break;
 	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+		return sys_quotactl(cmd, special, id, addr);
 	}
-	spec = getname (special);
+	spec = getname(special);
 	err = PTR_ERR(spec);
-	if (IS_ERR(spec)) return err;
-	old_fs = get_fs ();
+	if (IS_ERR(spec))
+		return err;
+	old_fs = get_fs();
 	set_fs (KERNEL_DS);
 	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
 	set_fs (old_fs);
 	putname (spec);
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_V1_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user(addr, &d, sizeof(struct user_dqblk32)))
 			return -EFAULT;
 	}
 	return err;
diff -urN linux-2.4.21-bk3/drivers/acpi/Config.in linux-2.4.21-bk4/drivers/acpi/Config.in
--- linux-2.4.21-bk3/drivers/acpi/Config.in	2003-07-08 02:59:29.000000000 -0700
+++ linux-2.4.21-bk4/drivers/acpi/Config.in	2003-07-08 02:59:40.000000000 -0700
@@ -37,6 +37,7 @@
       tristate     '  ASUS Laptop Extras'  CONFIG_ACPI_ASUS
       tristate     '  Toshiba Laptop Extras'	CONFIG_ACPI_TOSHIBA
       bool         '  Debug Statements'	CONFIG_ACPI_DEBUG
+      bool         '  Relaxed AML Checking'	CONFIG_ACPI_RELAXED_AML
     fi
   fi
 
diff -urN linux-2.4.21-bk3/drivers/acpi/executer/exfldio.c linux-2.4.21-bk4/drivers/acpi/executer/exfldio.c
--- linux-2.4.21-bk3/drivers/acpi/executer/exfldio.c	2003-07-08 02:59:30.000000000 -0700
+++ linux-2.4.21-bk4/drivers/acpi/executer/exfldio.c	2003-07-08 02:59:40.000000000 -0700
@@ -139,7 +139,41 @@
 			field_datum_byte_offset, obj_desc->common_field.access_byte_width,
 			rgn_desc->region.node->name.ascii, rgn_desc->region.length));
 
-		return_ACPI_STATUS (AE_AML_REGION_LIMIT);
+		#ifdef CONFIG_ACPI_RELAXED_AML
+		{
+			/*
+			 * Allow access to the field if it is within the region size
+			 * rounded up to a multiple of the access byte width.  This
+			 * overcomes "off-by-one" programming errors in the AML often
+			 * found in Toshiba laptops.  These errors were allowed by
+			 * the Microsoft ASL compiler.
+			 */
+			u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length,
+									obj_desc->common_field.access_byte_width);
+
+			if (rounded_length < (obj_desc->common_field.base_byte_offset
+						+ field_datum_byte_offset
+						+ obj_desc->common_field.access_byte_width)) {
+				return_ACPI_STATUS (AE_AML_REGION_LIMIT);
+			} else {
+				static int	warn_once = 1;
+				if (warn_once) {
+					// Could also associate a flag with each field, and
+					// warn once for each field.
+					ACPI_REPORT_WARNING((
+						"The ACPI AML in your computer contains errors, "
+						"please nag the manufacturer to correct it.\n"));
+					ACPI_REPORT_WARNING((
+						"Allowing relaxed access to fields; "
+						"turn on CONFIG_ACPI_DEBUG for details.\n"));
+					warn_once = 0;
+				}
+				return_ACPI_STATUS (AE_OK);
+			}
+		}
+		#else
+			return_ACPI_STATUS (AE_AML_REGION_LIMIT);
+		#endif
 	}
 
 	return_ACPI_STATUS (AE_OK);
diff -urN linux-2.4.21-bk3/drivers/char/Config.in linux-2.4.21-bk4/drivers/char/Config.in
--- linux-2.4.21-bk3/drivers/char/Config.in	2003-07-08 02:59:31.000000000 -0700
+++ linux-2.4.21-bk4/drivers/char/Config.in	2003-07-08 02:59:42.000000000 -0700
@@ -309,6 +309,9 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   if [ "$CONFIG_X86" = "y" ]; then
+      bool '  NVIDIA chipset support' CONFIG_AGP_NVIDIA
+   fi
    if [ "$CONFIG_IA64" = "y" ]; then
       bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
    fi
diff -urN linux-2.4.21-bk3/drivers/char/agp/agp.h linux-2.4.21-bk4/drivers/char/agp/agp.h
--- linux-2.4.21-bk3/drivers/char/agp/agp.h	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/char/agp/agp.h	2003-07-08 02:59:42.000000000 -0700
@@ -166,6 +166,9 @@
 #ifndef PCI_DEVICE_ID_VIA_8363_0
 #define PCI_DEVICE_ID_VIA_8363_0      0x0305
 #endif
+#ifndef PCI_DEVICE_ID_VIA_8601_0
+#define PCI_DEVICE_ID_VIA_8601_0      0x0601
+#endif
 #ifndef PCI_DEVICE_ID_VIA_82C694X_0
 #define PCI_DEVICE_ID_VIA_82C694X_0      0x0605
 #endif
@@ -184,6 +187,24 @@
 #ifndef PCI_DEVICE_ID_INTEL_830_M_1
 #define PCI_DEVICE_ID_INTEL_830_M_1     0x3577
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_855_GM_0
+#define PCI_DEVICE_ID_INTEL_855_GM_0	0x3580
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_855_GM_1
+#define PCI_DEVICE_ID_INTEL_855_GM_1	0x3582
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_855_PM_0
+#define PCI_DEVICE_ID_INTEL_855_PM_0	0x3340
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_855_PM_1
+#define PCI_DEVICE_ID_INTEL_855_PM_1	0x3342
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_865_G_0
+#define PCI_DEVICE_ID_INTEL_865_G_0	0x2570
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_865_G_1
+#define PCI_DEVICE_ID_INTEL_865_G_1	0x2572
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_820_0
 #define PCI_DEVICE_ID_INTEL_820_0       0x2500
 #endif
@@ -280,6 +301,28 @@
 #define INTEL_NBXCFG    0x50
 #define INTEL_ERRSTS    0x91
 
+/* Intel 855GM/852GM registers */
+#define I855_GMCH_CTRL             0x52
+#define I855_GMCH_ENABLED          0x4
+#define I855_GMCH_GMS_MASK         (0x7 << 4)
+#define I855_GMCH_GMS_STOLEN_0M    0x0
+#define I855_GMCH_GMS_STOLEN_1M    (0x1 << 4)
+#define I855_GMCH_GMS_STOLEN_4M    (0x2 << 4)
+#define I855_GMCH_GMS_STOLEN_8M    (0x3 << 4)
+#define I855_GMCH_GMS_STOLEN_16M   (0x4 << 4)
+#define I855_GMCH_GMS_STOLEN_32M   (0x5 << 4)
+#define I85X_CAPID                 0x44
+#define I85X_VARIANT_MASK          0x7
+#define I85X_VARIANT_SHIFT         5
+#define I855_GME                   0x0
+#define I855_GM                    0x4
+#define I852_GME                   0x2
+#define I852_GM                    0x5
+#define I855_PME                   0x0
+#define I855_PM                    0x4
+#define I852_PME                   0x2
+#define I852_PM                    0x5
+
 /* intel i830 registers */
 #define I830_GMCH_CTRL             0x52
 #define I830_GMCH_ENABLED          0x4
@@ -412,6 +455,17 @@
 #define SVWRKS_POSTFLUSH  0x14
 #define SVWRKS_DIRFLUSH   0x0c
 
+/* NVIDIA registers */
+#define NVIDIA_0_APBASE     0x10
+#define NVIDIA_0_APSIZE     0x80
+#define NVIDIA_1_WBC        0xf0
+#define NVIDIA_2_GARTCTRL   0xd0
+#define NVIDIA_2_APBASE     0xd8
+#define NVIDIA_2_APLIMIT    0xdc
+#define NVIDIA_2_ATTBASE(i) (0xe0 + (i) * 4)
+#define NVIDIA_3_APBASE     0x50
+#define NVIDIA_3_APLIMIT    0x54
+
 /* HP ZX1 SBA registers */
 #define HP_ZX1_CTRL		0x200
 #define HP_ZX1_IBASE		0x300
diff -urN linux-2.4.21-bk3/drivers/char/agp/agpgart_be.c linux-2.4.21-bk4/drivers/char/agp/agpgart_be.c
--- linux-2.4.21-bk3/drivers/char/agp/agpgart_be.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/char/agp/agpgart_be.c	2003-07-08 02:59:42.000000000 -0700
@@ -23,6 +23,12 @@
  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  */
+
+/*
+ * Intel(R) 855GM/852GM and 865G support, added by
+ * David Dawes <dawes@tungstengraphics.com>.
+ */
+
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
@@ -43,6 +49,9 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
+#ifdef CONFIG_AGP_NVIDIA
+    #include <asm/msr.h>
+#endif
 
 #include <linux/agp_backend.h>
 #include "agp.h"
@@ -577,7 +586,7 @@
 	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
 		SetPageReserved(page);
 
-	agp_bridge.gatt_table_real = (unsigned long *) table;
+	agp_bridge.gatt_table_real = (u32 *) table;
 	agp_gatt_table = (void *)table;
 #ifdef CONFIG_X86
 	err = change_page_attr(virt_to_page(table), 1<<page_order, PAGE_KERNEL_NOCACHE);
@@ -1112,34 +1121,64 @@
 	u16 gmch_ctrl;
 	int gtt_entries;
 	u8 rdct;
+	int local = 0;
 	static const int ddt[4] = { 0, 16, 32, 64 };
 
 	pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
 
-	switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-	case I830_GMCH_GMS_STOLEN_512:
-		gtt_entries = KB(512) - KB(132);
-		printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
-		break;
-	case I830_GMCH_GMS_STOLEN_1024:
-		gtt_entries = MB(1) - KB(132);
-		printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
-		break;
-	case I830_GMCH_GMS_STOLEN_8192:
-		gtt_entries = MB(8) - KB(132);
-		printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
-		break;
-	case I830_GMCH_GMS_LOCAL:
-		rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
-		gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
-		printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
-		break;
-	default:
-		printk(KERN_INFO PFX "no video memory detected.\n");
-		gtt_entries = 0;
-		break;
+	if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 &&
+	    agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) {
+		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
+		case I855_GMCH_GMS_STOLEN_1M:
+			gtt_entries = MB(1) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_4M:
+			gtt_entries = MB(4) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_8M:
+			gtt_entries = MB(8) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_16M:
+			gtt_entries = MB(16) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_32M:
+			gtt_entries = MB(32) - KB(132);
+			break;
+		default:
+			gtt_entries = 0;
+			break;
+		}
+	} else
+	{
+		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+		case I830_GMCH_GMS_STOLEN_512:
+			gtt_entries = KB(512) - KB(132);
+			break;
+		case I830_GMCH_GMS_STOLEN_1024:
+			gtt_entries = MB(1) - KB(132);
+			break;
+		case I830_GMCH_GMS_STOLEN_8192:
+			gtt_entries = MB(8) - KB(132);
+			break;
+		case I830_GMCH_GMS_LOCAL:
+			rdct = INREG8(intel_i830_private.registers,
+				      I830_RDRAM_CHANNEL_TYPE);
+			gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+				      MB(ddt[I830_RDRAM_DDT(rdct)]);
+			local = 1;
+			break;
+		default:
+			gtt_entries = 0;
+			break;
+		}
 	}
 
+	if (gtt_entries > 0)
+		printk(KERN_INFO PFX "Detected %dK %s memory.\n",
+		       gtt_entries / KB(1), local ? "local" : "stolen");
+	else
+		printk(KERN_INFO PFX
+		       "No pre-allocated video memory detected.\n");
 	gtt_entries /= KB(4);
 
 	intel_i830_private.gtt_entries = gtt_entries;
@@ -1192,9 +1231,16 @@
 	u16 gmch_ctrl;
 	aper_size_info_fixed *values;
 
-	pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
 	values = A_SIZE_FIX(agp_bridge.aperture_sizes);
 
+	if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 &&
+	    agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) {
+		agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+		agp_bridge.aperture_size_idx = 0;
+		return(values[0].size);
+	}
+		
+	pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
 	if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
 		agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
 		agp_bridge.aperture_size_idx = 0;
@@ -2450,8 +2496,8 @@
 		return retval;
 	}
 
-	agp_bridge.gatt_table_real = page_dir.real;
-	agp_bridge.gatt_table = page_dir.remapped;
+	agp_bridge.gatt_table_real = (u32 *)page_dir.real;
+	agp_bridge.gatt_table = (u32 *)page_dir.remapped;
 	agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real);
 
 	/* Get the address for the gart region.
@@ -2477,8 +2523,8 @@
 {
 	amd_page_map page_dir;
    
-	page_dir.real = agp_bridge.gatt_table_real;
-	page_dir.remapped = agp_bridge.gatt_table;
+	page_dir.real = (unsigned long *)agp_bridge.gatt_table_real;
+	page_dir.remapped = (unsigned long *)agp_bridge.gatt_table;
 
 	amd_free_gatt_pages();
 	amd_free_page_map(&page_dir);
@@ -3559,8 +3605,8 @@
 		return retval;
 	}
 
-	agp_bridge.gatt_table_real = page_dir.real;
-	agp_bridge.gatt_table = page_dir.remapped;
+	agp_bridge.gatt_table_real = (u32 *)page_dir.real;
+	agp_bridge.gatt_table = (u32 *)page_dir.remapped;
 	agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real);
 
 	/* Get the address for the gart region.
@@ -3588,8 +3634,8 @@
 {
 	serverworks_page_map page_dir;
    
-	page_dir.real = agp_bridge.gatt_table_real;
-	page_dir.remapped = agp_bridge.gatt_table;
+	page_dir.real = (unsigned long *)agp_bridge.gatt_table_real;
+	page_dir.remapped = (unsigned long *)agp_bridge.gatt_table;
 
 	serverworks_free_gatt_pages();
 	serverworks_free_page_map(&page_dir);
@@ -4003,6 +4049,330 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_NVIDIA
+
+static struct _nvidia_private {
+	struct pci_dev *dev_1;
+	struct pci_dev *dev_2;
+	struct pci_dev *dev_3;
+	volatile u32 *aperture;
+	int num_active_entries;
+	off_t pg_offset;
+} nvidia_private;
+
+static int nvidia_fetch_size(void)
+{
+	int i;
+	u8 size_value;
+	aper_size_info_8 *values;
+
+	pci_read_config_byte(agp_bridge.dev, NVIDIA_0_APSIZE, &size_value);
+	size_value &= 0x0f;
+	values = A_SIZE_8(agp_bridge.aperture_sizes);
+
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if (size_value == values[i].size_value) {
+			agp_bridge.previous_size =
+				agp_bridge.current_size = (void *) (values + i);
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+#define SYSCFG          0xC0010010
+#define IORR_BASE0      0xC0010016
+#define IORR_MASK0      0xC0010017
+#define AMD_K7_NUM_IORR 2
+
+static int nvidia_init_iorr(u32 base, u32 size)
+{
+	u32 base_hi, base_lo;
+	u32 mask_hi, mask_lo;
+	u32 sys_hi, sys_lo;
+	u32 iorr_addr, free_iorr_addr;
+
+	/* Find the iorr that is already used for the base */
+	/* If not found, determine the uppermost available iorr */
+	free_iorr_addr = AMD_K7_NUM_IORR;
+	for(iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) {
+		rdmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
+		rdmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
+
+		if ((base_lo & 0xfffff000) == (base & 0xfffff000))
+			break;
+
+		if ((mask_lo & 0x00000800) == 0)
+			free_iorr_addr = iorr_addr;
+	}
+	
+	if (iorr_addr >= AMD_K7_NUM_IORR) {
+		iorr_addr = free_iorr_addr;
+		if (iorr_addr >= AMD_K7_NUM_IORR)
+			return -EINVAL;
+	}
+
+    base_hi = 0x0;
+    base_lo = (base & ~0xfff) | 0x18;
+    mask_hi = 0xf;
+    mask_lo = ((~(size - 1)) & 0xfffff000) | 0x800;
+    wrmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
+    wrmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
+
+    rdmsr(SYSCFG, sys_lo, sys_hi);
+    sys_lo |= 0x00100000;
+    wrmsr(SYSCFG, sys_lo, sys_hi);
+
+	return 0;
+}
+
+static int nvidia_configure(void)
+{
+	int i, rc, num_dirs;
+	u32 apbase, aplimit;
+	aper_size_info_8 *current_size;
+	u32 temp;
+
+	current_size = A_SIZE_8(agp_bridge.current_size);
+
+	/* aperture size */
+	pci_write_config_byte(agp_bridge.dev, NVIDIA_0_APSIZE,
+		current_size->size_value);
+
+    /* address to map to */
+	pci_read_config_dword(agp_bridge.dev, NVIDIA_0_APBASE, &apbase);
+	apbase &= PCI_BASE_ADDRESS_MEM_MASK;
+	agp_bridge.gart_bus_addr = apbase;
+	aplimit = apbase + (current_size->size * 1024 * 1024) - 1;
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit);
+	pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase);
+	pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit);
+	if (0 != (rc = nvidia_init_iorr(apbase, current_size->size * 1024 * 1024)))
+		return rc;
+
+	/* directory size is 64k */
+	num_dirs = current_size->size / 64;
+	nvidia_private.num_active_entries = current_size->num_entries;
+	nvidia_private.pg_offset = 0;
+	if (num_dirs == 0) {
+		num_dirs = 1;
+		nvidia_private.num_active_entries /= (64 / current_size->size);
+		nvidia_private.pg_offset = (apbase & (64 * 1024 * 1024 - 1) &
+			~(current_size->size * 1024 * 1024 - 1)) / PAGE_SIZE;
+	}
+
+	/* attbase */
+	for(i = 0; i < 8; i++) {
+		pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_ATTBASE(i),
+			(agp_bridge.gatt_bus_addr + (i % num_dirs) * 64 * 1024) | 1);
+	}
+
+	/* gtlb control */
+	pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL,
+		temp | 0x11);
+
+	/* gart control */
+	pci_read_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, &temp);
+	pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE,
+		temp | 0x100);
+
+	/* map aperture */
+	nvidia_private.aperture =
+		(volatile u32 *) ioremap(apbase, 33 * PAGE_SIZE);
+
+	return 0;
+}
+
+static void nvidia_cleanup(void)
+{
+	aper_size_info_8 *previous_size;
+	u32 temp;
+
+	/* gart control */
+	pci_read_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, &temp);
+	pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE,
+		temp & ~(0x100));
+
+	/* gtlb control */
+	pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL,
+		temp & ~(0x11));
+
+	/* unmap aperture */
+	iounmap((void *) nvidia_private.aperture);
+
+	/* restore previous aperture size */
+	previous_size = A_SIZE_8(agp_bridge.previous_size);
+	pci_write_config_byte(agp_bridge.dev, NVIDIA_0_APSIZE,
+		previous_size->size_value);
+
+	/* restore iorr for previous aperture size */
+	nvidia_init_iorr(agp_bridge.gart_bus_addr,
+		previous_size->size * 1024 * 1024);
+}
+
+static void nvidia_tlbflush(agp_memory * mem)
+{
+	int i;
+	unsigned long end;
+	u32 wbc_reg, wbc_mask, temp;
+
+	/* flush chipset */
+	switch(agp_bridge.type) {
+	case NVIDIA_NFORCE:
+		wbc_mask = 0x00010000;
+		break;
+	case NVIDIA_NFORCE2:
+		wbc_mask = 0x80000000;
+		break;
+	default:
+		wbc_mask = 0;
+		break;
+	}
+
+	if (wbc_mask) {
+		pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg);
+		wbc_reg |= wbc_mask;
+		pci_write_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, wbc_reg);
+
+		end = jiffies + 3*HZ;
+		do {
+			pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg);
+			if ((signed)(end - jiffies) <= 0) {
+				printk(KERN_ERR "TLB flush took more than 3 seconds.\n");
+			}
+		} while (wbc_reg & wbc_mask);
+	}
+
+	/* flush TLB entries */
+	for(i = 0; i < 32 + 1; i++)
+		temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)];
+	for(i = 0; i < 32 + 1; i++)
+		temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)];
+}
+
+static unsigned long nvidia_mask_memory(unsigned long addr, int type)
+{
+	/* Memory type is ignored */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+static int nvidia_insert_memory(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	int i, j;
+	
+	if ((type != 0) || (mem->type != 0))
+		return -EINVAL;
+	
+	if ((pg_start + mem->page_count) >
+		(nvidia_private.num_active_entries - agp_memory_reserved/PAGE_SIZE))
+		return -EINVAL;
+	
+	for(j = pg_start; j < (pg_start + mem->page_count); j++) {
+		if (!PGE_EMPTY(agp_bridge.gatt_table[nvidia_private.pg_offset + j])) {
+			return -EBUSY;
+		}
+	}
+
+	if (mem->is_flushed == FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		agp_bridge.gatt_table[nvidia_private.pg_offset + j] = agp_bridge.mask_memory(mem->memory[i], mem->type);
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int nvidia_remove_memory(agp_memory * mem, off_t pg_start,
+				     int type)
+{
+	int i;
+
+	if ((type != 0) || (mem->type != 0))
+		return -EINVAL;
+	
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		agp_bridge.gatt_table[nvidia_private.pg_offset + i] =
+		    (unsigned long) agp_bridge.scratch_page;
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static aper_size_info_8 nvidia_generic_sizes[5] =
+{
+	{512, 131072, 7, 0},
+	{256, 65536, 6, 8},
+	{128, 32768, 5, 12},
+	{64, 16384, 4, 14},
+	/* The 32M mode still requires a 64k gatt */
+	{32, 16384, 4, 15}
+};
+
+static gatt_mask nvidia_generic_masks[] =
+{
+	{0x00000001, 0}
+};
+
+static int __init nvidia_generic_setup (struct pci_dev *pdev)
+{
+	nvidia_private.dev_1 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
+	nvidia_private.dev_2 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
+	nvidia_private.dev_3 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
+	
+	if((nvidia_private.dev_1 == NULL) ||
+		(nvidia_private.dev_2 == NULL) ||
+		(nvidia_private.dev_3 == NULL)) {
+		printk(KERN_INFO PFX "agpgart: Detected an NVIDIA "
+			"nForce/nForce2 chipset, but could not find "
+			"the secondary devices.\n");
+		agp_bridge.type = NOT_SUPPORTED;
+		return -ENODEV;
+	}
+
+	agp_bridge.masks = nvidia_generic_masks;
+	agp_bridge.aperture_sizes = (void *) nvidia_generic_sizes;
+	agp_bridge.size_type = U8_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 5;
+	agp_bridge.dev_private_data = (void *) &nvidia_private;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = nvidia_configure;
+	agp_bridge.fetch_size = nvidia_fetch_size;
+	agp_bridge.cleanup = nvidia_cleanup;
+	agp_bridge.tlb_flush = nvidia_tlbflush;
+	agp_bridge.mask_memory = nvidia_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = nvidia_insert_memory;
+	agp_bridge.remove_memory = nvidia_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.suspend = agp_generic_suspend;
+	agp_bridge.resume = agp_generic_resume;
+	agp_bridge.cant_use_aperture = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_AGP_NVIDIA */
+
 #ifdef CONFIG_AGP_HP_ZX1
 
 #ifndef log2
@@ -4516,15 +4886,38 @@
 	{ PCI_DEVICE_ID_INTEL_830_M_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I830_M,
-		"Intel",
-		"i830M",
+		"Intel(R)",
+		"830M",
 		intel_830mp_setup },
-    { PCI_DEVICE_ID_INTEL_845_G_0,
+	
+	{ PCI_DEVICE_ID_INTEL_845_G_0,
 		 PCI_VENDOR_ID_INTEL,
 		 INTEL_I845_G,
-		 "Intel",
-		 "i845G",
+		 "Intel(R)",
+		 "845G",
 		 intel_845_setup },
+
+	{ PCI_DEVICE_ID_INTEL_855_GM_0,
+		 PCI_VENDOR_ID_INTEL,
+		 INTEL_I855_PM,
+		 "Intel(R)",
+		 "855PM",
+		 intel_845_setup },
+
+	{ PCI_DEVICE_ID_INTEL_855_PM_0,
+		 PCI_VENDOR_ID_INTEL,
+		 INTEL_I855_PM,
+		 "Intel(R)",
+		 "855PM",
+		 intel_845_setup },
+
+	{ PCI_DEVICE_ID_INTEL_865_G_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I865_G,
+		"Intel(R)",
+		"865G",
+		 intel_845_setup },
+
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -4565,12 +4958,24 @@
 		"SiS",
 		"740",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_651,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"651",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_650,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
 		"SiS",
 		"650",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_651,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"651",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_645,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
@@ -4583,6 +4988,12 @@
 		"SiS",
 		"646",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_648,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"648",
+		sis_generic_setup },		
 	{ PCI_DEVICE_ID_SI_735,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
@@ -4595,6 +5006,12 @@
 		"SiS",
 		"745",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_746,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"746",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_730,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
@@ -4658,6 +5075,12 @@
 		"Via",
 		"MVP3",
 		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_8601_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_PLE133,
+		"Via",
+		"Apollo PLE133",
+		via_generic_setup },
 	{ PCI_DEVICE_ID_VIA_82C691_0,
 		PCI_VENDOR_ID_VIA,
 		VIA_APOLLO_PRO,
@@ -4682,17 +5105,29 @@
 		"Via",
 		"Apollo Pro KT266",
 		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_8375,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_KM266,
+		"Via",
+		"Apollo Pro KM266 / KL266",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_8377_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_KT400,
+		"Via",
+		"Apollo Pro KT400",
+		via_generic_setup },
         { PCI_DEVICE_ID_VIA_8377_0,
 		PCI_VENDOR_ID_VIA,
 		VIA_APOLLO_KT400,
 		"Via",
 		"Apollo Pro KT400",
 		via_generic_setup },
-	{ PCI_DEVICE_ID_VIA_P4X333,
+	{ PCI_DEVICE_ID_VIA_P4M266,
 		PCI_VENDOR_ID_VIA,
-		VIA_APOLLO_P4X400,
+		VIA_APOLLO_P4M266,
 		"Via",
-		"Apollo P4X400",
+		"Apollo P4M266",
 		via_generic_setup },
 	{ 0,
 		PCI_VENDOR_ID_VIA,
@@ -4702,6 +5137,27 @@
 		via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
 
+#ifdef CONFIG_AGP_NVIDIA
+	{ PCI_DEVICE_ID_NVIDIA_NFORCE,
+		PCI_VENDOR_ID_NVIDIA,
+		NVIDIA_NFORCE,
+		"NVIDIA",
+		"nForce",
+		nvidia_generic_setup },
+	{ PCI_DEVICE_ID_NVIDIA_NFORCE2,
+		PCI_VENDOR_ID_NVIDIA,
+		NVIDIA_NFORCE2,
+		"NVIDIA",
+		"nForce2",
+		nvidia_generic_setup },
+	{ 0,
+		PCI_VENDOR_ID_NVIDIA,
+		NVIDIA_GENERIC,
+		"NVIDIA",
+		"Generic",
+		nvidia_generic_setup },
+#endif /* CONFIG_AGP_NVIDIA */
+
 #ifdef CONFIG_AGP_HP_ZX1
 	{ PCI_DEVICE_ID_HP_ZX1_LBA,
 		PCI_VENDOR_ID_HP,
@@ -4888,10 +5344,14 @@
                                  * with an external graphics
                                  * card. It will be initialized later 
                                  */
+				printk(KERN_ERR PFX "Detected an "
+				       "Intel(R) 845G, but could not find the"
+				       " secondary device. Assuming a "
+				       "non-integrated video card.\n");
 				agp_bridge.type = INTEL_I845_G;
 				break;
 			}
-			printk(KERN_INFO PFX "Detected an Intel "
+			printk(KERN_INFO PFX "Detected an Intel(R) "
 				   "845G Chipset.\n");
 			agp_bridge.type = INTEL_I810;
 			return intel_i830_setup(i810_dev);
@@ -4913,10 +5373,118 @@
 				agp_bridge.type = INTEL_I830_M;
 				break;
 			}
-			printk(KERN_INFO PFX "Detected an Intel "
+			printk(KERN_INFO PFX "Detected an Intel(R) "
 				   "830M Chipset.\n");
 			agp_bridge.type = INTEL_I810;
 			return intel_i830_setup(i810_dev);
+		case PCI_DEVICE_ID_INTEL_855_GM_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_855_GM_1, NULL);
+			if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+				i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_855_GM_1, i810_dev);
+			}
+			if (i810_dev == NULL) {
+                                /* 
+                                 * We probably have an 855PM chipset
+                                 * with an external graphics
+                                 * card. It will be initialized later.
+                                 */
+				agp_bridge.type = INTEL_I855_PM;
+				break;
+			}
+			{
+				u32 capval = 0;
+				const char *name = "855GM/852GM";
+
+				pci_read_config_dword(dev, I85X_CAPID, &capval);
+				switch ((capval >> I85X_VARIANT_SHIFT) &
+					I85X_VARIANT_MASK) {
+				case I855_GME:
+					name = "855GME";
+					break;
+				case I855_GM:
+					name = "855GM";
+					break;
+				case I852_GME:
+					name = "852GME";
+					break;
+				case I852_GM:
+					name = "852GM";
+					break;
+				}
+				printk(KERN_INFO PFX "Detected an Intel(R) "
+					"%s Chipset.\n", name);
+			}
+			agp_bridge.type = INTEL_I810;
+			return intel_i830_setup(i810_dev);
+		case PCI_DEVICE_ID_INTEL_855_PM_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_855_PM_1, NULL);
+			if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+				i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_855_PM_1, i810_dev);
+			}
+			if (i810_dev == NULL) {
+                                /* 
+                                 * We probably have an 855PM chipset
+                                 * with an external graphics
+                                 * card. It will be initialized later.
+                                 */
+				agp_bridge.type = INTEL_I855_PM;
+				break;
+			}
+			{
+				u32 capval = 0;
+				const char *name = "855PM/852PM";
+
+				pci_read_config_dword(dev, I85X_CAPID, &capval);
+				switch ((capval >> I85X_VARIANT_SHIFT) &
+					I85X_VARIANT_MASK) {
+				case I855_PME:
+					name = "855PME";
+					break;
+				case I855_PM:
+					name = "855PM";
+					break;
+				case I852_PME:
+					name = "852PME";
+					break;
+				case I852_PM:
+					name = "852PM";
+					break;
+				}
+				printk(KERN_INFO PFX "Detected an Intel(R) "
+					"%s Chipset.\n", name);
+			}
+			agp_bridge.type = INTEL_I810;
+			return intel_i830_setup(i810_dev);
+		case PCI_DEVICE_ID_INTEL_865_G_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_865_G_1, NULL);
+			if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+				i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_865_G_1, i810_dev);
+			}
+
+			if (i810_dev == NULL) {
+                                /* 
+                                 * We probably have a 865G chipset
+                                 * with an external graphics
+                                 * card. It will be initialized later 
+                                 */
+				printk(KERN_ERR PFX "Detected an "
+				       "Intel(R) 865G, but could not"
+				       " find the"
+				       " secondary device. Assuming a "
+				       "non-integrated video card.\n");
+				agp_bridge.type = INTEL_I865_G;
+				break;
+			}
+			printk(KERN_INFO PFX "Detected an Intel(R) "
+				   "865G Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i830_setup(i810_dev);
 		default:
 			break;
 		}
diff -urN linux-2.4.21-bk3/drivers/char/random.c linux-2.4.21-bk4/drivers/char/random.c
--- linux-2.4.21-bk3/drivers/char/random.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.21-bk4/drivers/char/random.c	2003-07-08 02:59:42.000000000 -0700
@@ -175,7 +175,7 @@
  *	chmod 600 $random_seed
  *	poolfile=/proc/sys/kernel/random/poolsize
  *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
- *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
  *
  * and the following lines in an appropriate script which is run as
  * the system is shutdown:
@@ -188,7 +188,7 @@
  *	chmod 600 $random_seed
  *	poolfile=/proc/sys/kernel/random/poolsize
  *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
- *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
  *
  * For example, on most modern systems using the System V init
  * scripts, such code fragments would be found in
diff -urN linux-2.4.21-bk3/drivers/char/serial.c linux-2.4.21-bk4/drivers/char/serial.c
--- linux-2.4.21-bk3/drivers/char/serial.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.21-bk4/drivers/char/serial.c	2003-07-08 02:59:42.000000000 -0700
@@ -4353,9 +4353,10 @@
 #ifdef CONFIG_DDB5074
 	pbn_nec_nile4,
 #endif
-#if 0
+
+	pbn_dci_pccom4,
 	pbn_dci_pccom8,
-#endif
+
 	pbn_xircom_combo,
 
 	pbn_siig10x_0,
@@ -4449,9 +4450,10 @@
 	{ SPCI_FL_BASE0, 1, 520833,			   /* pbn_nec_nile4 */
 		64, 3, NULL, 0x300 },
 #endif
-#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */		   /* pbn_dci_pccom8 */
-	{ SPCI_FL_BASE3, 8, 115200, 8 },
-#endif
+
+	{SPCI_FL_BASE3, 4, 115200, 8},			   /* pbn_dci_pccom4 */
+	{SPCI_FL_BASE3, 8, 115200, 8},			   /* pbn_dci_pccom8 */
+
 	{ SPCI_FL_BASE0, 1, 115200,			  /* pbn_xircom_combo */
 		0, 0, pci_xircom_fn },
 
@@ -4912,11 +4914,12 @@
 		pbn_nec_nile4 },
 #endif
 
-#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */
+	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_dci_pccom4 },
 	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_dci_pccom8 },
-#endif
 
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 	 PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
diff -urN linux-2.4.21-bk3/drivers/hotplug/ibmphp_ebda.c linux-2.4.21-bk4/drivers/hotplug/ibmphp_ebda.c
--- linux-2.4.21-bk3/drivers/hotplug/ibmphp_ebda.c	2003-06-13 07:51:33.000000000 -0700
+++ linux-2.4.21-bk4/drivers/hotplug/ibmphp_ebda.c	2003-07-08 02:59:42.000000000 -0700
@@ -292,6 +292,7 @@
 	rio_complete = 0;
 	hs_complete = 0;
 
+	/* FIXME: This is x86-32 specific, and even then PC specific.. */
 	io_mem = ioremap ((0x40 << 4) + 0x0e, 2);
 	if (!io_mem )
 		return -ENOMEM;
@@ -299,6 +300,9 @@
 	iounmap (io_mem);
 	debug ("returned ebda segment: %x\n", ebda_seg);
 	
+	if(ebda_seg == 0)		/* No EBDA */
+		return -ENOENT;
+	
 	io_mem = ioremap (ebda_seg<<4, 65000);
 	if (!io_mem )
 		return -ENOMEM;
diff -urN linux-2.4.21-bk3/drivers/i2c/i2c-algo-bit.c linux-2.4.21-bk4/drivers/i2c/i2c-algo-bit.c
--- linux-2.4.21-bk3/drivers/i2c/i2c-algo-bit.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.21-bk4/drivers/i2c/i2c-algo-bit.c	2003-07-08 02:59:42.000000000 -0700
@@ -609,7 +609,7 @@
 
 int __init i2c_algo_bit_init (void)
 {
-	printk("i2c-algo-bit.o: i2c bit algorithm module\n");
+	printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n");
 	return 0;
 }
 
diff -urN linux-2.4.21-bk3/drivers/i2c/i2c-core.c linux-2.4.21-bk4/drivers/i2c/i2c-core.c
--- linux-2.4.21-bk3/drivers/i2c/i2c-core.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-bk4/drivers/i2c/i2c-core.c	2003-07-08 02:59:42.000000000 -0700
@@ -1264,7 +1264,7 @@
 
 static int __init i2c_init(void)
 {
-	printk("i2c-core.o: i2c core module\n");
+	printk(KERN_INFO "i2c-core.o: i2c core module\n");
 	memset(adapters,0,sizeof(adapters));
 	memset(drivers,0,sizeof(drivers));
 	adap_count=0;
diff -urN linux-2.4.21-bk3/drivers/macintosh/macio-adb.c linux-2.4.21-bk4/drivers/macintosh/macio-adb.c
--- linux-2.4.21-bk3/drivers/macintosh/macio-adb.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-bk4/drivers/macintosh/macio-adb.c	2003-07-08 02:59:43.000000000 -0700
@@ -218,7 +218,6 @@
 				out_8(&adb->ctrl.r, DTB + CRE);
 			} else {
 				out_8(&adb->ctrl.r, DTB);
-				req->complete = 1;
 				current_req = req->next;
 				complete = 1;
 				if (current_req)
@@ -238,7 +237,6 @@
 				for (i = 0; i < req->reply_len; ++i)
 					req->reply[i] = in_8(&adb->data[i].r);
 			}
-			req->complete = 1;
 			current_req = req->next;
 			complete = 1;
 			if (current_req)
@@ -255,8 +253,16 @@
 		out_8(&adb->intr.r, 0);
 	}
 	spin_unlock(&macio_lock);
-	if (complete && req && req->done)
-		(*req->done)(req);
+	if (complete && req) {
+	    void (*done)(struct adb_request *) = req->done;
+	    mb();
+	    req->complete = 1;
+	    /* Here, we assume that if the request has a done member, the
+    	     * struct request will survive to setting req->complete to 1
+	     */
+	    if (done)
+		(*done)(req);
+	}
 	if (ibuf_len)
 		adb_input(ibuf, ibuf_len, regs, autopoll);
 }
diff -urN linux-2.4.21-bk3/drivers/macintosh/via-cuda.c linux-2.4.21-bk4/drivers/macintosh/via-cuda.c
--- linux-2.4.21-bk3/drivers/macintosh/via-cuda.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-bk4/drivers/macintosh/via-cuda.c	2003-07-08 02:59:43.000000000 -0700
@@ -37,7 +37,6 @@
 #ifdef CONFIG_MAC
 #define CUDA_IRQ IRQ_MAC_ADB
 #define __openfirmware
-#define eieio()
 #else
 #define CUDA_IRQ vias->intrs[0].line
 #endif
@@ -175,8 +174,8 @@
     /* for us by the main VIA driver in arch/m68k/mac/via.c        */
 
 #ifndef CONFIG_MAC
-    via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
-    via[IER] = IER_SET|SR_INT; eieio();	/* enable interrupt from SR */
+    out_8(&via[IFR], 0x7f);	/* clear interrupts by writing 1s */
+    out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
 #endif
 
     /* enable autopoll */
@@ -244,7 +243,8 @@
 #endif /* CONFIG_ADB */
 
 #define WAIT_FOR(cond, what)					\
-    do {							\
+    do {                                                        \
+    	int x;							\
 	for (x = 1000; !(cond); --x) {				\
 	    if (x == 0) {					\
 		printk("Timeout waiting for " what "\n");	\
@@ -257,40 +257,40 @@
 static int
 cuda_init_via()
 {
-    int x;
-
-    via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;	/* TACK & TIP out */
-    via[B] |= TACK | TIP;				/* negate them */
-    via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;		/* SR data in */
-    eieio();
-    x = via[SR]; eieio();	/* clear any left-over data */
+    out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ);	/* TACK & TIP out */
+    out_8(&via[B], in_8(&via[B]) | TACK | TIP);			/* negate them */
+    out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT);	/* SR data in */
+    (void)in_8(&via[SR]);						/* clear any left-over data */
 #ifndef CONFIG_MAC
-    via[IER] = 0x7f; eieio();	/* disable interrupts from VIA */
+    out_8(&via[IER], 0x7f);					/* disable interrupts from VIA */
+    (void)in_8(&via[IER]);
 #endif
-    eieio();
 
     /* delay 4ms and then clear any pending interrupt */
     mdelay(4);
-    x = via[SR]; eieio();
+    (void)in_8(&via[SR]);
+    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
 
     /* sync with the CUDA - assert TACK without TIP */
-    via[B] &= ~TACK; eieio();
+    out_8(&via[B], in_8(&via[B]) & ~TACK);
 
     /* wait for the CUDA to assert TREQ in response */
-    WAIT_FOR((via[B] & TREQ) == 0, "CUDA response to sync");
+    WAIT_FOR((in_8(&via[B]) & TREQ) == 0, "CUDA response to sync");
 
     /* wait for the interrupt and then clear it */
-    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (2)");
-    x = via[SR]; eieio();
+    WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
+    (void)in_8(&via[SR]);
+    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
 
     /* finish the sync by negating TACK */
-    via[B] |= TACK; eieio();
+    out_8(&via[B], in_8(&via[B]) | TACK);
 
     /* wait for the CUDA to negate TREQ and the corresponding interrupt */
-    WAIT_FOR(via[B] & TREQ, "CUDA response to sync (3)");
-    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (4)");
-    x = via[SR]; eieio();
-    via[B] |= TIP; eieio();	/* should be unnecessary */
+    WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
+    WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
+    (void)in_8(&via[SR]);
+    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+    out_8(&via[B], in_8(&via[B]) | TIP);	/* should be unnecessary */
 
     return 0;
 }
@@ -413,55 +413,59 @@
     req = current_req;
     if (req == 0)
 	return;
-    if ((via[B] & TREQ) == 0)
+    if ((in_8(&via[B]) & TREQ) == 0)
 	return;			/* a byte is coming in from the CUDA */
 
     /* set the shift register to shift out and send a byte */
-    via[ACR] |= SR_OUT; eieio();
-    via[SR] = req->data[0]; eieio();
-    via[B] &= ~TIP;
+    out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
+    out_8(&via[SR], req->data[0]);
+    out_8(&via[B], in_8(&via[B]) & ~TIP);
     cuda_state = sent_first_byte;
 }
 
 void
 cuda_poll()
 {
-    if (via[IFR] & SR_INT) {
-	unsigned long flags;
+    unsigned long flags;
 
-	/* cuda_interrupt only takes a normal lock, we disable
-	 * interrupts here to avoid re-entering and thus deadlocking.
-	 * An option would be to disable only the IRQ source with
-	 * disable_irq(), would that work on m68k ? --BenH
-	 */
-	local_irq_save(flags);
-	cuda_interrupt(0, 0, 0);
-	local_irq_restore(flags);
-    }
+    /* cuda_interrupt only takes a normal lock, we disable
+     * interrupts here to avoid re-entering and thus deadlocking.
+     * An option would be to disable only the IRQ source with
+     * disable_irq(), would that work on m68k ? --BenH
+     */
+    local_irq_save(flags);
+    cuda_interrupt(0, 0, 0);
+    local_irq_restore(flags);
 }
 
 static void
 cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
-    int x, status;
+    int status;
     struct adb_request *req = NULL;
     unsigned char ibuf[16];
     int ibuf_len = 0;
     int complete = 0;
+    unsigned char virq;
     
-    if ((via[IFR] & SR_INT) == 0)
-	return;
-
     spin_lock(&cuda_lock);
-    status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
+
+    virq = in_8(&via[IFR]) & 0x7f;
+    out_8(&via[IFR], virq);   
+    if ((virq & SR_INT) == 0) {
+        spin_unlock(&cuda_lock);
+	return;
+    }
+    
+    status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);
     /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
     switch (cuda_state) {
     case idle:
 	/* CUDA has sent us the first byte of data - unsolicited */
 	if (status != TREQ)
 	    printk("cuda: state=idle, status=%x\n", status);
-	x = via[SR]; eieio();
-	via[B] &= ~TIP; eieio();
+	(void)in_8(&via[SR]);
+	out_8(&via[B], in_8(&via[B]) & ~TIP);
 	cuda_state = reading;
 	reply_ptr = cuda_rbuf;
 	reading_reply = 0;
@@ -471,8 +475,8 @@
 	/* CUDA has sent us the first byte of data of a reply */
 	if (status != TREQ)
 	    printk("cuda: state=awaiting_reply, status=%x\n", status);
-	x = via[SR]; eieio();
-	via[B] &= ~TIP; eieio();
+	(void)in_8(&via[SR]);
+	out_8(&via[B], in_8(&via[B]) & ~TIP);
 	cuda_state = reading;
 	reply_ptr = current_req->reply;
 	reading_reply = 1;
@@ -481,16 +485,16 @@
     case sent_first_byte:
 	if (status == TREQ + TIP + SR_OUT) {
 	    /* collision */
-	    via[ACR] &= ~SR_OUT; eieio();
-	    x = via[SR]; eieio();
-	    via[B] |= TIP | TACK; eieio();
+	    out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
+	    (void)in_8(&via[SR]);
+	    out_8(&via[B], in_8(&via[B]) | TIP | TACK);
 	    cuda_state = idle;
 	} else {
 	    /* assert status == TIP + SR_OUT */
 	    if (status != TIP + SR_OUT)
 		printk("cuda: state=sent_first_byte status=%x\n", status);
-	    via[SR] = current_req->data[1]; eieio();
-	    via[B] ^= TACK; eieio();
+	    out_8(&via[SR], current_req->data[1]);
+	    out_8(&via[B], in_8(&via[B]) ^ TACK);
 	    data_index = 2;
 	    cuda_state = sending;
 	}
@@ -499,9 +503,9 @@
     case sending:
 	req = current_req;
 	if (data_index >= req->nbytes) {
-	    via[ACR] &= ~SR_OUT; eieio();
-	    x = via[SR]; eieio();
-	    via[B] |= TACK | TIP; eieio();
+	    out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
+	    (void)in_8(&via[SR]);
+	    out_8(&via[B], in_8(&via[B]) | TACK | TIP);
 	    req->sent = 1;
 	    if (req->reply_expected) {
 		cuda_state = awaiting_reply;
@@ -513,27 +517,27 @@
 		cuda_start();
 	    }
 	} else {
-	    via[SR] = req->data[data_index++]; eieio();
-	    via[B] ^= TACK; eieio();
+	    out_8(&via[SR], req->data[data_index++]);
+	    out_8(&via[B], in_8(&via[B]) ^ TACK);
 	}
 	break;
 
     case reading:
-	*reply_ptr++ = via[SR]; eieio();
+	*reply_ptr++ = in_8(&via[SR]);
 	if (status == TIP) {
 	    /* that's all folks */
-	    via[B] |= TACK | TIP; eieio();
+	    out_8(&via[B], in_8(&via[B]) | TACK | TIP);
 	    cuda_state = read_done;
 	} else {
 	    /* assert status == TIP | TREQ */
 	    if (status != TIP + TREQ)
 		printk("cuda: state=reading status=%x\n", status);
-	    via[B] ^= TACK; eieio();
+	    out_8(&via[B], in_8(&via[B]) ^ TACK);
 	}
 	break;
 
     case read_done:
-	x = via[SR]; eieio();
+	(void)in_8(&via[SR]);
 	if (reading_reply) {
 	    req = current_req;
 	    req->reply_len = reply_ptr - req->reply;
@@ -548,7 +552,6 @@
 		    memmove(req->reply, req->reply + 2, req->reply_len);
 		}
 	    }
-	    req->complete = 1;
 	    current_req = req->next;
 	    complete = 1;
 	} else {
@@ -563,7 +566,7 @@
 	    memcpy(ibuf, cuda_rbuf, ibuf_len);
 	}
 	if (status == TREQ) {
-	    via[B] &= ~TIP; eieio();
+	    out_8(&via[B], in_8(&via[B]) & ~TIP);
 	    cuda_state = reading;
 	    reply_ptr = cuda_rbuf;
 	    reading_reply = 0;
@@ -577,8 +580,16 @@
 	printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
     }
     spin_unlock(&cuda_lock);
-    if (complete && req && req->done)
-	(*req->done)(req);
+    if (complete && req) {
+    	void (*done)(struct adb_request *) = req->done;
+    	mb();
+    	req->complete = 1;
+    	/* Here, we assume that if the request has a done member, the
+    	 * struct request will survive to setting req->complete to 1
+    	 */
+    	if (done)
+		(*done)(req);
+    }
     if (ibuf_len)
 	cuda_input(ibuf, ibuf_len, regs);
 }
diff -urN linux-2.4.21-bk3/drivers/media/video/cpia_pp.c linux-2.4.21-bk4/drivers/media/video/cpia_pp.c
--- linux-2.4.21-bk3/drivers/media/video/cpia_pp.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.21-bk4/drivers/media/video/cpia_pp.c	2003-07-08 02:59:43.000000000 -0700
@@ -383,8 +383,8 @@
 			return -EINVAL;
 		}
 		if((err = ReadPacket(cam, buffer, 8)) < 0) {
-			return err;
 			DBG("Error reading command result\n");
+                       return err;
 		}
 		memcpy(data, buffer, databytes);
 	} else if(command[0] == DATA_OUT) {
diff -urN linux-2.4.21-bk3/drivers/message/fusion/Makefile linux-2.4.21-bk4/drivers/message/fusion/Makefile
--- linux-2.4.21-bk3/drivers/message/fusion/Makefile	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-bk4/drivers/message/fusion/Makefile	2003-07-08 02:59:43.000000000 -0700
@@ -9,7 +9,7 @@
 # parent makefile.
 #
 # Note 3! If you want to turn on various debug defines for an extended period of
-# time but don't want them lingering around in the Makefile when you pass it on 
+# time but don't want them lingering around in the Makefile when you pass it on
 # to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC
@@ -28,6 +28,7 @@
 #EXTRA_CFLAGS += -DMPT_DEBUG
 #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
 #EXTRA_CFLAGS += -DMPT_DEBUG_SG
+#EXTRA_CFLAGS += -DMPTSCSIH_DBG_TIMEOUT
 #
 # driver/module specifics...
 #
@@ -36,7 +37,8 @@
 #CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
 #
 #  For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCANDV
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_DV
+#CFLAGS_mptscsih.o += -DMPT_DEBUG_DV_TINY
 #CFLAGS_mptscsih.o += -DMPT_DEBUG_RESET
 #CFLAGS_mptscsih.o += -DMPT_DEBUG_NEH
 #
diff -urN linux-2.4.21-bk3/drivers/message/fusion/isense.c linux-2.4.21-bk4/drivers/message/fusion/isense.c
--- linux-2.4.21-bk3/drivers/message/fusion/isense.c	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/isense.c	2003-07-08 02:59:43.000000000 -0700
@@ -9,9 +9,9 @@
  *  Written By: Steven J. Ralston
  *  (yes I wrote some of the orig. code back in 1991!)
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: isense.c,v 1.33 2002/02/27 18:44:19 sralston Exp $
+ *  $Id: isense.c,v 1.34 2003/03/18 22:49:48 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -89,7 +89,9 @@
 #define my_VERSION	MPT_LINUX_VERSION_COMMON
 #define MYNAM		"isense"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,62)
 EXPORT_NO_SYMBOLS;
+#endif
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-bk3/drivers/message/fusion/linux_compat.h linux-2.4.21-bk4/drivers/message/fusion/linux_compat.h
--- linux-2.4.21-bk3/drivers/message/fusion/linux_compat.h	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/linux_compat.h	2003-07-08 02:59:43.000000000 -0700
@@ -75,11 +75,11 @@
 typedef void (*__cleanup_module_func_t)(void);
 #define module_init(x) \
 	int init_module(void) __attribute__((alias(#x))); \
-	extern inline __init_module_func_t __init_module_inline(void) \
+	static inline __init_module_func_t __init_module_inline(void) \
 	{ return x; }
 #define module_exit(x) \
 	void cleanup_module(void) __attribute__((alias(#x))); \
-	extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+	static inline __cleanup_module_func_t __cleanup_module_inline(void) \
 	{ return x; }
 
 #else
@@ -247,6 +247,8 @@
 
 /*
  *  We use our new error handling code if the kernel version is 2.4.18 or newer.
+ *  Remark: 5/5/03 use old EH code with 2.4 kernels as it runs in a background thread
+ *  2.4 kernels choke on a call to schedule via eh thread.
  */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
         #define MPT_SCSI_USE_NEW_EH
@@ -270,6 +272,13 @@
 #define mptscsih_sync_irq(_irq) synchronize_irq()
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58)
+#define mpt_inc_use_count()
+#define mpt_dec_use_count()
+#else
+#define mpt_inc_use_count() MOD_INC_USE_COUNT
+#define mpt_dec_use_count() MOD_DEC_USE_COUNT
+#endif
 
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.21-bk3/drivers/message/fusion/lsi/mpi_tool.h linux-2.4.21-bk4/drivers/message/fusion/lsi/mpi_tool.h
--- linux-2.4.21-bk3/drivers/message/fusion/lsi/mpi_tool.h	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/lsi/mpi_tool.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,129 +0,0 @@
-/*
- *  Copyright (c) 2001 LSI Logic Corporation.
- *
- *
- *           Name:  MPI_TOOL.H
- *          Title:  MPI Toolbox structures and definitions
- *  Creation Date:  July 30, 2001
- *
- *    MPI Version:  01.02.02
- *
- *  Version History
- *  ---------------
- *
- *  Date      Version   Description
- *  --------  --------  ------------------------------------------------------
- *  08-08-01  01.02.01  Original release.
- *  08-29-01  01.02.02  Added DIAG_DATA_UPLOAD_HEADER and related defines.
- *  --------------------------------------------------------------------------
- */
-
-#ifndef MPI_TOOL_H
-#define MPI_TOOL_H
-
-#define MPI_TOOLBOX_CLEAN_TOOL                      (0x00)
-#define MPI_TOOLBOX_MEMORY_MOVE_TOOL                (0x01)
-#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL           (0x02)
-
-
-/****************************************************************************/
-/* Toolbox reply                                                            */
-/****************************************************************************/
-
-typedef struct _MSG_TOOLBOX_REPLY
-{
-    U8                      Tool;                       /* 00h */
-    U8                      Reserved;                   /* 01h */
-    U8                      MsgLength;                  /* 02h */
-    U8                      Function;                   /* 03h */
-    U16                     Reserved1;                  /* 04h */
-    U8                      Reserved2;                  /* 06h */
-    U8                      MsgFlags;                   /* 07h */
-    U32                     MsgContext;                 /* 08h */
-    U16                     Reserved3;                  /* 0Ch */
-    U16                     IOCStatus;                  /* 0Eh */
-    U32                     IOCLogInfo;                 /* 10h */
-} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY,
-  ToolboxReply_t, MPI_POINTER pToolboxReply_t;
-
-
-/****************************************************************************/
-/* Toolbox Clean Tool request                                               */
-/****************************************************************************/
-
-typedef struct _MSG_TOOLBOX_CLEAN_REQUEST
-{
-    U8                      Tool;                       /* 00h */
-    U8                      Reserved;                   /* 01h */
-    U8                      ChainOffset;                /* 02h */
-    U8                      Function;                   /* 03h */
-    U16                     Reserved1;                  /* 04h */
-    U8                      Reserved2;                  /* 06h */
-    U8                      MsgFlags;                   /* 07h */
-    U32                     MsgContext;                 /* 08h */
-    U32                     Flags;                      /* 0Ch */
-} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST,
-  ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t;
-
-#define MPI_TOOLBOX_CLEAN_NVSRAM                    (0x00000001)
-#define MPI_TOOLBOX_CLEAN_SEEPROM                   (0x00000002)
-#define MPI_TOOLBOX_CLEAN_FLASH                     (0x00000004)
-
-
-/****************************************************************************/
-/* Toolbox Memory Move request                                              */
-/****************************************************************************/
-
-typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST
-{
-    U8                      Tool;                       /* 00h */
-    U8                      Reserved;                   /* 01h */
-    U8                      ChainOffset;                /* 02h */
-    U8                      Function;                   /* 03h */
-    U16                     Reserved1;                  /* 04h */
-    U8                      Reserved2;                  /* 06h */
-    U8                      MsgFlags;                   /* 07h */
-    U32                     MsgContext;                 /* 08h */
-    SGE_SIMPLE_UNION        SGL;                        /* 0Ch */
-} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST,
-  ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t;
-
-
-/****************************************************************************/
-/* Toolbox Diagnostic Data Upload request                                   */
-/****************************************************************************/
-
-typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
-{
-    U8                      Tool;                       /* 00h */
-    U8                      Reserved;                   /* 01h */
-    U8                      ChainOffset;                /* 02h */
-    U8                      Function;                   /* 03h */
-    U16                     Reserved1;                  /* 04h */
-    U8                      Reserved2;                  /* 06h */
-    U8                      MsgFlags;                   /* 07h */
-    U32                     MsgContext;                 /* 08h */
-    U32                     Flags;                      /* 0Ch */
-    U32                     Reserved3;                  /* 10h */
-    SGE_SIMPLE_UNION        SGL;                        /* 14h */
-} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
-  ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t;
-
-typedef struct _DIAG_DATA_UPLOAD_HEADER
-{
-    U32                     DiagDataLength;             /* 00h */
-    U8                      FormatCode;                 /* 04h */
-    U8                      Reserved;                   /* 05h */
-    U16                     Reserved1;                  /* 06h */
-} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER,
-  DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t;
-
-#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1            (0x01)
-#define MPI_TB_DIAG_FORMAT_SCSI_2                   (0x02)
-#define MPI_TB_DIAG_FORMAT_SCSI_3                   (0x03)
-#define MPI_TB_DIAG_FORMAT_FC_TRACE_1               (0x04)
-
-
-#endif
-
-
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptbase.c linux-2.4.21-bk4/drivers/message/fusion/mptbase.c
--- linux-2.4.21-bk3/drivers/message/fusion/mptbase.c	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptbase.c	2003-07-08 02:59:43.000000000 -0700
@@ -47,9 +47,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptbase.c,v 1.126 2002/12/16 15:28:45 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.130 2003/05/07 14:08:30 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -123,8 +123,10 @@
 /*
  *  cmd line parameters
  */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
 MODULE_PARM(PortIo, "0-1i");
 MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io");
+#endif
 static int PortIo = 0;
 
 #ifdef MFCNT
@@ -444,7 +446,7 @@
 			 */
 			if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))
 				|| (mf < ioc->req_frames)) ) {
-				printk(MYIOC_s_WARN_FMT 
+				printk(MYIOC_s_WARN_FMT
 					"mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx);
 				cb_idx = 0;
 				pa = 0;
@@ -452,14 +454,14 @@
 			}
 			if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth))
 				|| (mr < ioc->reply_frames)) ) {
-				printk(MYIOC_s_WARN_FMT 
+				printk(MYIOC_s_WARN_FMT
 					"mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr);
 				cb_idx = 0;
 				pa = 0;
 				freeme = 0;
 			}
 			if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) {
-				printk(MYIOC_s_WARN_FMT 
+				printk(MYIOC_s_WARN_FMT
 					"mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx);
 				cb_idx = 0;
 				pa = 0;
@@ -577,7 +579,7 @@
 		CONFIGPARMS *pCfg;
 		unsigned long flags;
 
-		dprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+		dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
 				ioc->name, mf, reply));
 
 		pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
@@ -600,7 +602,7 @@
 				u16		 status;
 
 				status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-				dprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+				dcprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
 				     status, le32_to_cpu(pReply->IOCLogInfo)));
 
 				pCfg->status = status;
@@ -684,7 +686,7 @@
 			MptEvHandlers[i] = NULL;
 			last_drv_idx = i;
 			if (cbfunc != mpt_base_reply) {
-				MOD_INC_USE_COUNT;
+				mpt_inc_use_count();
 			}
 			break;
 		}
@@ -704,7 +706,7 @@
 void
 mpt_deregister(int cb_idx)
 {
-	if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+	if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
 		MptCallbacks[cb_idx] = NULL;
 		MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
 		MptEvHandlers[cb_idx] = NULL;
@@ -714,7 +716,7 @@
 			isense_idx++;
 
 		if (cb_idx != mpt_base_index) {
-			MOD_DEC_USE_COUNT;
+			mpt_dec_use_count();
 		}
 	}
 }
@@ -944,7 +946,7 @@
  *	mpt_add_sge - Place a simple SGE at address pAddr.
  *	@pAddr: virtual address for SGE
  *	@flagslength: SGE flags and data transfer length
- *	@dma_addr: Physical address 
+ *	@dma_addr: Physical address
  *
  *	This routine places a MPT request frame back on the MPT adapter's
  *	FreeQ.
@@ -974,7 +976,7 @@
  *	@pAddr: virtual address for SGE
  *	@next: nextChainOffset value (u32's)
  *	@length: length of next SGL segment
- *	@dma_addr: Physical address 
+ *	@dma_addr: Physical address
  *
  *	This routine places a MPT request frame back on the MPT adapter's
  *	FreeQ.
@@ -987,7 +989,7 @@
 		u32 tmp = dma_addr & 0xFFFFFFFF;
 
 		pChain->Length = cpu_to_le16(length);
-		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); 
+		pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size();
 
 		pChain->NextChainOffset = next;
 
@@ -1070,7 +1072,7 @@
 
 		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
-		if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
+		if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
 			return -2;
 		}
 
@@ -1084,7 +1086,7 @@
 				(req_as_bytes[(ii*4) + 2] << 16) |
 				(req_as_bytes[(ii*4) + 3] << 24));
 			CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
-			if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) {
+			if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) {
 				r = -3;
 				break;
 			}
@@ -1278,17 +1280,19 @@
 	u32		 psize;
 	int		 ii;
 	int		 r = -ENODEV;
-	u64		 mask = 0xffffffffffffffff;
+	u64		 mask = 0xffffffffffffffffULL;
 
 	if (pci_enable_device(pdev))
 		return r;
 
 	if (!pci_set_dma_mask(pdev, mask)) {
-		dprintk((KERN_INFO MYNAM 
-			": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
-	} else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
-		printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
-		return r;
+		dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+	} else {
+		if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) {
+			printk(KERN_WARNING MYNAM
+				": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+			return r;
+		}
 	}
 
 	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
@@ -1510,7 +1514,7 @@
 	/* NEW!  20010220 -sralston
 	 * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
 	 */
-	if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) 
+	if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030)
 			|| (ioc->chip_type == C1035) || (ioc->chip_type == FC929X))
 		mpt_detect_bound_ports(ioc, pdev);
 
@@ -1551,20 +1555,23 @@
 	int	 r;
 	int	 ii;
 	int	 handlers;
+	int	 ret = 0;
+	int	 reset_alt_ioc_active = 0;
 
 	printk(KERN_INFO MYNAM ": Initiating %s %s\n",
 			ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
 
-	/* Disable reply interrupts */
+	/* Disable reply interrupts (also blocks FreeQ) */
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
 	ioc->active = 0;
-	/* NOTE: Access to IOC's request FreeQ is now blocked! */
 
 	if (ioc->alt_ioc) {
-		/* Disable alt-IOC's reply interrupts for a bit ... */
+		if (ioc->alt_ioc->active)
+			reset_alt_ioc_active = 1;
+
+		/* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
 		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
 		ioc->alt_ioc->active = 0;
-		/* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
 	}
 
 	hard = 1;
@@ -1572,15 +1579,29 @@
 		hard = 0;
 
 	if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
-		printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
-				ioc->name);
+		if (hard_reset_done == -4) {
+			printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
+					ioc->name);
+
+			if (reset_alt_ioc_active && ioc->alt_ioc) {
+				/* (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));
+				ioc->alt_ioc->active = 1;
+			}
+
+		} else {
+			printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
+					ioc->name);
+		}
 		return -1;
 	}
 
 	/* hard_reset_done = 0 if a soft reset was performed
 	 * and 1 if a hard reset was performed.
 	 */
-	if (hard_reset_done && ioc->alt_ioc) {
+	if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
 		if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
 			alt_ioc_ready = 1;
 		else
@@ -1589,42 +1610,55 @@
 					ioc->alt_ioc->name, r);
 	}
 
-	/* Get IOC facts! */
+	/* Get IOC facts! Allow 1 retry */
 	if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0)
-		return -2;
-	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		r = GetIocFacts(ioc, sleepFlag, reason);
+
+	if (r) {
+		ret = -2;
+	} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 		MptDisplayIocCapabilities(ioc);
 	}
 
 	if (alt_ioc_ready) {
-		if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0)
-			return -2;
-		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
+			/* Retry - alt IOC was initialized once
+			 */
+			r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
+		}
+		if (r) {
+			alt_ioc_ready = 0;
+			reset_alt_ioc_active = 0;
+		} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 			MptDisplayIocCapabilities(ioc->alt_ioc);
 		}
 	}
 
-	/*
-	 * Prime reply & request queues!
+	/* Prime reply & request queues!
 	 * (mucho alloc's) Must be done prior to
 	 * init as upper addresses are needed for init.
+	 * If fails, continue with alt-ioc processing
 	 */
-	if ((r = PrimeIocFifos(ioc)) != 0)
-		return -3;
+	if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0))
+		ret = -3;
 
-	// May need to check/upload firmware & data here!
-	if ((r = SendIocInit(ioc, sleepFlag)) != 0)
-		return -4;
+	/* May need to check/upload firmware & data here!
+	 * If fails, continue with alt-ioc processing
+	 */
+	if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0))
+		ret = -4;
 // NEW!
 	if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
 		printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
 				ioc->alt_ioc->name, r);
 		alt_ioc_ready = 0;
+		reset_alt_ioc_active = 0;
 	}
 
 	if (alt_ioc_ready) {
 		if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
 			alt_ioc_ready = 0;
+			reset_alt_ioc_active = 0;
 			printk(KERN_WARNING MYNAM
 				": alt-%s: (%d) init failure WARNING!\n",
 					ioc->alt_ioc->name, r);
@@ -1636,13 +1670,18 @@
 			ddlprintk((MYIOC_s_INFO_FMT
 				"firmware upload required!\n", ioc->name));
 
-			r = mpt_do_upload(ioc, sleepFlag);
-			if (r != 0)
-				printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			/* Controller is not operational, cannot do upload
+			 */
+			if (ret == 0) {
+				r = mpt_do_upload(ioc, sleepFlag);
+				if (r != 0)
+					printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+			}
+
 			/* Handle the alt IOC too */
 			if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){
 				ddlprintk((MYIOC_s_INFO_FMT
-					"Alt-ioc firmware upload required!\n", 
+					"Alt-ioc firmware upload required!\n",
 					ioc->name));
 				r = mpt_do_upload(ioc->alt_ioc, sleepFlag);
 				if (r != 0)
@@ -1651,12 +1690,13 @@
 		}
 	}
 
+	if (ret == 0) {
+		/* Enable! (reply interrupt) */
+		CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+		ioc->active = 1;
+	}
 
-	/* Enable! (reply interrupt) */
-	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
-	ioc->active = 1;
-
-	if (ioc->alt_ioc) {
+	if (reset_alt_ioc_active && ioc->alt_ioc) {
 		/* (re)Enable alt-IOC! (reply interrupt) */
 		dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 				ioc->alt_ioc->name));
@@ -1668,7 +1708,7 @@
 	 *  Enable MPT base driver management of EventNotification
 	 *  and EventAck handling.
 	 */
-	if (!ioc->facts.EventState)
+	if ((ret == 0) && (!ioc->facts.EventState))
 		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
 
 	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
@@ -1682,7 +1722,7 @@
 	 *	routine calls HardResetHandler, which calls into here again,
 	 *	and we try GetLanConfigPages again...
 	 */
-	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
 		if ((int)ioc->chip_type <= (int)FC929) {
 			/*
 			 *  Pre-fetch FC port WWN and stuff...
@@ -1712,11 +1752,11 @@
 			 */
 			mpt_GetScsiPortSettings(ioc, 0);
 
-			/* Get version and length of SDP 1 
+			/* Get version and length of SDP 1
 			 */
 			mpt_readScsiDevicePageHeaders(ioc, 0);
 
-			/* Find IM volumes 
+			/* Find IM volumes
 			 */
 			if (ioc->facts.MsgVersion >= 0x0102)
 				mpt_findImVolumes(ioc);
@@ -1738,24 +1778,24 @@
 	if (hard_reset_done) {
 		r = handlers = 0;
 		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
-			if (MptResetHandlers[ii]) {
+			if ((ret == 0) && MptResetHandlers[ii]) {
 				dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
 						ioc->name, ii));
 				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET);
 				handlers++;
+			}
 
-				if (alt_ioc_ready) {
-					dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
-							ioc->name, ioc->alt_ioc->name, ii));
-					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
-					handlers++;
-				}
+			if (alt_ioc_ready && MptResetHandlers[ii]) {
+				dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
+						ioc->name, ioc->alt_ioc->name, ii));
+				r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+				handlers++;
 			}
 		}
 		/* FIXME?  Examine results here? */
 	}
 
-	return 0;
+	return ret;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1830,7 +1870,7 @@
 			ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
 
 			if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) {
-				printk(KERN_WARNING MYNAM 
+				printk(KERN_WARNING MYNAM
 					": firmware downloadboot failure (%d)!\n", ret);
 			}
 		}
@@ -2014,8 +2054,8 @@
  *
  *	Returns:
  *		 1 - DIAG reset and READY
- *		 0 - READY initially OR soft reset and READY 
- *		-1 - Any failure on KickStart 
+ *		 0 - READY initially OR soft reset and READY
+ *		-1 - Any failure on KickStart
  *		-2 - Msg Unit Reset Failed
  *		-3 - IO Unit Reset Failed
  *		-4 - IOC owned by a PEER
@@ -2058,7 +2098,7 @@
 			else
 				statefault = 4;
 		}
-	} 
+	}
 
 	/*
 	 *	Check to see if IOC is in FAULT state.
@@ -2106,9 +2146,7 @@
 	 *  Loop here waiting for IOC to come READY.
 	 */
 	ii = 0;
-	cntdn = HZ * 15;
-	if (sleepFlag != CAN_SLEEP)
-		cntdn *= 10;	/* 1500 iterations @ 1msec per */
+	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15;	/* 15 seconds */
 
 	while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
 		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
@@ -2199,7 +2237,7 @@
 	int			 req_sz;
 	int			 reply_sz;
 	u32			 status;
-
+	
 	/* IOC *must* NOT be in RESET state! */
 	if (ioc->last_state == MPI_IOC_STATE_RESET) {
 		printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
@@ -2260,7 +2298,7 @@
 		facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
 
 		/*
-		 * FC f/w version changed between 1.1 and 1.2 
+		 * FC f/w version changed between 1.1 and 1.2
 		 *	Old: u16{Major(4),Minor(4),SubMinor(8)}
 		 *	New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
 		 */
@@ -2433,10 +2471,10 @@
 	if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
 		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw))
 			ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE;
-		else 
+		else
 			ioc->upload_fw = 1;
 	}
-	ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", 
+	ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n",
 		   ioc->name, ioc_init.Flags, ioc->upload_fw));
 
 	if ((int)ioc->chip_type <= (int)FC929) {
@@ -2482,9 +2520,7 @@
 	 *  LoopInit and TargetDiscovery!
 	 */
 	count = 0;
-	cntdn = HZ * 60;					/* chg'd from 30 to 60 seconds */
-	if (sleepFlag != CAN_SLEEP)
-		cntdn *= 10;					/* scale for 1msec delays */
+	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60;	/* 60 seconds */
 	state = mpt_GetIocState(ioc, 1);
 	while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
 		if (sleepFlag == CAN_SLEEP) {
@@ -2570,8 +2606,8 @@
  * Outputs: frags - number of fragments needed
  * Return NULL if failed.
  */
-void * 
-mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) 
+void *
+mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz)
 {
 	fw_image_t	**cached_fw = NULL;
 	u8		*mem = NULL;
@@ -2580,7 +2616,7 @@
 	int		bytes_left, bytes, num_frags;
 	int		sz, ii;
 
-	/* cached_fw 
+	/* cached_fw
 	 */
 	sz = ioc->num_fw_frags * sizeof(void *);
 	mem = kmalloc(sz, GFP_ATOMIC);
@@ -2737,8 +2773,8 @@
 	ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1;
 	ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32);
 
-	ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, 
-			ioc->facts.FWImageSize, &num_frags, &alloc_sz); 
+	ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc,
+			ioc->facts.FWImageSize, &num_frags, &alloc_sz);
 
 	if (ioc->cached_fw == NULL) {
 		/* Major Failure.
@@ -2785,8 +2821,8 @@
 		sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
 	}
 
-	mpt_add_sge(&request[sgeoffset], 
-			MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, 
+	mpt_add_sge(&request[sgeoffset],
+			MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size,
 			ioc->cached_fw[ii]->fw_dma);
 
 	sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
@@ -3133,8 +3169,8 @@
  *		 0 - no reset due to History bit, READY	
  *		-1 - no reset due to History bit but not READY	
  *		     OR reset but failed to come READY
- *		-2 - no reset, could not enter DIAG mode 
- *		-3 - reset but bad FW bit 
+ *		-2 - no reset, could not enter DIAG mode
+ *		-3 - reset but bad FW bit
  */
 static int
 KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
@@ -3277,7 +3313,7 @@
 
 		/*
 		 * Disable the ARM (Bug fix)
-		 * 
+		 *
 		 */
 		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
 		mdelay (1);
@@ -3326,7 +3362,7 @@
 #ifdef MPT_DEBUG
 				if (ioc->alt_ioc)
 					diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-				dprintk((MYIOC_s_INFO_FMT 
+				dprintk((MYIOC_s_INFO_FMT
 					"DbG2b: diag0=%08x, diag1=%08x\n",
 					ioc->name, diag0val, diag1val));
 #endif
@@ -3343,18 +3379,18 @@
 				}
 			}
 			if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) {
-				printk(KERN_WARNING MYNAM 
+				printk(KERN_WARNING MYNAM
 					": firmware downloadboot failure (%d)!\n", count);
 			}
 
 		} else {
 			/* Wait for FW to reload and for board
 			 * to go to the READY state.
-			 * Maximum wait is 30 seconds.
+			 * Maximum wait is 60 seconds.
 			 * If fail, no error will check again
 			 * with calling program.
 			 */
-			for (count = 0; count < 30; count ++) {
+			for (count = 0; count < 60; count ++) {
 				doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
 				doorbell &= MPI_IOC_STATE_MASK;
 
@@ -3472,15 +3508,13 @@
 	dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
 			ioc->name, reset_type));
 	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
-	if ((r = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+	if ((r = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
 		return r;
 
-	/* FW ACK'd request, wait for READY state 
+	/* FW ACK'd request, wait for READY state
 	 */
-	cntdn = HZ * 15;
 	count = 0;
-	if (sleepFlag != CAN_SLEEP)
-		cntdn *= 10;	/* 1500 iterations @ 1msec per */
+	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15;	/* 15 seconds */
 
 	while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
 		cntdn--;
@@ -3756,7 +3790,7 @@
 	 * our handshake request.
 	 */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-	if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+	if (!failcnt && (t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
 		failcnt++;
 
 	if (!failcnt) {
@@ -3774,7 +3808,7 @@
 				    (req_as_bytes[(ii*4) + 3] << 24));
 
 			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
-			if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0)
+			if ((t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0)
 				failcnt++;
 		}
 
@@ -3818,10 +3852,12 @@
 static int
 WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
-	int cntdn = HZ * howlong;
+	int cntdn;
 	int count = 0;
 	u32 intstat;
 
+	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
+
 	if (sleepFlag == CAN_SLEEP) {
 		while (--cntdn) {
 			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
@@ -3832,7 +3868,6 @@
 			count++;
 		}
 	} else {
-		cntdn *= 10; /* convert to msec */
 		while (--cntdn) {
 			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
 			if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
@@ -3840,7 +3875,6 @@
 			mdelay (1);
 			count++;
 		}
-		count /= 10;
 	}
 
 	if (cntdn) {
@@ -3869,10 +3903,11 @@
 static int
 WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
 {
-	int cntdn = HZ * howlong;
+	int cntdn;
 	int count = 0;
 	u32 intstat;
 
+	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong;
 	if (sleepFlag == CAN_SLEEP) {
 		while (--cntdn) {
 			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
@@ -3883,7 +3918,6 @@
 			count++;
 		}
 	} else {
-		cntdn *= 10; /* convert to msec */
 		while (--cntdn) {
 			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
 			if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
@@ -3891,7 +3925,6 @@
 			mdelay(1);
 			count++;
 		}
-		count /= 10;
 	}
 
 	if (cntdn) {
@@ -4275,7 +4308,7 @@
 	int			 ii;
 	int			 data, rc = 0;
 
-	/* Allocate memory 
+	/* Allocate memory
 	 */
 	if (!ioc->spi_data.nvram) {
 		int	 sz;
@@ -4454,12 +4487,17 @@
 	ioc->spi_data.sdp0version = cfg.hdr->PageVersion;
 	ioc->spi_data.sdp0length = cfg.hdr->PageLength;
 
+	dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
+			ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
+
+	dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
+			ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
 	return 0;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes 
+ *	mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *	@ioc: Pointer to a Adapter Strucutre
  *	@portnum: IOC port number
  *
@@ -4802,7 +4840,7 @@
 	 */
 	in_isr = in_interrupt();
 	if (in_isr) {
-		dprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+		dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
 				ioc->name));
 		return -EPERM;
 	}
@@ -4810,7 +4848,7 @@
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) {
-		dprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+		dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
 				ioc->name));
 		return -EAGAIN;
 	}
@@ -4843,7 +4881,7 @@
 
 	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
 
-	dprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+	dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
 		ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
 
 	/* Append pCfg pointer to end of mf
@@ -4890,7 +4928,7 @@
 {
 	MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
 
-	dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+	dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
 
 	/* Perform a FW reload */
 	if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
@@ -4900,7 +4938,7 @@
 	 * Hard reset clean-up will wake up
 	 * process and free all resources.
 	 */
-	dprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+	dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
 
 	return;
 }
@@ -4921,9 +4959,12 @@
 
 	dprintk((KERN_WARNING MYNAM
 			": IOC %s_reset routed to MPT base driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
 		/* If the internal config Q is not empty -
 		 * delete timer. MF resources will be freed when
 		 * the FIFO's are primed.
@@ -4941,10 +4982,9 @@
 	} else {
 		CONFIGPARMS *pNext;
 
-		/* Search the configQ for internal commands. 
+		/* Search the configQ for internal commands.
 		 * Flush the Q, and wake up all suspended threads.
 		 */
-#if 1
 		spin_lock_irqsave(&ioc->FreeQlock, flags);
 		if (! Q_IS_EMPTY(&ioc->configQ)){
 			pCfg = (CONFIGPARMS *)ioc->configQ.head;
@@ -4961,23 +5001,6 @@
 			} while (pCfg != (CONFIGPARMS *)&ioc->configQ);
 		}
 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-#else
-		while (1) {
-			spin_lock_irqsave(&ioc->FreeQlock, flags);
-			if (! Q_IS_EMPTY(&ioc->configQ)){
-				spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-				break;
-			}
-			pCfg = (CONFIGPARMS *)ioc->configQ.head;
-
-			Q_DEL_ITEM(&pCfg->linkage);
-			spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
-			pCfg->status = MPT_CONFIG_ERROR;
-			pCfg->wait_done = 1;
-			wake_up(&mpt_waitq);
-		}
-#endif
 	}
 
 	return 1;		/* currently means nothing really */
@@ -5425,6 +5448,29 @@
 
 	/* FIXME: If do_ioc_recovery fails, repeat....
 	 */
+	
+	/* The SCSI driver needs to adjust timeouts on all current
+	 * commands prior to the diagnostic reset being issued.
+	 * Prevents timeouts occuring during a diagnostic reset...very bad.
+	 * For all other protocol drivers, this is a no-op.
+	 */
+	{
+		int	 ii;
+		int	 r = 0;
+
+		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+			if (MptResetHandlers[ii]) {
+				dprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+						ioc->name, ii));
+				r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET);
+				if (ioc->alt_ioc) {
+					dprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+							ioc->name, ioc->alt_ioc->name, ii));
+					r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+				}
+			}
+		}
+	}
 
 	if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
 		printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
@@ -5836,7 +5882,7 @@
 		isense_idx = last_drv_idx;
 		r = 1;
 	}
-	MOD_INC_USE_COUNT;
+	mpt_inc_use_count();
 	return r;
 }
 
@@ -5855,7 +5901,7 @@
 	mpt_ScsiOpcodesPtr = NULL;
 	printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
 	isense_idx = -1;
-	MOD_DEC_USE_COUNT;
+	mpt_dec_use_count();
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptbase.h linux-2.4.21-bk4/drivers/message/fusion/mptbase.h
--- linux-2.4.21-bk3/drivers/message/fusion/mptbase.h	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptbase.h	2003-07-08 02:59:43.000000000 -0700
@@ -11,9 +11,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptbase.h,v 1.144 2003/01/28 21:31:56 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.149 2003/05/07 14:08:31 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.05.00fix"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.05.00fix"
+#define MPT_LINUX_VERSION_COMMON	"2.05.05+"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.05.05+"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -93,7 +93,7 @@
  */
 #define MPT_MAX_ADAPTERS		18
 #define MPT_MAX_PROTOCOL_DRIVERS	16
-#define MPT_MAX_BUS			1
+#define MPT_MAX_BUS			1	/* Do not change */
 #define MPT_MAX_FC_DEVICES		255
 #define MPT_MAX_SCSI_DEVICES		16
 #define MPT_LAST_LUN			31
@@ -383,12 +383,9 @@
 	u8			 maxWidth;	/* 0 if narrow, 1 if wide*/
 	u8			 negoFlags;	/* bit field, 0 if WDTR/SDTR/QAS allowed */
 	u8			 raidVolume;	/* set, if RAID Volume */
-#ifdef ABORT_FIX
-	u8			 numAborts;
-#else
-	u8			 rsvd;
-#endif
-	u16			 rsvd1raid;
+	u8			 type;		/* byte 0 of Inquiry data */
+	u8			 cflags;	/* controller flags */
+	u8			 rsvd1raid;
 	int			 npaths;
 	u16			 fc_phys_lun;
 	u16			 fc_xlat_lun;
@@ -400,11 +397,8 @@
 	ScsiCmndTracker		 WaitQ;
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
+	u32			 num_luns;
 //--- LUN split here?
-#ifdef MPT_SAVE_AUTOSENSE
-	u8			 sense[SCSI_STD_SENSE_BYTES];		/* 18 */
-	u8			 rsvd2[2];	/* alignment */
-#endif
 	u32			 luns;		/* Max LUNs is 32 */
 	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
 	u8			 pad0[4];
@@ -428,13 +422,15 @@
  *  Fibre Channel (SCSI) target device and associated defines...
  */
 #define MPT_TARGET_DEFAULT_DV_STATUS	0
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,55)
+#define MPT_TARGET_FLAGS_CONFIGURED	0x02
+#define MPT_TARGET_FLAGS_Q_YES		0x08
+#else
 #define MPT_TARGET_FLAGS_VALID_NEGO	0x01
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
-#ifdef MPT_SAVE_AUTOSENSE
-#define MPT_TARGET_FLAGS_VALID_SENSE	0x04
-#endif
 #define MPT_TARGET_FLAGS_Q_YES		0x08
 #define MPT_TARGET_FLAGS_VALID_56	0x10
+#endif
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
 #define MPT_TARGET_NO_NEGO_SYNC		0x02
@@ -603,7 +599,7 @@
 	dma_addr_t		 sense_buf_pool_dma;
 	u32			 sense_buf_low_dma;
 	int			 mtrr_reg;
-	void			*pcidev;	/* struct pci_dev pointer */
+	struct pci_dev		*pcidev;	/* struct pci_dev pointer */
 	u8			*memmap;	/* mmap address */
 	struct Scsi_Host	*sh;		/* Scsi Host pointer */
 	ScsiCfgData		spi_data;	/* Scsi config. data */
@@ -616,6 +612,12 @@
 	int			 eventTypes;	/* Event logging parameters */
 	int			 eventContext;	/* Next event context */
 	int			 eventLogSize;	/* Max number of cached events */
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	int			timeout_hard;
+	int			timeout_delta;
+	int			timeout_cnt;
+	int			timeout_maxcnt;
+#endif
 	struct _mpt_ioctl_events *events;	/* pointer to event log */
 	fw_image_t		**cached_fw;	/* Pointer to FW SG List */
 	Q_TRACKER		 configQ;	/* linked list of config. requests */
@@ -656,6 +658,7 @@
 /* reset_phase defs */
 #define MPT_IOC_PRE_RESET		0
 #define MPT_IOC_POST_RESET		1
+#define MPT_IOC_SETUP_RESET		2
 
 /*
  * Invent MPT host event (super-set of MPI Events)
@@ -758,6 +761,19 @@
 #define nehprintk(x)
 #endif
 
+#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
+#define dcprintk(x) printk x
+#else
+#define dcprintk(x)
+#endif
+
+#if defined(MPT_DEBUG_SCSI) || defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
+#define dsprintk(x) printk x
+#else
+#define dsprintk(x)
+#endif
+
+
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
 	(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
 
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptctl.c linux-2.4.21-bk4/drivers/message/fusion/mptctl.c
--- linux-2.4.21-bk3/drivers/message/fusion/mptctl.c	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptctl.c	2003-07-08 02:59:43.000000000 -0700
@@ -32,9 +32,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston, Noah Romer
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptctl.c,v 1.63 2002/12/03 21:26:33 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.66 2003/05/07 14:08:32 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -102,7 +102,9 @@
 #define my_VERSION	MPT_LINUX_VERSION_COMMON
 #define MYNAM		"mptctl"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,62)
 EXPORT_NO_SYMBOLS;
+#endif
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
@@ -136,7 +138,7 @@
 static int mptctl_replace_fw (unsigned long arg);
 
 static int mptctl_do_reset(unsigned long arg);
-static int mptctl_hp_hostinfo(unsigned long arg);
+static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd);
 static int mptctl_hp_targetinfo(unsigned long arg);
 
 /*
@@ -267,8 +269,12 @@
 			 */
 			iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK;
 			if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) {
-				if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)
-					mod_timer(&ioc->ioctl->timer, jiffies + HZ);
+				if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) {
+					ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
+					del_timer (&ioc->ioctl->timer);
+					ioc->ioctl->timer.expires = jiffies + HZ;
+					add_timer(&ioc->ioctl->timer);
+				}
 			}
 			ioc->ioctl->tmPtr = NULL;
 
@@ -334,6 +340,7 @@
 			 */
 			ioc->ioctl->wait_done = 1;
 			wake_up (&mptctl_wait);
+
 		} else if (reply && cmd == MPI_FUNCTION_FW_DOWNLOAD) {
 			/* Two paths to FW DOWNLOAD! */
 			// NOTE: Expects/requires non-Turbo reply!
@@ -518,9 +525,12 @@
 {
 	MPT_IOCTL *ioctl = ioc->ioctl;
 	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
-	if (reset_phase == MPT_IOC_PRE_RESET){
+	if (reset_phase == MPT_IOC_SETUP_RESET){
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET){
 
 		/* Someone has called the reset handler to
 		 * do a hard reset. No more replies from the FW.
@@ -537,13 +547,15 @@
 		}
 
 	} else {
+		ioctl->tmPtr = NULL;
+
 		/* Set the status and continue IOCTL
 		 * processing. All memory will be free'd
 		 * by originating thread after wake_up is
 		 * called.
 		 */
 		if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){
-			ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET;
+			ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET;
 
 			/* Wake up the calling process
 			 */
@@ -625,7 +637,11 @@
 		return -ENODEV;
 	}
 
-
+	if (!iocp->active) {
+		printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+				__FILE__, __LINE__);
+		return -EFAULT;
+	}
 
 	/* Handle those commands that are just returning
 	 * information stored in the driver.
@@ -656,25 +672,19 @@
 
 	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));
 
-	switch(cmd) {
-	case MPTFWDOWNLOAD:
+	if (cmd == MPTFWDOWNLOAD)
 		ret = mptctl_fw_download(arg);
-		break;
-	case MPTCOMMAND:
+	else if (cmd == MPTCOMMAND)
 		ret = mptctl_mpt_command(arg);
-		break;
-	case MPTHARDRESET:
+	else if (cmd == MPTHARDRESET)
 		ret = mptctl_do_reset(arg);
-		break;
-	case HP_GETHOSTINFO:
-		ret = mptctl_hp_hostinfo(arg);
-		break;
-	case HP_GETTARGETINFO:
+	else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))
+		ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));
+	else if (cmd == HP_GETTARGETINFO)
 		ret = mptctl_hp_targetinfo(arg);
-		break;
-	default:
+	else
 		ret = -EINVAL;
-	}
+
 
 	up(&mptctl_syscall_sem_ioc[iocp->id]);
 
@@ -702,7 +712,7 @@
 		return -ENODEV; /* (-6) No such device or address */
 	}
 
-	if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) {
+	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
 		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
 			__FILE__, __LINE__);
 		return -1;
@@ -871,7 +881,7 @@
 	 *	96		8
 	 *	64		4
 	 */
-	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) 
+	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
 			/ (sizeof(dma_addr_t) + sizeof(u32));
 	if (numfrags > maxfrags) {
 		ret = -EMLINK;
@@ -1225,10 +1235,16 @@
 	u8			revision;
 
 	dctlprintk((": mptctl_getiocinfo called.\n"));
-	if (data_size == sizeof(struct mpt_ioctl_iocinfo))
-		cim_rev = 1;
-	else if (data_size == (sizeof(struct mpt_ioctl_iocinfo) - sizeof(struct mpt_ioctl_pci_info)))
+	/* Add of PCI INFO results in unaligned access for
+	 * IA64 and Sparc. Reset long to int. Return no PCI
+	 * data for obsolete format.
+	 */
+	if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0))
 		cim_rev = 0;
+	else if (data_size == sizeof(struct mpt_ioctl_iocinfo))
+		cim_rev = 1;
+	else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12))
+		cim_rev = 0;	/* obsolete */
 	else
 		return -EFAULT;
 
@@ -1412,7 +1428,7 @@
 
 	/* Get number of devices
          */
-	if ( (sh = ioc->sh) != NULL) {
+	if ((sh = ioc->sh) != NULL) {
 
 		max_id = sh->max_id - 1;
 		hd = (MPT_SCSI_HOST *) sh->hostdata;
@@ -1435,9 +1451,8 @@
 
 							pdata++;
 
-							if (maxWordsLeft <= 0) {
+							if (maxWordsLeft <= 0)
 								break;
-							}
 						}
 					}
 				}
@@ -1710,7 +1725,7 @@
 	/* Allocate memory for the new FW image
 	 */
 	newFwSize = karg.newImageSize;
-	fwmem = mpt_alloc_fw_memory(ioc, newFwSize, &num_frags, &alloc_sz); 
+	fwmem = mpt_alloc_fw_memory(ioc, newFwSize, &num_frags, &alloc_sz);
 	if (fwmem == NULL)
 		return -ENOMEM;
 
@@ -1730,7 +1745,7 @@
 	}
 
 
-	/* Free the old FW image 
+	/* Free the old FW image
 	 */
 	if (ioc->cached_fw) {
 		mpt_free_fw_memory(ioc, 0);
@@ -1812,22 +1827,20 @@
 	MPT_FRAME_HDR	*mf = NULL;
 	MPIHeader_t	*hdr;
 	char		*psge;
-	MptSge_t	*this_sge = NULL;
-	MptSge_t	*sglbuf = NULL;
 	struct buflist	bufIn;	/* data In buffer */
 	struct buflist	bufOut; /* data Out buffer */
-	dma_addr_t	sglbuf_dma;
-	dma_addr_t	dma_addr;
+	dma_addr_t	dma_addr_in;
+	dma_addr_t	dma_addr_out;
 	int		dir;	/* PCI data direction */
 	int		sgSize = 0;	/* Num SG elements */
-	int		this_alloc;
-	int		 iocnum, flagsLength;
-	int		 sz, rc = 0;
-	int		 msgContext;
+	int		iocnum, flagsLength;
+	int		sz, rc = 0;
+	int		msgContext;
 	int		tm_flags_set = 0;
 	u16		req_idx;
 
 	dctlprintk(("mptctl_do_mpt_command called.\n"));
+	bufIn.kptr = bufOut.kptr = NULL;
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
@@ -1854,7 +1867,7 @@
 	if (karg.dataOutSize > 0)
 		sz += sizeof(dma_addr_t) + sizeof(u32);
 
-	if ( sz > ioc->req_sz) {
+	if (sz > ioc->req_sz) {
 		printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
 			"Request frame too large (%d) maximum (%d)\n",
 				__FILE__, __LINE__, sz, ioc->req_sz);
@@ -1897,12 +1910,16 @@
 	switch (hdr->Function) {
 	case MPI_FUNCTION_IOC_FACTS:
 	case MPI_FUNCTION_PORT_FACTS:
+		karg.dataOutSize  = karg.dataInSize = 0;
+		break;
+
 	case MPI_FUNCTION_CONFIG:
 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
 	case MPI_FUNCTION_FW_UPLOAD:
 	case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
 	case MPI_FUNCTION_FW_DOWNLOAD:
+	case MPI_FUNCTION_FC_PRIMITIVE_SEND:
 		break;
 
 	case MPI_FUNCTION_SCSI_IO_REQUEST:
@@ -1938,7 +1955,7 @@
 				cpu_to_le32(ioc->sense_buf_low_dma
 				   + (req_idx * MPT_SENSE_BUFFER_ALLOC));
 
-			if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
+			if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
 				if (hd->Targets)
 					pTarget = hd->Targets[target];
 			}
@@ -1949,11 +1966,10 @@
 			/* Have the IOCTL driver set the direction based
 			 * on the dataOutSize (ordering issue with Sparc).
 			 */
-			if (karg.dataOutSize > 0 ) {
+			if (karg.dataOutSize > 0) {
 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
 				dataSize = karg.dataOutSize;
-			}
-			else {
+			} else {
 				scsidir = MPI_SCSIIO_CONTROL_READ;
 				dataSize = karg.dataInSize;
 			}
@@ -2006,11 +2022,10 @@
 			/* Have the IOCTL driver set the direction based
 			 * on the dataOutSize (ordering issue with Sparc).
 			 */
-			if (karg.dataOutSize > 0 ) {
+			if (karg.dataOutSize > 0) {
 				scsidir = MPI_SCSIIO_CONTROL_WRITE;
 				dataSize = karg.dataOutSize;
-			}
-			else {
+			} else {
 				scsidir = MPI_SCSIIO_CONTROL_READ;
 				dataSize = karg.dataInSize;
 			}
@@ -2030,7 +2045,7 @@
 		break;
 
 	case MPI_FUNCTION_SCSI_TASK_MGMT:
-		{ 
+		{
 			MPT_SCSI_HOST *hd = NULL;
 			if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
 				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
@@ -2038,7 +2053,7 @@
 					__FILE__, __LINE__);
 				rc = -EFAULT;
 				goto done_free_mem;
-			}  else if (mptctl_set_tm_flags(hd) != 0) {
+			} else if (mptctl_set_tm_flags(hd) != 0) {
 				rc = -EPERM;
 				goto done_free_mem;
 			}
@@ -2063,7 +2078,7 @@
 			}
 
 			if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) ||
-				(pInit->MaxBuses != ioc->facts.MaxBuses) || 
+				(pInit->MaxBuses != ioc->facts.MaxBuses) ||
 				(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
 				(pInit->HostMfaHighAddr != high_addr) ||
 				(pInit->SenseBufferHighAddr != sense_high)) {
@@ -2095,7 +2110,6 @@
 			MPI_FUNCTION_FC_LINK_SRVC_BUF_POST
 			MPI_FUNCTION_FC_LINK_SRVC_RSP
 			MPI_FUNCTION_FC_ABORT
-			MPI_FUNCTION_FC_PRIMITIVE_SEND
 			MPI_FUNCTION_LAN_SEND
 			MPI_FUNCTION_LAN_RECEIVE
 		 	MPI_FUNCTION_LAN_RESET
@@ -2113,7 +2127,7 @@
 	 * preceede the data in (read) SGE. psgList is used to free the
 	 * allocated memory.
 	 */
-	psge = (char *) ( ((int *) mf) + karg.dataSgeOffset);
+	psge = (char *) (((int *) mf) + karg.dataSgeOffset);
 	flagsLength = 0;
 
 	/* bufIn and bufOut are used for user to kernel space transfers
@@ -2121,30 +2135,18 @@
 	bufIn.kptr = bufOut.kptr = NULL;
 	bufIn.len = bufOut.len = 0;
 
-	if (karg.dataOutSize > 0 )
+	if (karg.dataOutSize > 0)
 		sgSize ++;
 
-	if (karg.dataInSize > 0 )
+	if (karg.dataInSize > 0)
 		sgSize ++;
 
 	if (sgSize > 0) {
 
-		/* Allocate memory for the SGL.
-		 * Used to free kernel memory once
-		 * the MF is freed.
-		 */
-		sglbuf = pci_alloc_consistent (ioc->pcidev,
-			sgSize*sizeof(MptSge_t), &sglbuf_dma);
-		if (sglbuf == NULL) {
-			rc = -ENOMEM;
-			goto done_free_mem;
-		}
-		this_sge = sglbuf;
-
 		/* Set up the dataOut memory allocation */
 		if (karg.dataOutSize > 0) {
 			dir = PCI_DMA_TODEVICE;
-			if (karg.dataInSize > 0 ) {
+			if (karg.dataInSize > 0) {
 				flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
 						MPI_SGE_FLAGS_DIRECTION |
 						mpt_addr_size() )
@@ -2153,22 +2155,25 @@
 				flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
 			}
 			flagsLength |= karg.dataOutSize;
-
-			this_alloc = karg.dataOutSize;
-			bufOut.len = this_alloc;
+			bufOut.len = karg.dataOutSize;
 			bufOut.kptr = pci_alloc_consistent(
-					ioc->pcidev, this_alloc, &dma_addr);
+					ioc->pcidev, bufOut.len, &dma_addr_out);
 
 			if (bufOut.kptr == NULL) {
 				rc = -ENOMEM;
 				goto done_free_mem;
 			} else {
+				/* Set up this SGE.
+				 * Copy to MF and to sglbuf
+				 */
+				mpt_add_sge(psge, flagsLength, dma_addr_out);
+				psge += (sizeof(u32) + sizeof(dma_addr_t));
+
 				/* Copy user data to kernel space.
 				 */
 				if (copy_from_user(bufOut.kptr,
 						karg.dataOutBufPtr,
 						bufOut.len)) {
-
 					printk(KERN_ERR
 						"%s@%d::mptctl_do_mpt_command - Unable "
 						"to read user data "
@@ -2177,16 +2182,6 @@
 					rc =  -EFAULT;
 					goto done_free_mem;
 				}
-
-				/* Set up this SGE.
-				 * Copy to MF and to sglbuf
-				 */
-				mpt_add_sge(psge, flagsLength, dma_addr);
-				psge += (sizeof(u32) + sizeof(dma_addr_t));
-
-				this_sge->FlagsLength = flagsLength;
-				this_sge->Address = dma_addr;
-				this_sge++;
 			}
 		}
 
@@ -2195,10 +2190,10 @@
 			flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
 			flagsLength |= karg.dataInSize;
 
-			this_alloc = karg.dataInSize;
-			bufIn.len = this_alloc;
+			bufIn.len = karg.dataInSize;
 			bufIn.kptr = pci_alloc_consistent(ioc->pcidev,
-							this_alloc, &dma_addr);
+					bufIn.len, &dma_addr_in);
+
 			if (bufIn.kptr == NULL) {
 				rc = -ENOMEM;
 				goto done_free_mem;
@@ -2206,11 +2201,7 @@
 				/* Set up this SGE
 				 * Copy to MF and to sglbuf
 				 */
-				mpt_add_sge(psge, flagsLength, dma_addr);
-
-				this_sge->FlagsLength = flagsLength;
-				this_sge->Address = dma_addr;
-				this_sge++;
+				mpt_add_sge(psge, flagsLength, dma_addr_in);
 			}
 		}
 	} else  {
@@ -2234,7 +2225,7 @@
 
 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 		rc = mpt_send_handshake_request(mptctl_id, ioc->id,
-				sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP);
+				sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
 		if (rc == 0) {
 			wait_event(mptctl_wait, ioc->ioctl->wait_done);
 		} else {
@@ -2242,45 +2233,41 @@
 			tm_flags_set= 0;
 			del_timer(&ioc->ioctl->timer);
 			ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE;
-			ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED;
+			ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED;
+			mpt_free_msg_frame(mptctl_id, ioc->id, mf);
 		}
 	} else {
 		mpt_put_msg_frame(mptctl_id, ioc->id, mf);
 		wait_event(mptctl_wait, ioc->ioctl->wait_done);
 	}
 
-	/* The command is complete.  * Return data to the user.
+	mf = NULL;
+
+	/* MF Cleanup:
+	 * If command failed and failure triggered a diagnostic reset
+	 * OR a diagnostic reset happens during command processing,
+	 * no data, messaging queues are reset (mf cannot be accessed),
+	 * and status is DID_IOCRESET
 	 *
-	 * If command completed,  mf has been freed so cannot
-	 * use this memory.
+	 * If a user-requested bus reset fails to be handshaked, then
+	 * mf is returned to free queue and status is TM_FAILED.
 	 *
-	 * If timeout, a recovery  mechanism has been called.
-	 * Need to free the mf.
+	 * Otherise, the command completed and the mf was freed
+	 # by ISR (mf cannot be touched).
 	 */
 	if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
-
-		/* A timeout - there is no data to return to the
-		 * the user other than an error.
-		 * The timer callback deleted the
+		/* The timer callback deleted the
 		 * timer and reset the adapter queues.
 		 */
 		printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - "
 			"Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__);
 		tm_flags_set= 0;
 		rc = -ETIME;
-
-		/* Free memory and return to the calling function
-		 */
-		goto done_free_mem;
 	} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) {
-		/* User TM request failed!
+		/* User TM request failed! mf has not been freed.
 		 */
 		rc = -ENODATA;
 	} else {
-		/* Callback freed request frame.
-		 */
-		mf = NULL;
-
 		/* If a valid reply frame, copy to the user.
 		 * Offset 2: reply length in U32's
 		 */
@@ -2338,42 +2325,31 @@
 	}
 
 done_free_mem:
-	/* Clear status bits.
-	 */
-	ioc->ioctl->status = 0;
+	/* Clear all status bits except TMTIMER_ACTIVE, this bit is cleared
+	 * upon completion of the TM command.
+	 * ioc->ioctl->status = 0;
+	 */
+	ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_TIMER_ACTIVE | MPT_IOCTL_STATUS_TM_FAILED |
+			MPT_IOCTL_STATUS_COMMAND_GOOD | MPT_IOCTL_STATUS_SENSE_VALID |
+			MPT_IOCTL_STATUS_RF_VALID | MPT_IOCTL_STATUS_DID_IOCRESET);
 
 	if (tm_flags_set)
 		mptctl_free_tm_flags(ioc);
 
-	if (sglbuf) {
-		this_sge = sglbuf;
-
-		/* Free the allocated memory.
-		 */
-		 if (bufOut.kptr != NULL ) {
-			dma_addr = this_sge->Address;
-			this_sge++;	/* go to next structure */
-			this_alloc = bufOut.len;
-			pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *) bufOut.kptr, dma_addr);
-		}
-
-		if (bufIn.kptr != NULL ) {
-			dma_addr = this_sge->Address;
-			this_alloc = bufIn.len;
-
-			pci_free_consistent(ioc->pcidev,
-					this_alloc, (void *) bufIn.kptr, dma_addr);
-		}
-
-		this_alloc = sgSize * sizeof(MptSge_t);
+	/* Free the allocated memory.
+	 */
+	 if (bufOut.kptr != NULL) {
 		pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *) sglbuf, sglbuf_dma);
+			bufOut.len, (void *) bufOut.kptr, dma_addr_out);
+	}
 
+	if (bufIn.kptr != NULL) {
+		pci_free_consistent(ioc->pcidev,
+			bufIn.len, (void *) bufIn.kptr, dma_addr_in);
 	}
 
-	/* mf will be null if allocation failed OR
-	 * if command completed OK (callback freed)
+	/* mf is null if command issued successfully
+	 * otherwise, failure occured after mf acquired.
 	 */
 	if (mf)
 		mpt_free_msg_frame(mptctl_id, ioc->id, mf);
@@ -2393,7 +2369,7 @@
  *		-ENOMEM if memory allocation error
  */
 static int
-mptctl_hp_hostinfo(unsigned long arg)
+mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 {
 	hp_host_info_t	*uarg = (hp_host_info_t *) arg;
 	MPT_ADAPTER		*ioc;
@@ -2404,9 +2380,18 @@
 	CONFIGPARMS		cfg;
 	ConfigPageHeader_t	hdr;
 	int			iocnum;
-	int			rc;
+	int			rc, cim_rev;
 
 	dctlprintk((": mptctl_hp_hostinfo called.\n"));
+	/* Reset long to int. Should affect IA64 and SPARC only
+	 */
+	if (data_size == sizeof(hp_host_info_t))
+		cim_rev = 1;
+	else if (data_size == sizeof(hp_host_info_rev0_t))
+		cim_rev = 0; /* obsolete */
+	else
+		return -EFAULT;
+
 	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
 		printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
 			"Unable to read in hp_host_info struct @ %p\n",
@@ -2436,7 +2421,7 @@
 	karg.bus = pdev->bus->number;
 
 	/* Save the SCSI host no. if
-	 * SCSI driver loaded 
+	 * SCSI driver loaded
 	 */
 	if (ioc->sh != NULL)
 		karg.host_no = ioc->sh->host_no;
@@ -2524,7 +2509,7 @@
 	if (ioc->sh != NULL) {
 		MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
 
-		if (hd) {
+		if (hd && (cim_rev == 1)) {
 			karg.hard_resets = hd->hard_resets;
 			karg.soft_resets = hd->soft_resets;
 			karg.timeouts = hd->timeouts;
@@ -2618,7 +2603,7 @@
 
 		if ((rc = mpt_config(ioc, &cfg)) == 0) {
 			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
-			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ? 
+			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ?
 					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
 
 			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
@@ -2697,7 +2682,7 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
-#define	owner_THIS_MODULE  owner:		THIS_MODULE,
+#define	owner_THIS_MODULE  .owner = THIS_MODULE,
 #else
 #define	owner_THIS_MODULE
 #endif
@@ -2883,6 +2868,8 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		/*{*/
 	err = register_ioctl32_conversion(MPTIOCINFO, NULL);
 	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(MPTIOCINFO1, NULL);
+	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(MPTTARGETINFO, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(MPTTEST, NULL);
@@ -2943,6 +2930,7 @@
 	printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!"
 			" (%d:err=%d)\n", where, err);
 	unregister_ioctl32_conversion(MPTIOCINFO);
+	unregister_ioctl32_conversion(MPTIOCINFO1);
 	unregister_ioctl32_conversion(MPTTARGETINFO);
 	unregister_ioctl32_conversion(MPTTEST);
 	unregister_ioctl32_conversion(MPTEVENTQUERY);
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptctl.h linux-2.4.21-bk4/drivers/message/fusion/mptctl.h
--- linux-2.4.21-bk3/drivers/message/fusion/mptctl.h	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptctl.h	2003-07-08 02:59:43.000000000 -0700
@@ -18,9 +18,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptctl.h,v 1.13 2002/12/03 21:26:33 pdelaney Exp $
+ *  $Id: mptctl.h,v 1.14 2003/03/18 22:49:51 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -90,6 +90,7 @@
 #endif	/*}*/
 
 #define MPTIOCINFO		_IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo)
+#define MPTIOCINFO1		_IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo_rev0)
 #define MPTTARGETINFO		_IOWR(MPT_MAGIC_NUMBER,18,struct mpt_ioctl_targetinfo)
 #define MPTTEST			_IOWR(MPT_MAGIC_NUMBER,19,struct mpt_ioctl_test)
 #define MPTEVENTQUERY		_IOWR(MPT_MAGIC_NUMBER,21,struct mpt_ioctl_eventquery)
@@ -99,7 +100,7 @@
 #define MPTFWREPLACE		_IOWR(MPT_MAGIC_NUMBER,25,struct mpt_ioctl_replace_fw)
 
 /*
- * SPARC PLATFORM REMARK:
+ * SPARC PLATFORM REMARKS:
  * IOCTL data structures that contain pointers
  * will have different sizes in the driver and applications
  * (as the app. will not use 8-byte pointers).
@@ -107,6 +108,8 @@
  * The driver will convert data from
  * mpt_fw_xfer32 (mpt_ioctl_command32) to mpt_fw_xfer (mpt_ioctl_command)
  * internally.
+ *
+ * If data structures change size, must handle as in IOCGETINFO.
  */
 struct mpt_fw_xfer {
 	unsigned int	 iocnum;	/* IOC unit number */
@@ -154,11 +157,11 @@
 struct mpt_ioctl_pci_info {
 	union {
 		struct {
-			unsigned long  deviceNumber   :  5;
-			unsigned long  functionNumber :  3;
-			unsigned long  busNumber      : 24;
+			unsigned int  deviceNumber   :  5;
+			unsigned int  functionNumber :  3;
+			unsigned int  busNumber      : 24;
 		} bits;
-		unsigned long  asUlong;
+		unsigned int  asUlong;
 	} u;
 };
 
@@ -189,6 +192,27 @@
 	struct mpt_ioctl_pci_info  pciInfo; /* Added Rev 1 */
 };
 
+/* Original structure, must always accept these
+ * IOCTLs. 4 byte pads can occur based on arch with
+ * above structure. Wish to re-align, but cannot.
+ */
+struct mpt_ioctl_iocinfo_rev0 {
+	mpt_ioctl_header hdr;
+	int		 adapterType;	/* SCSI or FCP */
+	int		 port;		/* port number */
+	int		 pciId;		/* PCI Id. */
+	int		 hwRev;		/* hardware revision */
+	int		 subSystemDevice;	/* PCI subsystem Device ID */
+	int		 subSystemVendor;	/* PCI subsystem Vendor ID */
+	int		 numDevices;		/* number of devices */
+	int		 FWVersion;		/* FW Version (integer) */
+	int		 BIOSVersion;		/* BIOS Version (integer) */
+	char		 driverVersion[MPT_IOCTL_VERSION_LENGTH];	/* Driver Version (string) */
+	char		 busChangeEvent;
+	char		 hostId;
+	char		 rsvd[2];
+};
+
 /*
  * Device Information Page
  * Report the number of, and ids of, all targets
@@ -318,6 +342,7 @@
 #define CPQFCTS_IOC_MAGIC 'Z'
 #define HP_IOC_MAGIC 'Z'
 #define HP_GETHOSTINFO		_IOR(HP_IOC_MAGIC, 20, hp_host_info_t)
+#define HP_GETHOSTINFO1		_IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t)
 #define HP_GETTARGETINFO	_IOR(HP_IOC_MAGIC, 21, hp_target_info_t)
 
 /* All HP IOCTLs must include this header
@@ -330,7 +355,7 @@
 	unsigned int lun;
 } hp_header_t;
 
-/*  
+/*
  *  Header:
  *  iocnum 	required (input)
  *  host 	ignored	
@@ -353,12 +378,35 @@
 	u32		 bus_phys_width;
 	u32		 base_io_addr;
 	u32		 rsvd;
+	unsigned int	 hard_resets;		/* driver initiated resets */
+	unsigned int	 soft_resets;		/* ioc, external resets */
+	unsigned int	 timeouts;		/* num timeouts */
+} hp_host_info_t;
+
+/* replace ulongs with uints, need to preserve backwards
+ * compatibility.
+ */
+typedef struct _hp_host_info_rev0 {
+	hp_header_t	 hdr;
+	u16		 vendor;
+	u16		 device;
+	u16		 subsystem_vendor;
+	u16		 subsystem_id;
+	u8		 devfn;
+	u8		 bus;
+	ushort		 host_no;		/* SCSI Host number, if scsi driver not loaded*/
+	u8		 fw_version[16];	/* string */	
+	u8		 serial_number[24];	/* string */
+	u32		 ioc_status;	
+	u32		 bus_phys_width;
+	u32		 base_io_addr;
+	u32		 rsvd;
 	unsigned long	 hard_resets;		/* driver initiated resets */
 	unsigned long	 soft_resets;		/* ioc, external resets */
 	unsigned long	 timeouts;		/* num timeouts */
-} hp_host_info_t;
+} hp_host_info_rev0_t;
 
-/*  
+/*
  *  Header:
  *  iocnum 	required (input)
  *  host 	required	
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptlan.c linux-2.4.21-bk4/drivers/message/fusion/mptlan.c
--- linux-2.4.21-bk3/drivers/message/fusion/mptlan.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptlan.c	2003-07-08 02:59:43.000000000 -0700
@@ -26,7 +26,7 @@
  *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
+ *  $Id: mptlan.c,v 1.55 2003/05/07 14:08:32 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -154,7 +154,7 @@
 static int  mpt_lan_reset(struct net_device *dev);
 static int  mpt_lan_close(struct net_device *dev);
 static void mpt_lan_post_receive_buckets(void *dev_id);
-static void mpt_lan_wake_post_buckets_task(struct net_device *dev, 
+static void mpt_lan_wake_post_buckets_task(struct net_device *dev,
 					   int priority);
 static int  mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg);
 static int  mpt_lan_receive_post_reply(struct net_device *dev,
@@ -242,7 +242,7 @@
 			//  would Oops because mf has already been set
 			//  to NULL.  So after return from this func,
 			//  mpt_interrupt() will attempt to put (NULL) mf ptr
-			//  item back onto it's adapter FreeQ - Oops!:-(
+			//  item back onto its adapter FreeQ - Oops!:-(
 			//  It's Ok, since mpt_lan_send_turbo() *currently*
 			//  always returns 0, but..., just in case:
 
@@ -339,12 +339,15 @@
 	struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv;
 
 	dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
 	if (priv->mpt_rxfidx == NULL)
 		return (1);
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		;
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
 		int i;
 		unsigned long flags;
 
@@ -868,7 +871,7 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 static inline 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
  */
 {
@@ -878,8 +881,6 @@
 		if (priority) {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_work(&priv->post_buckets_task);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
-			schedule_task(&priv->post_buckets_task);
 #else
 			queue_task(&priv->post_buckets_task, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
@@ -887,8 +888,6 @@
 		} else {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_delayed_work(&priv->post_buckets_task, 1);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
-			schedule_task(&priv->post_buckets_task);
 #else
 			queue_task(&priv->post_buckets_task, &tq_timer);
 #endif
@@ -1191,7 +1190,7 @@
 			remaining, atomic_read(&priv->buckets_out));
 	
 	if ((remaining < priv->bucketthresh) &&
-	    ((atomic_read(&priv->buckets_out) - remaining) > 
+	    ((atomic_read(&priv->buckets_out) - remaining) >
 	     MPT_LAN_BUCKETS_REMAIN_MISMATCH_THRESH)) {
 		
 		printk (KERN_WARNING MYNAM " Mismatch between driver's "
@@ -1525,7 +1524,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-void __init mpt_lan_exit(void)
+static void mpt_lan_exit(void)
 {
 	int i;
 
@@ -1534,10 +1533,11 @@
 	for (i = 0; mpt_landev[i] != NULL; i++) {
 		struct net_device *dev = mpt_landev[i];
 
-		printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n",
+		printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n",
 			       IOC_AND_NETDEV_NAMES_s_s(dev));
 		unregister_fcdev(dev);
-		mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+		//mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */
+		mpt_landev[i] = NULL;
 	}
 
 	if (LanCtx >= 0) {
@@ -1550,9 +1550,10 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
 MODULE_PARM(tx_max_out_p, "i");
 MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
+#endif
 
 module_init(mpt_lan_init);
 module_exit(mpt_lan_exit);
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptscsih.c linux-2.4.21-bk4/drivers/message/fusion/mptscsih.c
--- linux-2.4.21-bk3/drivers/message/fusion/mptscsih.c	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptscsih.c	2003-07-08 02:59:43.000000000 -0700
@@ -24,9 +24,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Original author: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.106 2003/01/28 21:31:57 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.1.2.4 2003/05/07 14:08:34 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -174,17 +174,14 @@
 static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx);
 static void	post_pendingQ_commands(MPT_SCSI_HOST *hd);
 
-static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
-static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+static int	mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
+static int	mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag);
 
 static int	mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 static int	mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
-#ifdef MPT_SAVE_AUTOSENSE
-static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
-#endif
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
@@ -200,7 +197,7 @@
 static void	mptscsih_domainValidation(void *hd);
 static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
 static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
-static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
@@ -270,6 +267,10 @@
 static struct mptscsih_driver_setup
 	driver_setup = MPTSCSIH_DRIVER_SETUP;
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+static Scsi_Cmnd *foo_to[8];
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private inline routines...
@@ -743,9 +744,9 @@
 
 		atomic_dec(&queue_depth);
 
-		/* writeSDP1 will use the ScsiDoneCtx
-		 * There is no processing for the reply.
-		 * Just return to the calling function.
+		/* Remark: writeSDP1 will use the ScsiDoneCtx
+		 * If a SCSI I/O cmd, device disabled by OS and
+		 * completion done. Cannot touch sc struct. Just free mem.
 		 */
 		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
 			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);
@@ -763,6 +764,26 @@
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	if (ioc->timeout_cnt > 0) {
+		int ii, left = 0;
+
+		for (ii=0; ii < 8; ii++) {
+			if (sc == foo_to[ii]) {
+				printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",
+					ioc->name, sc, jiffies);
+				foo_to[ii] = NULL;
+			}
+			if (foo_to[ii] != NULL)
+				left++;
+		}
+
+		if (left == 0) {
+			ioc->timeout_maxcnt = 0;
+			ioc->timeout_cnt = 0;
+		}
+	}
+#endif
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 
@@ -774,16 +795,13 @@
 			dlen = le32_to_cpu(pScsiReq->DataLength);
 			if (dlen >= SCSI_STD_INQUIRY_BYTES) {
 				mptscsih_initTarget(hd,
-						hd->port,
+						sc->channel,
 						sc->target,
 						pScsiReq->LUN[1],
 						sc->buffer,
 						dlen);
 			}
 		}
-#ifdef MPT_SAVE_AUTOSENSE
-		clear_sense_flag(hd, pScsiReq);
-#endif
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -871,9 +889,6 @@
 			 *  precedence!
 			 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
-#ifdef MPT_SAVE_AUTOSENSE
-			clear_sense_flag(hd, pScsiReq);
-#endif
 			if (scsi_state == 0) {
 				;
 			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -915,7 +930,7 @@
 			     && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
 			   ) {
 				mptscsih_initTarget(hd,
-						hd->port,
+						sc->channel,
 						sc->target,
 						pScsiReq->LUN[1],
 						sc->buffer,
@@ -926,9 +941,6 @@
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
-#ifdef MPT_SAVE_AUTOSENSE
-			clear_sense_flag(hd, pScsiReq);
-#endif
 			if (scsi_state == 0) {
 				;
 			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -999,7 +1011,7 @@
 			     && xfer_cnt >= SCSI_STD_INQUIRY_BYTES
 			   ) {
 				mptscsih_initTarget(hd,
-						hd->port,
+						sc->channel,
 						sc->target,
 						pScsiReq->LUN[1],
 						sc->buffer,
@@ -1238,7 +1250,7 @@
 
 	/* Flush the doneQ.
 	 */
-	dprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
+	dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n"));
 	while (1) {
 		spin_lock_irqsave(&hd->freedoneQlock, flags);
 		if (Q_IS_EMPTY(&hd->doneQ)) {
@@ -1305,6 +1317,22 @@
 	return;
 }
 
+static void
+mptscsih_reset_timeouts (MPT_SCSI_HOST *hd)
+{
+	Scsi_Cmnd	*SCpnt = NULL;
+	int		 ii;
+	int		 max = hd->ioc->req_depth;
+
+	for (ii= 0; ii < max; ii++) {
+		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
+			mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+			dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ",
+				(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+		}
+	}
+}
+
 /*
  *	mptscsih_flush_running_cmds - For each command found, search
  *		Scsi_Host instance taskQ and reply to OS.
@@ -1320,6 +1348,7 @@
 {
 	Scsi_Cmnd	*SCpnt = NULL;
 	MPT_FRAME_HDR	*mf = NULL;
+	MPT_DONE_Q	*buffer = NULL;
 	int		 ii;
 	int		 max = hd->ioc->req_depth;
 
@@ -1333,7 +1362,6 @@
 
 			/* Command found.
 			 */
-
 #ifndef MPT_SCSI_USE_NEW_EH
 			/* Search taskQ, if found, delete.
 			 */
@@ -1352,11 +1380,9 @@
 			hd->ScsiLookup[ii] = NULL;
 
 			mf = MPT_INDEX_2_MFPTR(hd->ioc, ii);
-			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
-					mf, SCpnt));
+			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n", mf, SCpnt));
 
 			/* Set status, free OS resources (SG DMA buffers)
-			 * Do OS callback
 			 * Free driver resources (chain, msg buffers)
 			 */
 			if (SCpnt->use_sg) {
@@ -1372,87 +1398,45 @@
 			}
 			SCpnt->result = DID_RESET << 16;
 			SCpnt->host_scribble = NULL;
-                        MPT_HOST_LOCK(flags);
-			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
-                        MPT_HOST_UNLOCK(flags);
 
 			/* Free Chain buffers */
 			mptscsih_freeChainBuffers(hd, ii);
 
 			/* Free Message frames */
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
-		}
-	}
-
-	return;
-}
-
-#ifdef DROP_TEST
-/* 	mptscsih_flush_drop_test - Free resources and do callback if
- *		DROP_TEST enabled.
- *
- *	@hd: Pointer to a SCSI HOST structure
- *
- *	Returns: None.
- *
- *	Must be called while new I/Os are being queued.
- */
-static void
-mptscsih_flush_drop_test (MPT_SCSI_HOST *hd)
-{
-	Scsi_Cmnd	*sc;
-	unsigned long	 flags;
-	u16		 req_idx;
 
-	/* Free resources for the drop test MF
-	 * and chain buffers.
-	 */
-	if (dropMfPtr) {
-		req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx);
-		sc = hd->ScsiLookup[req_idx];
-		if (sc == NULL) {
-			printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n",
-					ioc->name);
-		} else {
-			/* unmap OS resources, set status, do callback
-			 * free driver resources
+#if 1
+			/* Post to doneQ, do not reply until POST phase
+			 * of reset handler....prevents new commands from
+			 * being queued.
 			 */
-			if (sc->use_sg) {
-				pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
-					    sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction));
-			} else if (sc->request_bufflen) {
-				scPrivate	*my_priv;
+			spin_lock_irqsave(&hd->freedoneQlock, flags);
+			if (!Q_IS_EMPTY(&hd->freeQ)) {
+				buffer = hd->freeQ.head;
+				Q_DEL_ITEM(buffer);
 
-				my_priv = (scPrivate *) &sc->SCp;
-				pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1,
-					   sc->request_bufflen,
-					   scsi_to_pci_dma_dir(sc->sc_data_direction));
-			}
+				/* Set the Scsi_Cmnd pointer
+				 */
+				buffer->argp = (void *)SCpnt;
 
-			sc->host_scribble = NULL;
-			sc->result = DID_RESET << 16;
-			hd->ScsiLookup[req_idx] = NULL;
-			atomic_dec(&queue_depth);
-			MPT_HOST_LOCK(flags);
-			sc->scsi_done(sc);	/* Issue callback */
-			MPT_HOST_UNLOCK(flags);
+				/* Add to the doneQ
+				 */
+				Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+			} else {
+				spin_unlock_irqrestore(&hd->freedoneQlock, flags);
+				SCpnt->scsi_done(SCpnt);
+			}
+#else
+                        MPT_HOST_LOCK(flags);
+			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */
+                        MPT_HOST_UNLOCK(flags);
+#endif
 		}
-
-		mptscsih_freeChainBuffers(hd, req_idx);
-		mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr);
-		printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n",
-					hd->ioc->name, sc);
-		printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n",
-					hd->ioc->name, dropMfPtr, req_idx);
-		printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n",
-				hd->ioc->name, dropTestNum,
-				dropTestOK, dropTestBad);
 	}
-	dropMfPtr = NULL;
 
 	return;
 }
-#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1630,6 +1614,7 @@
 	int			 sz, ii;
 	int			 numSGE = 0;
 	int			 scale;
+	int			 ioc_cap;
 	u8			*mem;
 
 	if (! BeenHereDoneThat++) {
@@ -1668,265 +1653,287 @@
 
 	this = mpt_adapter_find_first();
 	while (this != NULL) {
-		int	 portnum;
-		for (portnum=0; portnum < this->facts.NumberOfPorts; portnum++) {
+		/* 20010202 -sralston
+		 *  Added sanity check on readiness of the MPT adapter.
+		 */
+		if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
+			printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
+					this->name);
+			continue;
+		}
 
-			/* 20010215 -sralston
-			 *  Added sanity check on SCSI Initiator-mode enabled
-			 *  for this MPT adapter.
-			 */
-			if (!(this->pfacts[portnum].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) {
-				printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
-						this->name);
-				continue;
-			}
+		if (!this->active) {
+			printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
+					this->name);
+			continue;
+		}
+
+
+		/*  Sanity check - ensure at least 1 port is INITIATOR capable
+		 */
+		ioc_cap = 0;
+		for (ii=0; ii < this->facts.NumberOfPorts; ii++) {
+			if (this->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)
+				ioc_cap ++;
+		}
+
+		if (!ioc_cap) {
+			printk(MYIOC_s_WARN_FMT "Skipping because SCSI Initiator mode is NOT enabled!\n",
+					this->name);
+			continue;
+		}
 
-			/* 20010202 -sralston
-			 *  Added sanity check on readiness of the MPT adapter.
-			 */
-			if (this->last_state != MPI_IOC_STATE_OPERATIONAL) {
-				printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",
-						this->name);
-				continue;
-			}
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-			tpnt->proc_dir = &proc_mpt_scsihost;
+		tpnt->proc_dir = &proc_mpt_scsihost;
 #endif
-			tpnt->proc_info = mptscsih_proc_info;
-			sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
-			if (sh != NULL) {
-				spin_lock_irqsave(&this->FreeQlock, flags);
-				sh->io_port = 0;
-				sh->n_io_port = 0;
-				sh->irq = 0;
-
-				/* Yikes!  This is important!
-				 * Otherwise, by default, linux
-				 * only scans target IDs 0-7!
-				 * pfactsN->MaxDevices unreliable
-				 * (not supported in early
-				 *	versions of the FW).
-				 * max_id = 1 + actual max id,
-				 * max_lun = 1 + actual last lun,
-				 *	see hosts.h :o(
+		tpnt->proc_info = mptscsih_proc_info;
+		sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
+		if (sh != NULL) {
+			spin_lock_irqsave(&this->FreeQlock, flags);
+			sh->io_port = 0;
+			sh->n_io_port = 0;
+			sh->irq = 0;
+
+			/* Yikes!  This is important!
+			 * Otherwise, by default, linux
+			 * only scans target IDs 0-7!
+			 * pfactsN->MaxDevices unreliable
+			 * (not supported in early
+			 *	versions of the FW).
+			 * max_id = 1 + actual max id,
+			 * max_lun = 1 + actual last lun,
+			 *	see hosts.h :o(
+			 */
+			if ((int)this->chip_type > (int)FC929)
+				sh->max_id = MPT_MAX_SCSI_DEVICES;
+			else {
+				/* For FC, increase the queue depth
+				 * from MPT_SCSI_CAN_QUEUE (31)
+				 * to MPT_FC_CAN_QUEUE (63).
 				 */
-				if ((int)this->chip_type > (int)FC929)
-					sh->max_id = MPT_MAX_SCSI_DEVICES;
-				else {
-					/* For FC, increase the queue depth
-					 * from MPT_SCSI_CAN_QUEUE (31)
-					 * to MPT_FC_CAN_QUEUE (63).
-					 */
-					sh->can_queue = MPT_FC_CAN_QUEUE;
-					sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
-				}
-				sh->max_lun = MPT_LAST_LUN + 1;
+				sh->can_queue = MPT_FC_CAN_QUEUE;
+				sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+			}
+			sh->max_lun = MPT_LAST_LUN + 1;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
-				sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+			sh->max_sectors = MPT_SCSI_MAX_SECTORS;
 #endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) || defined CONFIG_HIGHIO
-				sh->highmem_io = 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
+			sh->highmem_io = 1;
 #endif
-				sh->this_id = this->pfacts[portnum].PortSCSIID;
+			/* MPI uses {port, bus, id, lun}, but logically maps
+			 * devices on different ports to different buses, i.e.,
+			 * bus 1 may be the 2nd bus on port 0 or the 1st bus on port 1.
+			 * Map bus to channel, ignore port number in SCSI....
+			 *	hd->port = 0;
+			 * If max_channel > 0, need to adjust mem alloc, free, DV
+			 * and all access to VirtDev
+			 */
+			sh->max_channel = 0;
+			sh->this_id = this->pfacts[0].PortSCSIID;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
-				/* OS entry to allow host drivers to force
-				 * a queue depth on a per device basis.
-				 */
-				sh->select_queue_depths = mptscsih_select_queue_depths;
+			/* OS entry to allow host drivers to force
+			 * a queue depth on a per device basis.
+			 */
+			sh->select_queue_depths = mptscsih_select_queue_depths;
 #endif
-				/* Required entry.
-				 */
-				sh->unique_id = this->id;
-
-				/* Verify that we won't exceed the maximum
-				 * number of chain buffers
-				 * We can optimize:  ZZ = req_sz/sizeof(SGE)
-				 * For 32bit SGE's:
-				 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
-				 *               + (req_sz - 64)/sizeof(SGE)
-				 * A slightly different algorithm is required for
-				 * 64bit SGEs.
-				 */
-				scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
-				if (sizeof(dma_addr_t) == sizeof(u64)) {
-					numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-						(this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
-				} else {
-					numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
-						(this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
-				}
-
-				if (numSGE < sh->sg_tablesize) {
-					/* Reset this value */
-					dprintk((MYIOC_s_INFO_FMT
-						 "Resetting sg_tablesize to %d from %d\n",
-						 this->name, numSGE, sh->sg_tablesize));
-					sh->sg_tablesize = numSGE;
-				}
+			/* Required entry.
+			 */
+			sh->unique_id = this->id;
 
-				/* Set the pci device pointer in Scsi_Host structure.
-				 */
-				scsi_set_pci_device(sh, this->pcidev);
+			/* Verify that we won't exceed the maximum
+			 * number of chain buffers
+			 * We can optimize:  ZZ = req_sz/sizeof(SGE)
+			 * For 32bit SGE's:
+			 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
+			 *               + (req_sz - 64)/sizeof(SGE)
+			 * A slightly different algorithm is required for
+			 * 64bit SGEs.
+			 */
+			scale = this->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+			if (sizeof(dma_addr_t) == sizeof(u64)) {
+				numSGE = (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+					(this->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+			} else {
+				numSGE = 1 + (scale - 1) * (this->facts.MaxChainDepth-1) + scale +
+					(this->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+			}
 
-				spin_unlock_irqrestore(&this->FreeQlock, flags);
+			if (numSGE < sh->sg_tablesize) {
+				/* Reset this value */
+				dprintk((MYIOC_s_INFO_FMT
+					 "Resetting sg_tablesize to %d from %d\n",
+					 this->name, numSGE, sh->sg_tablesize));
+				sh->sg_tablesize = numSGE;
+			}
 
-				hd = (MPT_SCSI_HOST *) sh->hostdata;
-				hd->ioc = this;
-				hd->max_sge = sh->sg_tablesize;
+			/* Set the pci device pointer in Scsi_Host structure.
+			 */
+			scsi_set_pci_device(sh, this->pcidev);
 
-				if ((int)this->chip_type > (int)FC929)
-					hd->is_spi = 1;
+			spin_unlock_irqrestore(&this->FreeQlock, flags);
 
-				if (DmpService &&
-				    (this->chip_type == FC919 || this->chip_type == FC929))
-					hd->is_multipath = 1;
+			hd = (MPT_SCSI_HOST *) sh->hostdata;
+			hd->ioc = this;
+			hd->max_sge = sh->sg_tablesize;
 
-				hd->port = 0;		/* FIXME! */
+			if ((int)this->chip_type > (int)FC929)
+				hd->is_spi = 1;
 
-				/* SCSI needs Scsi_Cmnd lookup table!
-				 * (with size equal to req_depth*PtrSz!)
-				 */
-				sz = hd->ioc->req_depth * sizeof(void *);
-				mem = kmalloc(sz, GFP_ATOMIC);
-				if (mem == NULL)
-					goto done;
+			if (DmpService &&
+			    (this->chip_type == FC919 || this->chip_type == FC929))
+				hd->is_multipath = 1;
 
-				memset(mem, 0, sz);
-				hd->ScsiLookup = (struct scsi_cmnd **) mem;
+			/* SCSI needs Scsi_Cmnd lookup table!
+			 * (with size equal to req_depth*PtrSz!)
+			 */
+			sz = hd->ioc->req_depth * sizeof(void *);
+			mem = kmalloc(sz, GFP_ATOMIC);
+			if (mem == NULL)
+				goto done;
 
-				dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-					 this->name, hd->ScsiLookup, sz));
+			memset(mem, 0, sz);
+			hd->ScsiLookup = (struct scsi_cmnd **) mem;
 
-				if (mptscsih_initChainBuffers(hd, 1) < 0)
-					goto done;
+			dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
+				 this->name, hd->ScsiLookup, sz));
 
-				/* Allocate memory for free and doneQ's
-				 */
-				sz = sh->can_queue * sizeof(MPT_DONE_Q);
-				mem = kmalloc(sz, GFP_ATOMIC);
-				if (mem == NULL)
-					goto done;
+			if (mptscsih_initChainBuffers(hd, 1) < 0)
+				goto done;
 
-				memset(mem, 0xFF, sz);
-				hd->memQ = mem;
+			/* Allocate memory for free and doneQ's
+			 */
+			sz = sh->can_queue * sizeof(MPT_DONE_Q);
+			mem = kmalloc(sz, GFP_ATOMIC);
+			if (mem == NULL)
+				goto done;
 
-				/* Initialize the free, done and pending Qs.
-				 */
-				Q_INIT(&hd->freeQ, MPT_DONE_Q);
-				Q_INIT(&hd->doneQ, MPT_DONE_Q);
-				Q_INIT(&hd->pendingQ, MPT_DONE_Q);
-				spin_lock_init(&hd->freedoneQlock);
+			memset(mem, 0xFF, sz);
+			hd->memQ = mem;
 
-				mem = hd->memQ;
-				for (ii=0; ii < sh->can_queue; ii++) {
-					freedoneQ = (MPT_DONE_Q *) mem;
-					Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
-					mem += sizeof(MPT_DONE_Q);
-				}
+			/* Initialize the free, done and pending Qs.
+			 */
+			Q_INIT(&hd->freeQ, MPT_DONE_Q);
+			Q_INIT(&hd->doneQ, MPT_DONE_Q);
+			Q_INIT(&hd->pendingQ, MPT_DONE_Q);
+			spin_lock_init(&hd->freedoneQlock);
+
+			mem = hd->memQ;
+			for (ii=0; ii < sh->can_queue; ii++) {
+				freedoneQ = (MPT_DONE_Q *) mem;
+				Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);
+				mem += sizeof(MPT_DONE_Q);
+			}
 
-				/* Initialize this Scsi_Host
-				 * internal task Q.
-				 */
-				Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
-				hd->taskQcnt = 0;
+			/* Initialize this Scsi_Host
+			 * internal task Q.
+			 */
+			Q_INIT(&hd->taskQ, MPT_FRAME_HDR);
+			hd->taskQcnt = 0;
 
-				/* 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)
-					goto done;
+			/* 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)
+				goto done;
 
-				memset(mem, 0, sz);
-				hd->Targets = (VirtDevice **) mem;
+			memset(mem, 0, sz);
+			hd->Targets = (VirtDevice **) mem;
 
-				dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));
+			dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));
 
 
-				/* Clear the TM flags
-				 */
-				hd->tmPending = 0;
+			/* Clear the TM flags
+			 */
+			hd->tmPending = 0;
 #ifdef MPT_SCSI_USE_NEW_EH
-				hd->tmState = TM_STATE_NONE;
+			hd->tmState = TM_STATE_NONE;
 #endif
-				hd->resetPending = 0;
-				hd->abortSCpnt = NULL;
-				hd->tmPtr = NULL;
-				hd->numTMrequests = 0;
-
-				/* Clear the pointer used to store
-				 * single-threaded commands, i.e., those
-				 * issued during a bus scan, dv and
-				 * configuration pages.
-				 */
-				hd->cmdPtr = NULL;
-
-				/* Attach the SCSI Host to the IOC structure
-				 */
-				this->sh = sh;
+			hd->resetPending = 0;
+			hd->abortSCpnt = NULL;
+			hd->tmPtr = NULL;
+			hd->numTMrequests = 0;
 
-				/* Initialize this SCSI Hosts' timers
-				 * To use, set the timer expires field
-				 * and add_timer
-				 */
-				init_timer(&hd->timer);
-				hd->timer.data = (unsigned long) hd;
-				hd->timer.function = mptscsih_timer_expired;
+			/* Clear the pointer used to store
+			 * single-threaded commands, i.e., those
+			 * issued during a bus scan, dv and
+			 * configuration pages.
+			 */
+			hd->cmdPtr = NULL;
 
-				init_timer(&hd->TMtimer);
-				hd->TMtimer.data = (unsigned long) hd;
-				hd->TMtimer.function = mptscsih_taskmgmt_timeout;
-				hd->qtag_tick = jiffies;
+			/* Attach the SCSI Host to the IOC structure
+			 */
+			this->sh = sh;
 
-				/* Moved Earlier Pam D */
-				/* this->sh = sh;	*/
+			/* Initialize this SCSI Hosts' timers
+			 * To use, set the timer expires field
+			 * and add_timer
+			 */
+			init_timer(&hd->timer);
+			hd->timer.data = (unsigned long) hd;
+			hd->timer.function = mptscsih_timer_expired;
+
+			init_timer(&hd->TMtimer);
+			hd->TMtimer.data = (unsigned long) hd;
+			hd->TMtimer.function = mptscsih_taskmgmt_timeout;
+			hd->qtag_tick = jiffies;
+
+			/* Moved Earlier Pam D */
+			/* this->sh = sh;	*/
+
+#ifdef MPTSCSIH_DBG_TIMEOUT
+			hd->ioc->timeout_hard = 0;
+			hd->ioc->timeout_delta = 30 * HZ;
+			hd->ioc->timeout_maxcnt = 0;
+			hd->ioc->timeout_cnt = 0;
+			for (ii=0; ii < 8; ii++)
+				foo_to[ii] = NULL;
+#endif
 
-				if (hd->is_spi) {
-					/* Update with the driver setup
-					 * values.
-					 */
-					if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
-						hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
-					if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
-						hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
+			if (hd->is_spi) {
+				/* Update with the driver setup
+				 * values.
+				 */
+				if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)
+					hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;
+				if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)
+					hd->ioc->spi_data.minSyncFactor = driver_setup.min_sync_fac;
 
-					if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
-						hd->ioc->spi_data.maxSyncOffset = 0;
+				if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC)
+					hd->ioc->spi_data.maxSyncOffset = 0;
 
-					hd->negoNvram = 0;
+				hd->negoNvram = 0;
 #ifdef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-					hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+				hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 #endif
-					if (driver_setup.dv == 0)
-						hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
+				if (driver_setup.dv == 0)
+					hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
 
-					hd->ioc->spi_data.forceDv = 0;
-					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-						hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
+				hd->ioc->spi_data.forceDv = 0;
+				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+					hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE;
 	
-					if (hd->negoNvram == 0) {
-						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-							hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
-					}
-
-					ddvprintk((MYIOC_s_INFO_FMT
-						"dv %x width %x factor %x \n",
-						hd->ioc->name, driver_setup.dv,
-						driver_setup.max_width,
-						driver_setup.min_sync_fac));
-
+				if (hd->negoNvram == 0) {
+					for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++)
+						hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE;
 				}
 
-				mpt_scsi_hosts++;
+				ddvprintk((MYIOC_s_INFO_FMT
+					"dv %x width %x factor %x \n",
+					hd->ioc->name, driver_setup.dv,
+					driver_setup.max_width,
+					driver_setup.min_sync_fac));
 			}
 
-		}	/* for each adapter port */
+			mpt_scsi_hosts++;
+		}
 
 		this = mpt_adapter_find_next(this);
 	}
@@ -2251,11 +2258,129 @@
 	return ((info.pos > info.offset) ? info.pos - info.offset : 0);
 }
 
+#ifndef MPTSCSIH_DBG_TIMEOUT
 static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len)
 {
 	/* Not yet implemented */
 	return len;
 }
+#else
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c)	((c) - '0')
+#define is_space(c)	((c) == ' ' || (c) == '\t')
+
+#define UC_DBG_TIMEOUT		0x01
+#define UC_DBG_HARDRESET	0x02
+
+static int skip_spaces(char *ptr, int len)
+{
+	int cnt, c;
+
+	for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --);
+
+	return (len - cnt);
+}
+
+static int get_int_arg(char *ptr, int len, ulong *pv)
+{
+	int cnt, c;
+	ulong	v;
+	for (v =  0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) {
+		v = (v * 10) + digit_to_bin(c);
+	}
+
+	if (pv)
+		*pv = v;
+
+	return (len - cnt);
+}
+
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+	int verb_len = strlen(verb);
+
+	if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+		return verb_len;
+	else
+		return 0;
+}
+
+#define SKIP_SPACES(min_spaces)						\
+	if ((arg_len = skip_spaces(ptr,len)) < (min_spaces))		\
+		return -EINVAL;						\
+	ptr += arg_len;							\
+	len -= arg_len;
+
+#define GET_INT_ARG(v)							\
+	if (!(arg_len = get_int_arg(ptr,len, &(v))))			\
+		return -EINVAL;						\
+	ptr += arg_len;							\
+	len -= arg_len;
+
+static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length)
+{
+	char *ptr = buffer;
+	char btmp[24];	/* REMOVE */
+	int arg_len;
+	int len	= length;
+	int cmd;
+	ulong number = 1;
+	ulong delta = 10;
+
+	if ((len > 0) && (ptr[len -1] == '\n'))
+		--len;
+
+	if (len < 22) {
+		strncpy(btmp, buffer, len);
+		btmp[len+1]='\0';
+	} else {
+		strncpy(btmp, buffer, 22);
+		btmp[23]='\0';
+	}
+	printk("user_command:  ioc %d, buffer %s, length %d\n",
+			ioc->id, btmp, length);
+
+	if ((arg_len = is_keyword(ptr, len, "timeout")) != 0)
+		cmd = UC_DBG_TIMEOUT;
+	else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0)
+		cmd = UC_DBG_HARDRESET;
+	else
+		return -EINVAL;
+
+	ptr += arg_len;
+	len -= arg_len;
+
+	switch(cmd) {
+		case UC_DBG_TIMEOUT:
+			SKIP_SPACES(1);
+			GET_INT_ARG(number);
+			SKIP_SPACES(1);
+			GET_INT_ARG(delta);
+			break;
+	}
+
+	printk("user_command: cnt=%ld delta=%ld\n", number, delta);
+
+	if (len)
+		return -EINVAL;
+	else {
+		if (cmd == UC_DBG_HARDRESET) {
+			ioc->timeout_hard = 1;
+		} else if (cmd == UC_DBG_TIMEOUT) {
+			/* process this command ...
+			 */
+			ioc->timeout_maxcnt = 0;
+			ioc->timeout_delta = delta < 2 ? 2 : delta;
+			ioc->timeout_cnt = 0;
+			ioc->timeout_maxcnt = number < 8 ? number: 8;
+		}
+	}
+	/* Not yet implemented */
+	return length;
+}
+#endif
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -2318,19 +2443,6 @@
 #define ADD_INDEX_LOG(req_ent)	do { } while(0)
 #endif
 
-#ifdef	DROP_TEST
-#define DROP_IOC	1	/* IOC to force failures */
-#define DROP_TARGET	3	/* Target ID to force failures */
-#define	DROP_THIS_CMD	10000	/* iteration to drop command */
-static int dropCounter = 0;
-static int dropTestOK = 0;	/* num did good */
-static int dropTestBad = 0;	/* num did bad */
-static int dropTestNum = 0;	/* total = good + bad + incomplete */
-static int numTotCmds = 0;
-static MPT_FRAME_HDR *dropMfPtr = NULL;
-static int numTMrequested = 0;
-#endif
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mptscsih_put_msgframe - Wrapper routine to post message frame to F/W.
@@ -2403,49 +2515,16 @@
 	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
 
-#ifdef MPT_SAVE_AUTOSENSE
-	/* 20000617 -sralston
-	 *  GRRRRR...  Shouldn't have to do this but...
-	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
-	 *  If yes, return cached SenseData.
-	 */
-	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
-		u8 *dest = NULL;
-		int sz;
-
-		if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_SENSE)) {
-			pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;	//sjr-moved-here
-			if (!SCpnt->use_sg) {
-				dest = SCpnt->request_buffer;
-			} else {
-				struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-				if (sg)
-					dest = (u8 *)(ulong)sg_dma_address(sg);
-			}
-
-			if (dest) {
-				sz = MIN (SCSI_STD_SENSE_BYTES, SCpnt->request_bufflen);
-				memcpy(dest, pTarget->sense, sz);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-				SCpnt->resid = SCpnt->request_bufflen - sz;
-#endif
-				SCpnt->result = 0;
-				SCpnt->scsi_done(SCpnt);
-
-				//sjr-moved-up//pTarget->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
-
-				return 0;
-			}
-		}
-	}
-#endif
-
 	if (hd->resetPending) {
 		/* Prevent new commands from being issued
-		 * while reloading the FW.
+		 * while reloading the FW. Reset timer to 60 seconds,
+		 * as the FW can take some time to come ready.
+		 * For New EH, cmds on doneQ posted to FW.
 		 */
 		did_errcode = 1;
+		mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60));
+		dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
 		goto did_error;
 	}
 
@@ -2500,8 +2579,8 @@
 
 	/* Use the above information to set up the message frame
 	 */
-	pScsiReq->TargetID = target;
-	pScsiReq->Bus = hd->port;
+	pScsiReq->TargetID = (u8) target;
+	pScsiReq->Bus = (u8) SCpnt->channel;
 	pScsiReq->ChainOffset = 0;
 	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
 	pScsiReq->CDBLength = SCpnt->cmd_len;
@@ -2554,39 +2633,6 @@
 		hd->ScsiLookup[my_idx] = SCpnt;
 		SCpnt->host_scribble = NULL;
 
-#ifdef	DROP_TEST
-		numTotCmds++;
-		/* If the IOC number and target match, increment
-		 * counter. If counter matches DROP_THIS, do not
-		 * issue command to FW to force a reset.
-		 * Save the MF pointer so we can free resources
-		 * when task mgmt completes.
-		 */
-		if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {
-			dropCounter++;
-
-			if (dropCounter == DROP_THIS_CMD) {
-				dropCounter = 0;
-
-				/* If global is set, then we are already
-				 * doing something - so keep issuing commands.
-				 */
-				if (dropMfPtr == NULL) {
-					dropTestNum++;
-					dropMfPtr = mf;
-					atomic_inc(&queue_depth);
-					printk(MYIOC_s_INFO_FMT
-						"Dropped SCSI cmd (%p)\n",
-						hd->ioc->name, SCpnt);
-					printk("mf (%p) req (%4x) tot cmds (%d)\n",
-						mf, my_idx, numTotCmds);
-
-					return 0;
-				}
-			}
-		}
-#endif
-
 		/* SCSI specific processing */
 		issueCmd = 1;
 		if (hd->is_spi) {
@@ -2639,6 +2685,18 @@
 			}
 		}
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+		if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) {
+			foo_to[hd->ioc->timeout_cnt] = SCpnt;
+			hd->ioc->timeout_cnt++;
+			//mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta);
+			issueCmd = 0;
+			printk(MYIOC_s_WARN_FMT
+				"to pendingQ: (sc=%p, mf=%p, time=%ld)\n",
+				hd->ioc->name, SCpnt, mf, jiffies);
+		}
+#endif
+
 		if (issueCmd) {
 			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
 			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
@@ -2682,6 +2740,8 @@
 	SCpnt->result = (DID_BUS_BUSY << 16);
 	spin_lock_irqsave(&hd->freedoneQlock, flags);
 	if (!Q_IS_EMPTY(&hd->freeQ)) {
+		dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n",
+			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
 		buffer = hd->freeQ.head;
 		Q_DEL_ITEM(buffer);
 
@@ -2777,7 +2837,7 @@
  *	Returns 0 for SUCCESS or -1 if FAILED.
  */
 static int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
 	MPT_ADAPTER	*ioc = NULL;
 	int		 rc = -1;
@@ -2792,19 +2852,18 @@
 		return 0;
 
 	ioc = hd->ioc;
-	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
-
 	if (ioc == NULL) {
 		printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
-		return 0;
+		return FAILED;
 	}
+	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
 
 	// SJR - CHECKME - Can we avoid this here?
 	// (mpt_HardResetHandler has this check...)
 	spin_lock_irqsave(&ioc->diagLock, flags);
 	if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) {
 		spin_unlock_irqrestore(&ioc->diagLock, flags);
-		return 0;
+		return FAILED;
 	}
 	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
@@ -2814,6 +2873,39 @@
 	if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM)
 		doTask = 0;
 
+#ifdef MPT_SCSI_USE_NEW_EH
+	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
+	 *  If we time out and not bus reset, then we return a FAILED status to the caller.
+	 *  The call to mptscsih_tm_pending_wait() will set the pending flag if we are
+	 *  successful. Otherwise, reload the FW.
+	 */
+	if (mptscsih_tm_pending_wait(hd) == FAILED) {
+		if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+			nehprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			return FAILED;
+		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
+			nehprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			return FAILED;
+		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
+			nehprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: "
+			   "Timed out waiting for last TM (%d) to complete! \n",
+			   hd->ioc->name, hd->tmPending));
+			if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
+				return FAILED;
+				
+			doTask = 0;
+		}
+	} else {
+		spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+		hd->tmPending |=  (1 << type);
+		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+	}
+#endif
+
 	/* Is operational?
 	 */
 	ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
@@ -2821,7 +2913,7 @@
 #ifdef MPT_DEBUG_RESET
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
 		printk(MYIOC_s_WARN_FMT
-			"TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n",
+			"TM Handler: IOC Not operational(0x%x)!\n",
 			hd->ioc->name, ioc_raw_state);
 	}
 #endif
@@ -2833,23 +2925,23 @@
 		 */
 		if (hd->hard_resets < -1)
 			hd->hard_resets++;
-		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
+		rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, sleepFlag);
 		if (rc) {
 			printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
 		} else {
 			dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
 		}
 	}
-#ifdef DROP_TEST
-	numTMrequested++;
-	if (numTMrequested > 5) {
-		rc = 0;		/* set to 1 to force a hard reset */
-		numTMrequested = 0;
-	}
+#ifdef MPTSCSIH_DBG_TIMEOUT
+	if (hd->ioc->timeout_hard)
+		rc = 1;
 #endif
 
-	if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) {
-		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
+	/* Only fall through to the HRH if this is a bus reset
+	 */
+	if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
+		ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
+		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
 			 hd->ioc->name));
 		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
 	}
@@ -2863,7 +2955,6 @@
 	return rc;
 }
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
@@ -2883,7 +2974,7 @@
  *	else other non-zero value returned.
  */
 static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, int sleepFlag)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, int sleepFlag)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
@@ -2905,7 +2996,7 @@
 	 */
 	pScsiTm = (SCSITaskMgmt_t *) mf;
 	pScsiTm->TargetID = target;
-	pScsiTm->Bus = hd->port;
+	pScsiTm->Bus = channel;
 	pScsiTm->ChainOffset = 0;
 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
 
@@ -2979,6 +3070,9 @@
 		return FAILED;
 	}
 
+	if (hd->resetPending)
+		return FAILED;
+
 	printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n",
 	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
 
@@ -3001,19 +3095,6 @@
 		return SUCCESS;
 	}
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
-	if (mptscsih_tm_pending_wait(hd) == FAILED){
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		return FAILED;
-	}
-
 	/* If this command is pended, then timeout/hang occurred
 	 * during DV. Post command and flush pending Q
 	 * and then following up with the reset request.
@@ -3022,7 +3103,7 @@
 		mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);
 		post_pendingQ_commands(hd);
 		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
-			   "Found command in pending queue! (sc=%p)\n",
+			   "Posting pended cmd! (sc=%p)\n",
 			   hd->ioc->name, SCpnt));
 	}
 
@@ -3038,7 +3119,7 @@
 
 	hd->abortSCpnt = SCpnt;
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-	                       SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
+	                       SCpnt->channel, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP)
 		< 0) {
 
 		/* The TM request failed and the subsequent FW-reload failed!
@@ -3081,29 +3162,19 @@
 		return FAILED;
 	}
 
+	if (hd->resetPending)
+		return FAILED;
+
 	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n",
 	       hd->ioc->name, SCpnt, atomic_read(&queue_depth));
 
-	/* Unsupported for SCSI. Suppored for FCP
+	/* Unsupported for SCSI. Supported for FCP
 	 */
 	if (hd->is_spi)
 		return FAILED;
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
-	if (mptscsih_tm_pending_wait(hd) == FAILED) {
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		return FAILED;
-	}
-
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-	                       SCpnt->target, 0, 0, NO_SLEEP)
+	                       SCpnt->channel, SCpnt->target, 0, 0, NO_SLEEP)
 		< 0){
 		/* The TM request failed and the subsequent FW-reload failed!
 		 * Fatal error case.
@@ -3147,22 +3218,9 @@
 	if (hd->timeouts < -1)
 		hd->timeouts++;
 
-	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
-	 *  If we time out, then we return a FAILED status to the caller.  This
-	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
-	 *  successful.
-	 */
-	if (mptscsih_tm_pending_wait(hd) == FAILED) {
-		nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: "
-			   "Timed out waiting for previous TM to complete! "
-			   "(sc = %p)\n",
-			   hd->ioc->name, SCpnt));
-		return FAILED;
-	}
-
 	/* We are now ready to execute the task management request. */
 	if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-	                       0, 0, 0, NO_SLEEP)
+	                       SCpnt->channel, 0, 0, 0, NO_SLEEP)
 	    < 0){
 
 		/* The TM request failed and the subsequent FW-reload failed!
@@ -3241,7 +3299,7 @@
 mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
 {
 	unsigned long  flags;
-	int            loop_count = 60 * 4;  /* Wait 60 seconds */
+	int            loop_count = 2 * 10 * 4;  /* Wait 2 seconds */
 	int            status = FAILED;
 
 	do {
@@ -3254,6 +3312,8 @@
 			break;
 		}
 		spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+		//set_current_state(TASK_INTERRUPTIBLE);
+		//schedule_timeout(HZ/4);
 		mdelay(250);
 	} while (--loop_count);
 
@@ -3382,10 +3442,6 @@
 		mytaskQ_bh_active = 1;
 		spin_unlock_irqrestore(&mytaskQ_lock, flags);
 
-		/*
-		 *  Oh how cute, no alloc/free/mgmt needed if we use
-		 *  (bottom/unused portion of) MPT request frame.
-		 */
 		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
 		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt);
 
@@ -3570,6 +3626,15 @@
 					continue;
 				}
 
+#ifdef MPTSCSIH_DBG_TIMEOUT
+				if (ioc->timeout_hard == 1) {
+					mptscsih_TMHandler(hd, 
+						MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 
+						0, 0, 0, 0, CAN_SLEEP);
+
+				}
+#endif
+
 				spin_lock_irqsave(&ioc->FreeQlock, flags);
 				if (Q_IS_EMPTY(&hd->taskQ)) {
 					spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -3662,7 +3727,9 @@
 				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 				mf = NULL;
 
-				if (mptscsih_TMHandler(hd, task_type, SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) < 0) {
+				if (mptscsih_TMHandler(hd, task_type, SCpnt->channel,
+						      SCpnt->target, SCpnt->lun,
+						       ctx2abort, CAN_SLEEP) < 0) {
 
 					/* The TM request failed and the subsequent FW-reload failed!
 					 * Fatal error case.
@@ -3768,10 +3835,7 @@
 			 */
 			if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
 				hd->abortSCpnt = NULL;
-#ifdef	DROP_TEST
-			if (dropMfPtr)
-				dropTestBad++;
-#endif
+
 			/* If an internal command is present
 			 * or the TM failed - reload the FW.
 			 * FC FW may respond FAILED to an ABORT
@@ -3805,17 +3869,9 @@
 			hd->abortSCpnt = NULL;
 			flush_doneQ(hd);
 
-#ifdef	DROP_TEST
-			if (dropMfPtr)
-				dropTestOK++;
-#endif
 		}
 	}
 
-#ifdef	DROP_TEST
-	mptscsih_flush_drop_test(hd);
-#endif
-
 #ifndef MPT_SCSI_USE_NEW_EH
 	/*
 	 *  Signal to _bh thread that we finished.
@@ -3840,19 +3896,9 @@
  *	This is anyones guess quite frankly.
  */
 int
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
-mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
-		sector_t capacity, int *ip)
-{
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-mptscsih_bios_param(Disk * disk, struct block_device *bdev, int *ip)
-{
-	sector_t capacity = disk->capacity;
-#else
 mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
 {
 	unsigned capacity = disk->capacity;
-#endif
 	int size;
 
 	size = capacity;
@@ -3872,43 +3918,6 @@
  *	Called once per device the bus scan. Use it to force the queue_depth
  *	member to 1 if a device does not support Q tags.
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
-int
-mptscsih_slave_attach(Scsi_Device *device)
-{
-	struct Scsi_Host	*host = device->host;
-	VirtDevice		*pTarget;
-	MPT_SCSI_HOST		*hd;
-
-	hd = (MPT_SCSI_HOST *)host->hostdata;
-	if (hd && (hd->Targets != NULL)) {
-		pTarget = hd->Targets[device->id];
-		if (pTarget) {
-			if (!device->tagged_supported ||
-			    !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) {
-				scsi_adjust_queue_depth(device, 0, 1);
-
-			} else if ((pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)
-				   && (pTarget->inq_data[0] & 0x1f) == 0x00
-				   && (pTarget->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
-				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-							MPT_SCSI_CMD_PER_DEV_HIGH);
-			} else {
-				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-							MPT_SCSI_CMD_PER_DEV_LOW);
-			}
-#if 0
-			/* Original Code for 2.5 */
-			} else {
-				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-						device->host->can_queue >> 1);
-			}
-#endif
-		}
-	}
-	return 0;
-}
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
 void
 mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList)
 {
@@ -3951,14 +3960,21 @@
 				/* error case - No Inq. Data */
 				device->queue_depth = 1;
 			}
-			dprintk((MYIOC_s_INFO_FMT
-				 "target = %d, sync factor = %x, queue depth = %d\n",
-				 hd->ioc->name, pTarget->target_id,
-				 pTarget->minSyncFactor, device->queue_depth));
+
+			if (pTarget != NULL) {
+				printk(MYIOC_s_INFO_FMT
+					 "scsi%d: Id=%d Lun=%d: Queue depth=%d\n",
+					 hd->ioc->name, sh->host_no,
+					 device->id, device->lun, device->queue_depth);
+
+				dprintk((MYIOC_s_INFO_FMT
+					 "Id = %d, sync factor = %x\n",
+					 hd->ioc->name, pTarget->target_id,
+					 pTarget->minSyncFactor));
+			}
 		}
 	}
 }
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -3997,34 +4013,6 @@
 		sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
 		memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
 
-		/* save sense data to the target device
-		 */
-		if (hd->is_spi && target) {
-#ifdef MPT_SAVE_AUTOSENSE
-			int sz;
-
-			sz = MIN(pReq->SenseBufferLength, sense_count);
-			if (sz > SCSI_STD_SENSE_BYTES)
-				sz =  SCSI_STD_SENSE_BYTES;
-			memcpy(target->sense, sense_data, sz);
-			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
-#endif
-
-#ifdef ABORT_FIX
-			if (sz >= SCSI_STD_SENSE_BYTES) {
-				if ((sense_data[02] == ABORTED_COMMAND) &&
-					(sense_data[12] == 0x47) && (sense_data[13] == 0x00)){
-					target->numAborts++;
-					if ((target->raidVolume == 0) && (target->numAborts > 5)) {
-						target->numAborts = 0;
-						target->minSyncFactor++;
-						hd->ioc->spi_data.dvStatus[index] |= MPT_SCSICFG_NEGOTIATE;
-					}
-				}
-			}
-#endif
-		}
-
 		/* Log SMART data (asc = 0x5D, non-IM case only) if required.
 		 */
 		if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
@@ -4207,7 +4195,8 @@
 
 	dtmprintk((KERN_WARNING MYNAM
 			": IOC %s_reset routed to SCSI host driver!\n",
-			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"));
+			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
 	/* If a FW reload request arrives after base installed but
 	 * before all scsi hosts have been attached, then an alt_ioc
@@ -4218,28 +4207,26 @@
 	else
 		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
-	if (reset_phase == MPT_IOC_PRE_RESET) {
-		dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n",
-			ioc->name));
-
+	if (reset_phase == MPT_IOC_SETUP_RESET) {
+		dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
 		/* Clean Up:
 		 * 1. Set Hard Reset Pending Flag
 		 * All new commands go to doneQ
 		 */
 		hd->resetPending = 1;
 
+		/* 2. Reset timeouts on all running commands
+		 */
+		mptscsih_reset_timeouts (hd);
+
+	} else if (reset_phase == MPT_IOC_PRE_RESET) {
+		dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
+
 		/* 2. Flush running commands
-		 *	Clean drop test code - if compiled
 		 *	Clean ScsiLookup (and associated memory)
 		 *	AND clean mytaskQ
 		 */
 
-		/* 2a. Drop Test Command.
-		 */
-#ifdef	DROP_TEST
-		mptscsih_flush_drop_test(hd);
-#endif
-
 		/* 2b. Reply to OS all known outstanding I/O commands.
 		 */
 		mptscsih_flush_running_cmds(hd);
@@ -4269,14 +4256,16 @@
 		 */
 		clean_taskQ(hd);
 #endif
-		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n",
-			ioc->name));
+		
+#ifdef MPTSCSIH_DBG_TIMEOUT
+		ioc->timeout_hard = 0;
+#endif
 
+		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
 	} else {
 		ScsiCfgData	*pSpi = NULL;
 
-		dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n",
-			ioc->name));
+		dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
 
 		/* Once a FW reload begins, all new OS commands are
 		 * redirected to the doneQ w/ a reset status.
@@ -4335,16 +4324,15 @@
 		 */
 		flush_doneQ(hd);
 
-		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n",
-			ioc->name));
-
-
-		/* 8. Set then flag to force DV and re-read IOC Page 3
+		/* 8. Set flag to force DV and re-read IOC Page 3
 		 */
-		pSpi = &ioc->spi_data;
-		pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
-		ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+		if (hd->is_spi) {
+			pSpi = &ioc->spi_data;
+			pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+			ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+		}
 
+		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 	}
 
 	return 1;		/* currently means nothing really */
@@ -4800,7 +4788,7 @@
 	/*
 	 * Need to check ASC here; if it is "special," then
 	 * the ASCQ is variable, and indicates failed component number.
-	 * We must treat the ASCQ as a "dont care" while searching the
+	 * We must treat the ASCQ as a "don't care" while searching the
 	 * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later
 	 * on when we actually need to identify the failed component.
 	 */
@@ -5079,7 +5067,7 @@
 	u8 factor = MPT_ASYNC;
 	u8 offset = 0;
 	u8 version, nfactor;
-	u8 noQas = 1;
+	u8 noQas = 0;
 
 	ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
 
@@ -5090,9 +5078,20 @@
 		}
 		return;
 	}
+
+	/* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
+	 * support. If available, default QAS to off and allow enabling.
+	 * If not available, default QAS to on, turn off for non-disks.
+	 */
+	if (target->tflags & MPT_TARGET_FLAGS_VALID_56)
+		noQas = 1;
+
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+		if ((target->inq_data[0] & 0x1F) != 0x00)
+			noQas = 1;
+
 		version = target->inq_data[2] & 0x07;
 		if (version < 2) {
 			width = 0;
@@ -5200,7 +5199,7 @@
 
 		/* Disable QAS if mixed configuration case
 		 */
-		if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) == 0x00)){
+		if ((noQas) && (!pspi_data->noQas) && ((target->inq_data[0] & 0x1F) != 0x03)){
 			VirtDevice	*vdev;
 			int ii;
 
@@ -5212,29 +5211,10 @@
 					vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
 			}
 		}
-
-	}
-
-	return;
-}
-
-#ifdef MPT_SAVE_AUTOSENSE
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *  Clear sense valid flag.
- */
-static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
-{
-	VirtDevice	*target;
-	int		 index = (int) pReq->TargetID;
-
-	if ((target = hd->Targets[index])) {
-		target->tflags &= ~MPT_TARGET_FLAGS_VALID_SENSE;
 	}
 
 	return;
 }
-#endif
 
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks)
@@ -5637,10 +5617,6 @@
 
 	/* If target struct exists, clear sense valid flag.
 	 */
-#ifdef MPT_SAVE_AUTOSENSE
-	clear_sense_flag(hd, pReq);
-#endif
-
 	if (mr == NULL) {
 		completionCode = MPT_SCANDV_GOOD;
 	} else {
@@ -5691,13 +5667,10 @@
 					completionCode = MPT_SCANDV_SOME_ERROR;
 
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
-#ifdef MPT_SAVE_AUTOSENSE
-				VirtDevice	*target;
-#endif
 				u8		*sense_data;
 				int		 sz;
 
-				/* save sense data in global & target structure
+				/* save sense data in global structure
 				 */
 				completionCode = MPT_SCANDV_SENSE;
 				hd->pLocal->scsiStatus = pReply->SCSIStatus;
@@ -5708,15 +5681,6 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
-#ifdef MPT_SAVE_AUTOSENSE
-				target = hd->Targets[pReq->TargetID];
-				if (target) {
-					memcpy(target->sense, sense_data, sz);
-					target->tflags
-						|= MPT_TARGET_FLAGS_VALID_SENSE;
-				}
-#endif
-
 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
 						sense_data));
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
@@ -5799,6 +5763,8 @@
 			 *	for bus reset.
 			 */
 #ifndef MPT_SCSI_USE_NEW_EH
+			SCSIIORequest_t	*pReq = (SCSIIORequest_t *) hd->cmdPtr;
+
 			spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
 			if (hd->tmPending) {
 				spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
@@ -5806,9 +5772,8 @@
 			} else
 				hd->tmPending = 1;
 			spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-
 			if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-							0, 0, 0, NO_SLEEP) < 0) {
+							pReq->Bus, 0, 0, 0, NO_SLEEP) < 0) {
 				printk(MYIOC_s_WARN_FMT "TM FAILED!\n", hd->ioc->name);
 			}
 #else
@@ -6527,7 +6492,7 @@
  *	Return: None.
  */
 static int
-mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
+mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
 	VirtDevice		*pTarget = NULL;
@@ -6555,6 +6520,7 @@
 	int			 patt;
 	int			 repeat;
 	int			 retcode = 0;
+	int			 nfactor =  MPT_ULTRA320;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -6567,11 +6533,14 @@
 	if (ioc->spi_data.sdp0length == 0)
 		return 0;
 
-	if (id == ioc->pfacts[portnum].PortSCSIID)
+	/* If multiple buses are used, require that the initiator
+	 * id be the same on all buses.
+	 */
+	if (id == ioc->pfacts[0].PortSCSIID)
 		return 0;
 
 	lun = 0;
-	bus = 0;
+	bus = (u8) bus_number;
 	ddvtprintk((MYIOC_s_NOTE_FMT
 			"DV started: numIOs %d bus=%d, id %d dv @ %p\n",
 			ioc->name, atomic_read(&queue_depth), bus, id, &dv));
@@ -6676,16 +6645,33 @@
 
 	/* Skip this ID? Set cfg.hdr to force config page write
 	 */
-	if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) &&
-			(!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) {
-
-		ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
-			ioc->name, bus, id, lun));
-
-		dv.cmd = MPT_SET_MAX;
-		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
-		cfg.hdr = &header1;
-		goto target_done;
+	{
+		ScsiCfgData *pspi_data = &hd->ioc->spi_data;
+		if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+			/* Set the factor from nvram */
+			nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
+			if (nfactor < pspi_data->minSyncFactor )
+				nfactor = pspi_data->minSyncFactor;
+	
+			if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE)) {
+	
+				ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+					ioc->name, bus, id, lun));
+	
+				dv.cmd = MPT_SET_MAX;
+				mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+				cfg.hdr = &header1;
+	
+				/* Save the final negotiated settings to
+				 * SCSI device page 1.
+				 */
+				cfg.physAddr = cfg1_dma_addr;
+				cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+				cfg.dir = 1;
+				mpt_config(hd->ioc, &cfg);
+				goto target_done;
+			}
+		}
 	}
 
 	/* Finish iocmd inititialization - hidden or visible disk? */
@@ -6807,6 +6793,14 @@
 			}
 		}
 
+		/* Reset the size for disks
+		 */
+		inq0 = (*pbuf1) & 0x1F;
+		if ((inq0 == 0) && pTarget && !pTarget->raidVolume) {
+			sz = 0x40;
+			iocmd.size = sz;
+		}
+
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
@@ -6816,6 +6810,26 @@
 		if (mptscsih_do_cmd(hd, &iocmd) < 0)
 			goto target_done;
 
+		if (sz == 0x40) {
+			if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
+				&& (pTarget->minSyncFactor > 0x09)) {
+				if ((pbuf1[56] & 0x04) == 0)
+					;
+				else if ((pbuf1[56] & 0x01) == 1) {
+					pTarget->minSyncFactor = nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
+				} else {
+					pTarget->minSyncFactor = nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
+				}
+
+				dv.max.factor = pTarget->minSyncFactor;
+
+				if ((pbuf1[56] & 0x02) == 0) {
+					pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+					hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+				}
+			}
+		}
+
 		if (doFallback)
 			dv.cmd = MPT_FALLBACK;
 		else
@@ -7323,19 +7337,16 @@
 		dv.cmd = MPT_SAVE;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
-#if 0	
-	/* Double writes to SDP1 can cause problems,
-	 * skip here since unnecessary
-	 */
-		/* Save the final negotiated settings to
+		/* Double writes to SDP1 can cause problems,
+		 * skip save of the final negotiated settings to
 		 * SCSI device page 1.
-		 */
+		 *
 		cfg.hdr = &header1;
 		cfg.physAddr = cfg1_dma_addr;
 		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
 		cfg.dir = 1;
 		mpt_config(hd->ioc, &cfg);
-#endif
+		 */
 	}
 
 	/* If this is a RAID Passthrough, enable internal IOs
diff -urN linux-2.4.21-bk3/drivers/message/fusion/mptscsih.h linux-2.4.21-bk4/drivers/message/fusion/mptscsih.h
--- linux-2.4.21-bk3/drivers/message/fusion/mptscsih.h	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/mptscsih.h	2003-07-08 02:59:43.000000000 -0700
@@ -18,9 +18,9 @@
  *  Copyright (c) 1999-2002 LSI Logic Corporation
  *  Originally By: Steven J. Ralston
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.22 2002/12/16 15:28:48 pdelaney Exp $
+ *  $Id: mptscsih.h,v 1.1.2.2 2003/05/07 14:08:35 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -72,7 +72,7 @@
 /*
  *	Try to keep these at 2^N-1
  */
-#define MPT_FC_CAN_QUEUE	63
+#define MPT_FC_CAN_QUEUE	127
 #if defined MPT_SCSI_USE_NEW_EH
 	#define MPT_SCSI_CAN_QUEUE	127
 #else
@@ -217,11 +217,7 @@
 #define x_scsi_taskmgmt_bh	mptscsih_taskmgmt_bh
 #define x_scsi_old_abort	mptscsih_old_abort
 #define x_scsi_old_reset	mptscsih_old_reset
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
-#define x_scsi_slave_attach	mptscsih_slave_attach
-#else
 #define x_scsi_select_queue_depths	mptscsih_select_queue_depths
-#endif
 #define x_scsi_proc_info	mptscsih_proc_info
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -241,86 +237,18 @@
 extern	int		 x_scsi_old_abort(Scsi_Cmnd *);
 extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
 #endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
-extern int		 x_scsi_bios_param(struct scsi_device * sdev, struct block_device *bdev,
-				sector_t capacity, int *ip);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-extern	int		 x_scsi_bios_param(Disk *, struct block_device *, int *);
-#else
 extern	int		 x_scsi_bios_param(Disk *, kdev_t, int *);
-#endif
 extern	void		 x_scsi_taskmgmt_bh(void *);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
-extern	int		 x_scsi_slave_attach(Scsi_Device *);
-#else
 extern	void		 x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
-#endif
-
 extern	int		 x_scsi_proc_info(char *, char **, off_t, int, int, int);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #define PROC_SCSI_DECL
 #else
-#define PROC_SCSI_DECL  proc_name: "mptscsih",
+#define PROC_SCSI_DECL  .proc_name = "mptscsih",
 #endif
 
 #ifdef MPT_SCSI_USE_NEW_EH
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
-
-#define MPT_SCSIHOST {						\
-	PROC_SCSI_DECL						\
-	.proc_info			= x_scsi_proc_info,	\
-	.name				= "MPT SCSI Host",	\
-	.detect				= x_scsi_detect,	\
-	.release			= x_scsi_release,	\
-	.info				= x_scsi_info,		\
-	.command			= NULL,			\
-	.queuecommand			= x_scsi_queuecommand,	\
-	.slave_attach			= x_scsi_slave_attach,	\
-	.eh_strategy_handler		= NULL,			\
-	.eh_abort_handler		= x_scsi_abort,		\
-	.eh_device_reset_handler	= x_scsi_dev_reset,	\
-	.eh_bus_reset_handler		= x_scsi_bus_reset,	\
-	.eh_host_reset_handler		= x_scsi_host_reset,	\
-	.bios_param			= x_scsi_bios_param,	\
-	.can_queue			= MPT_SCSI_CAN_QUEUE,	\
-	.this_id			= -1,			\
-	.sg_tablesize			= MPT_SCSI_SG_DEPTH,	\
-	.max_sectors			= MPT_SCSI_MAX_SECTORS,	\
-	.cmd_per_lun			= MPT_SCSI_CMD_PER_LUN,	\
-	.unchecked_isa_dma		= 0,			\
-	.use_clustering			= ENABLE_CLUSTERING,	\
-}
-
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
-
-#define MPT_SCSIHOST {						\
-	PROC_SCSI_DECL						\
-	.proc_info			= x_scsi_proc_info,	\
-	.name				= "MPT SCSI Host",	\
-	.detect				= x_scsi_detect,	\
-	.release			= x_scsi_release,	\
-	.info				= x_scsi_info,		\
-	.command			= NULL,			\
-	.queuecommand			= x_scsi_queuecommand,	\
-	.eh_strategy_handler		= NULL,			\
-	.eh_abort_handler		= x_scsi_abort,		\
-	.eh_device_reset_handler	= x_scsi_dev_reset,	\
-	.eh_bus_reset_handler		= x_scsi_bus_reset,	\
-	.eh_host_reset_handler		= x_scsi_host_reset,	\
-	.bios_param			= x_scsi_bios_param,	\
-	.can_queue			= MPT_SCSI_CAN_QUEUE,	\
-	.this_id			= -1,			\
-	.sg_tablesize			= MPT_SCSI_SG_DEPTH,	\
-	.max_sectors			= MPT_SCSI_MAX_SECTORS,	\
-	.cmd_per_lun			= MPT_SCSI_CMD_PER_LUN,	\
-	.unchecked_isa_dma		= 0,			\
-	.use_clustering			= ENABLE_CLUSTERING,	\
-}
-
-#else  /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
-
 #define MPT_SCSIHOST {						\
 	.next				= NULL,			\
 	PROC_SCSI_DECL						\
@@ -346,8 +274,6 @@
 	.use_new_eh_code		= 1			\
 }
 
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */
-
 #else /* MPT_SCSI_USE_NEW_EH */
 
 #define MPT_SCSIHOST {						\
diff -urN linux-2.4.21-bk3/drivers/message/fusion/scsi3.h linux-2.4.21-bk4/drivers/message/fusion/scsi3.h
--- linux-2.4.21-bk3/drivers/message/fusion/scsi3.h	2003-07-08 02:59:32.000000000 -0700
+++ linux-2.4.21-bk4/drivers/message/fusion/scsi3.h	2003-07-08 02:59:43.000000000 -0700
@@ -7,7 +7,7 @@
  *  Copyright (c) 1996-2002 Steven J. Ralston
  *  Written By: Steven J. Ralston (19960517)
  *  (mailto:sjralston1@netscape.net)
- *  (mailto:lstephen@lsil.com)
+ *  (mailto:lstephens@lsil.com)
  *
  *  $Id: scsi3.h,v 1.9 2002/02/27 18:45:02 sralston Exp $
  */
diff -urN linux-2.4.21-bk3/drivers/mtd/chips/gen_probe.c linux-2.4.21-bk4/drivers/mtd/chips/gen_probe.c
--- linux-2.4.21-bk3/drivers/mtd/chips/gen_probe.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.21-bk4/drivers/mtd/chips/gen_probe.c	2003-07-08 02:59:43.000000000 -0700
@@ -277,6 +277,7 @@
 
 extern cfi_cmdset_fn_t cfi_cmdset_0001;
 extern cfi_cmdset_fn_t cfi_cmdset_0002;
+extern cfi_cmdset_fn_t cfi_cmdset_0020;
 
 static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 
 						  int primary)
diff -urN linux-2.4.21-bk3/drivers/net/eexpress.c linux-2.4.21-bk4/drivers/net/eexpress.c
--- linux-2.4.21-bk3/drivers/net/eexpress.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.21-bk4/drivers/net/eexpress.c	2003-07-08 02:59:44.000000000 -0700
@@ -654,7 +654,7 @@
 		buf = skb_padto(buf, ETH_ZLEN);
 		if(buf == NULL)
 			return 0;
-		length = buf->len;
+		length = ETH_ZLEN;
 	}
 
 	disable_irq(dev->irq);
diff -urN linux-2.4.21-bk3/drivers/net/wan/sdla_chdlc.c linux-2.4.21-bk4/drivers/net/wan/sdla_chdlc.c
--- linux-2.4.21-bk3/drivers/net/wan/sdla_chdlc.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.21-bk4/drivers/net/wan/sdla_chdlc.c	2003-07-08 02:59:45.000000000 -0700
@@ -591,8 +591,7 @@
 	
 
 		if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){
-			printk (KERN_INFO "%s: 
-				Failed to set interrupt triggers!\n",
+			printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
 				card->devname);
 			return -EIO;	
         	}
@@ -1089,13 +1088,11 @@
 	
 	set_bit(0,&chdlc_priv_area->config_chdlc);
 	chdlc_priv_area->config_chdlc_timeout=jiffies;
-	del_timer(&chdlc_priv_area->poll_delay_timer);
 
 	/* Start the CHDLC configuration after 1sec delay.
 	 * This will give the interface initilization time
 	 * to finish its configuration */
-	chdlc_priv_area->poll_delay_timer.expires=jiffies+HZ;
-	add_timer(&chdlc_priv_area->poll_delay_timer);
+	mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ);
 	return err;
 }
 
diff -urN linux-2.4.21-bk3/drivers/net/wan/sdla_fr.c linux-2.4.21-bk4/drivers/net/wan/sdla_fr.c
--- linux-2.4.21-bk3/drivers/net/wan/sdla_fr.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.21-bk4/drivers/net/wan/sdla_fr.c	2003-07-08 02:59:45.000000000 -0700
@@ -4541,9 +4541,7 @@
 {
 	fr_channel_t* chan = dev->priv;
 
-	del_timer(&chan->fr_arp_timer);
-	chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ);
-	add_timer(&chan->fr_arp_timer);
+	mod_timer(&chan->fr_arp_timer, jiffies + (chan->inarp_interval) * HZ);
 	return;
 }
 
diff -urN linux-2.4.21-bk3/drivers/net/wan/sdla_x25.c linux-2.4.21-bk4/drivers/net/wan/sdla_x25.c
--- linux-2.4.21-bk3/drivers/net/wan/sdla_x25.c	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.21-bk4/drivers/net/wan/sdla_x25.c	2003-07-08 02:59:45.000000000 -0700
@@ -1267,9 +1267,7 @@
 			connect(card);
 			S508_S514_unlock(card, &smp_flags);
 
-			del_timer(&card->u.x.x25_timer);
-			card->u.x.x25_timer.expires=jiffies+HZ;
-			add_timer(&card->u.x.x25_timer);
+			mod_timer(&card->u.x.x25_timer, jiffies + HZ);
 		}
 	}
 	/* Device is not up until the we are in connected state */
diff -urN linux-2.4.21-bk3/drivers/net/wan/z85230.c linux-2.4.21-bk4/drivers/net/wan/z85230.c
--- linux-2.4.21-bk3/drivers/net/wan/z85230.c	2001-11-09 14:03:11.000000000 -0800
+++ linux-2.4.21-bk4/drivers/net/wan/z85230.c	2003-07-08 02:59:45.000000000 -0700
@@ -1451,7 +1451,6 @@
 	c->tx_next_skb=NULL;
 	c->tx_ptr=c->tx_next_ptr;
 	
-	netif_wake_queue(c->netdevice);
 	if(c->tx_skb==NULL)
 	{
 		/* Idle on */
@@ -1513,7 +1512,6 @@
 			/* ABUNDER off */
 			write_zsreg(c, R10, c->regs[10]);
 			write_zsctrl(c, RES_Tx_CRC);
-//???			write_zsctrl(c, RES_EOM_L);
 	
 			while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))
 			{		
@@ -1523,6 +1521,10 @@
 
 		}
 	}
+	/*
+	 *	Since we emptied tx_skb we can ask for more
+	 */
+	netif_wake_queue(c->netdevice);
 }
 
 /**
@@ -1540,7 +1542,6 @@
 {
 	struct sk_buff *skb;
 
-	netif_wake_queue(c->netdevice);
 	/* Actually this can happen.*/
 	if(c->tx_skb==NULL)
 		return;
@@ -1795,7 +1796,6 @@
 	z8530_tx_begin(c);
 	spin_unlock_irqrestore(c->lock, flags);
 	
-	netif_wake_queue(c->netdevice);
 	return 0;
 }
 
diff -urN linux-2.4.21-bk3/drivers/s390/Config.in linux-2.4.21-bk4/drivers/s390/Config.in
--- linux-2.4.21-bk3/drivers/s390/Config.in	2003-06-13 07:51:35.000000000 -0700
+++ linux-2.4.21-bk4/drivers/s390/Config.in	2003-07-08 02:59:45.000000000 -0700
@@ -80,6 +80,7 @@
     tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
     bool 'Token Ring driver support' CONFIG_TR
+    dep_tristate 'Cisco 7000 support' CONFIG_C7000 m
     bool 'FDDI driver support' CONFIG_FDDI
     comment 'S/390 network device drivers'
     bool 'Channel Device Configuration' CONFIG_CHANDEV
diff -urN linux-2.4.21-bk3/drivers/s390/net/Makefile linux-2.4.21-bk4/drivers/s390/net/Makefile
--- linux-2.4.21-bk3/drivers/s390/net/Makefile	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.21-bk4/drivers/s390/net/Makefile	2003-07-08 02:59:45.000000000 -0700
@@ -12,6 +12,7 @@
 obj-$(CONFIG_IUCV) += iucv.o fsm.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o
 obj-$(CONFIG_IUCV) += netiucv.o
+obj-$(CONFIG_C7000) += c7000.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.21-bk3/drivers/s390/net/c7000.c linux-2.4.21-bk4/drivers/s390/net/c7000.c
--- linux-2.4.21-bk3/drivers/s390/net/c7000.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/drivers/s390/net/c7000.c	2003-07-08 02:59:45.000000000 -0700
@@ -0,0 +1,3293 @@
+/*
+	Cisco/7000 driver -- Copyright (C) 2000 UTS Global LLC.
+	Author: Bob Scardapane (UTS Global LLC).
+	Version: 3.
+
+	To use this driver, run the LINUX command:
+
+	insmod c7000 base0=0xYYYY lhost0=s1 uhost0=s2 lappl0=s3 uappl0=s4 dbg=x
+
+	base0=0xYYYY defines the base unit address of the interface.
+	lhost0=s1 defines the local host name.
+	uhost0=s2 defines the unit host name.
+	lappl0=s3 defines the local application name.
+	uappl0=s4 defines the unit application name.
+	dbg=x defines the message level.  Higher values will result in
+	additional diagnostic messages.
+
+	Additional interfaces are defined on insmod by using the variable
+	name groups "base1,lhost1,lappl1,uhost1,uappl1", etc... up to three
+	additional groups.
+
+	In addition, the module will automatically detect the unit base
+	addresses by scanning all active irq's for a control unit type
+	of 0x3088 and a model of 0x61 (CLAW mode). The noauto parameter
+	can be used to suppress automatic detection.
+
+	The values of lhostx, lapplx, uhostx and uapplx default to:
+
+	lapplx - TCPIP
+	lhostx - UTS
+	uapplx - TCPIP
+	uhostx - C7011
+
+	Note that the values passed in the insmod command will always
+	override the automatic detection of the unit base addreeses and
+	the default values of lapplx, lhostx, uapplx and uhostx.
+
+	The parameter noauto can be used to disable automatic detection of
+	devices:
+
+	noauto=1 (disable automatic detection)
+	noauto=0 (Enable automatic detectio.  This is the default value.)
+
+	The values in base0 - base3 will be copied to the bases array when
+	the module is loaded. 
+
+	To configure the interface(s), run the LINUX command(s):
+
+	ifconfig ci0 ...
+	ifconfig ci1 ...
+	ifconfig ci2 ...
+	ifconfig ci3 ...
+
+	There is one device structure for each controller in the c7000_devices
+	array.  The base address of each controller is in the bases array.
+	These arrays parallel each other.  There is also one c7000_controller
+	structure for each controller.  This structure is pointed to by field
+	priv in the individual device structure. 
+
+	In each c7000_controller, there are embedded c7000_unit structures.
+	There is one c7000_unit structure per device number that makes up
+	a controller (currently 2 units per controller).
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+ 
+/*
+	Global defines
+*/
+
+/*
+	Maximum number of controllers.
+*/
+
+#define	MAX_C7000	4
+
+/*
+	Number of units per controller.
+*/
+
+#define	NUNITS		2
+
+/*
+	Define indexes of read and write units in the cunits array.
+*/
+
+#define	C7000_RD	0
+#define	C7000_WR	1
+
+/*
+	Number of device buffers.
+*/
+
+#define	C7000_MAXBUF	40
+
+/*
+	Transmission queue length.
+*/
+
+#define	C7000_TXQUEUE_LEN	100
+/*
+	Size of the IP packet data.
+*/
+
+#define	C7000_DATAL	4096
+
+/*
+	Size of the read header data.
+*/
+
+#define	C7000_READHDRL	4
+
+/*
+	Size of read flag byte.
+*/
+
+#define	C7000_READFFL	1
+
+/*
+	Size of a device buffer.  This is how it is arranged in memory:
+	4096 (IP packet data) + 4 (read header) + 1 (read flag) = 4101.
+*/
+
+#define	C7000_BUFSIZE	C7000_DATAL + C7000_READHDRL + C7000_READFFL
+
+/*
+	Size of sigsmod data.
+*/
+
+#define	C7000_SIGSMODL	1
+
+/*
+	Flag value that indicates a read was completed in the flag
+	field of a c7000_rd_header.
+*/
+
+#define	FLAG_FF		0xff
+/*
+	Size of C7000 sense id data.
+*/
+
+#define SIDL		32
+
+/*
+	Maximum number of read and write retries.
+*/
+
+#define	C7000_MAX_RETRIES	3
+
+/*
+	Define sense byte0 value for a box reset.
+*/
+
+#define	C7000_BOX_RESET		0x41
+
+/*
+	CCW commands.
+*/
+
+#define	C7000_WRITE_CCW		0x01	/* normal write */
+#define	C7000_READ_CCW		0x02	/* normal read */
+#define	C7000_NOOP_CCW		0x03	/* no operation */
+#define	C7000_SIGSMOD_CCW	0x05	/* signal status modifier */
+#define	C7000_TIC_CCW		0x08	/* transfer in channel */
+#define	C7000_READHDR_CCW	0x12	/* read header  */
+#define	C7000_READFF_CCW	0x22	/* read FF flag */
+#define	C7000_SID_CCW		0xe4	/* sense identification */
+
+/*
+	Control commands.
+*/
+
+#define	C7000_SYS_VALIDATE		1
+#define C7000_SYS_VALIDATE_RESP		2
+#define	C7000_CONN_REQ			33
+#define C7000_CONN_RESP			34
+#define C7000_CONN_CONFRM		35
+#define C7000_DISCONN			36
+#define C7000_BOXERROR			65
+
+/*
+	State machine values.
+*/
+
+#define	C7000_INIT	1
+#define C7000_HALT	2
+#define C7000_SID	3
+#define C7000_SYSVAL	4
+#define	C7000_CONNECT	5
+#define C7000_READY	6
+#define C7000_READ	7
+#define C7000_WRITE	8
+#define	C7000_DISC	9
+#define C7000_STOP	10
+#define	C7000_STOPPED	11
+#define C7000_ERROR	12
+
+/*
+	The lower subchannel is used for read operations and the one that is
+	one higher is used for write operations.
+
+	Both subchannels are initially in state C7000_INIT.  A transition to
+	state C7000_HALT occurs when halt_IO is issued on each.  When the
+	halts completes a transition to state C7000_SID occurs and a channel
+	program is issued to do a sense identification on both subchannels.
+
+	When the sense identification completes, the state C7000_SYSVAL is
+	entered on the read subchannel.  A read channel program is issued.
+
+	When the sense identification completes, the write subchannel enters
+	state C7000_SYSVAL and a system validation request is written.  The
+	read subchannel is also put into this state.
+	
+	When both the system validation response is read and an inbound system
+	validation request is read, the inbound system validation request is
+	responded to and both subchannels enter the C7000_CONNECT state.
+
+	A read channel program is posted to look for the inbound connect
+	request.  When that is received a connection confirmation is written.
+	The state of both subchannels is then changed to C7000_READY.  A
+	read channel program is then posted and the state is changed to
+	C7000_READ.  When a read completes, the packet is sent to the higher
+	layers and the read channel program is restarted.
+
+	When there is a packet to be written, state C7000_WRITE is entered
+	and a channel program is issued to write the data.  The subchannel
+	is in state C7000_READY when there is nothing to be written.
+
+	When the stop method is executed, a disconnect message is sent and
+	the state is changed to C7000_DISC in both subchannels.  A halt_IO
+	will be issued to both subchannels and state C7000_STOP will be entered.
+	When the halt IO completes, state C7000_STOPPED will be set. 
+
+	State C7000_ERROR is set when an error occurs in the interrupt
+	routine.  Recycle the interface (ifconfig down / ifconfig up)
+	to reset this state.
+*/
+
+/*
+	Results from c7000_check_csw.
+*/
+
+enum	c7000_rupt {
+	C7000_NORMAL,
+	C7000_CHANERR,
+	C7000_UCK,
+	C7000_UCK_RESET,
+	C7000_UE,
+	C7000_ATTN,
+	C7000_BUSY,
+	C7000_OTHER
+};
+
+/*
+	Bits set in device structure tbusy field.
+*/
+
+#define	TB_TX		0	/* sk buffer handling in progress */
+#define	TB_STOP		1	/* network device stop in progress */
+#define	TB_RETRY	2	/* retry in progress */
+#define	TB_NOBUFFER	3	/* no buffer on free queue */
+
+/*
+	Bit in c7000_unit.flag_a that indicates the bh routine is busy.
+*/
+
+#define	C7000_BH_ACTIVE	0
+
+#define CPrintk(level, args...) \
+	if (level <= dbg) \
+		printk(args)
+
+/*
+	Maximum length of a system validation string.
+*/
+
+#define	NAMLEN	8
+
+#define	Err_Conn_Confirm	1
+#define	Err_Names_not_Matched	166
+#define	Err_C7000_NOT_READY	167
+#define	Err_Duplicate		170
+#define	Err_Closing		171
+#define	Err_No_Such_App		172
+#define	Err_Host_Not_Ready	173
+#define	Err_CLOSING		174
+#define	Err_Dup_Link		175
+#define	Err_Wrong_Version	179
+#define	Err_Wrong_Frame_Size	180
+
+/*
+	Define a macro to extract the logical link identifier from
+	the c7000 read header command field.
+*/
+
+#define	C7000_LINKID(cmd)	((unsigned char)cmd >> 3)
+
+/*
+	Define the control unit type for a Cisco 7000.
+*/
+
+#define	C7000_CU_TYPE		0x3088
+
+/*
+	Define the control unit model for a Cisco 7000.
+*/
+
+#define	C7000_CU_MODEL		0x61
+
+/*
+	Define the default system validate parameters (lapplx,
+	lhostx, uapplx, uhostx).
+*/
+
+#define	C7000_DFLT_LAPPL	"TCPIP"
+#define	C7000_DFLT_LHOST	"UTS"
+#define	C7000_DFLT_UAPPL	"TCPIP"
+#define	C7000_DFLT_UHOST	"C7011"
+
+/*
+	Global variables.
+*/
+
+/*
+	Base device addresses of the controllers.
+*/
+
+static int	base0 = -1;
+static int	base1 = -1;
+static int	base2 = -1;
+static int	base3 = -1;
+
+static int	bases[MAX_C7000];
+
+/*
+	Local application names.
+*/
+
+static char	*lappl0;
+static char	*lappl1;
+static char	*lappl2;
+static char	*lappl3;
+
+/*
+	Local host names.
+*/
+
+static char	*lhost0;
+static char	*lhost1;
+static char	*lhost2;
+static char	*lhost3;
+
+/*
+	Unit application names.
+*/
+
+static char	*uappl0;
+static char	*uappl1;
+static char	*uappl2;
+static char	*uappl3;
+
+/*
+	Unit hosts names.
+*/
+
+static char	*uhost0;
+static char	*uhost1;
+static char	*uhost2;
+static char	*uhost3;
+
+/*
+	Debugging level (higher numbers emit lower priority messages).
+*/
+
+static unsigned int	dbg = 0;
+
+/*
+	Parameter that controls auto detection.
+*/
+
+static int	noauto = 0;
+
+/*
+	Interface names.
+*/
+
+static char	ifnames[MAX_C7000][8] = {"ci0", "ci1", "ci2", "ci3"};
+
+/*
+	One device structure per controller.
+*/
+
+/* RBH Try out the new code for 2.4.0 */
+#define NEWSTUFF
+
+#ifdef NEWSTUFF
+#define STRUCT_NET_DEVICE struct net_device
+#else
+#define STRUCT_NET_DEVICE struct device
+#endif
+
+STRUCT_NET_DEVICE	c7000_devices[MAX_C7000];
+
+/*
+	Scratch variable filled in with controller name.
+*/
+
+static char	*controller;
+
+/*
+	Identify parameters that can be passed on the LINUX insmod command.
+*/
+
+MODULE_AUTHOR("Robert Scardapane (UTS Global)");
+MODULE_DESCRIPTION("Network module for Cisco 7000 box.");
+
+MODULE_PARM(base0, "1i");
+MODULE_PARM_DESC(base0, "Base unit address for 1st C7000 box.");
+MODULE_PARM(base1, "1i");
+MODULE_PARM_DESC(base1, "Base unit address for 2nd C7000 box.");
+MODULE_PARM(base2, "1i");
+MODULE_PARM_DESC(base2, "Base unit address for 3rd C7000 box.");
+MODULE_PARM(base3, "1i");
+MODULE_PARM_DESC(base3, "Base unit address for 4th C7000 box.");
+
+MODULE_PARM(lappl0, "s");
+MODULE_PARM_DESC(lappl0, "Application name for 1st C7000 box.");
+MODULE_PARM(lappl1, "s");
+MODULE_PARM_DESC(lappl1, "Application name for 2nd C7000 box.");
+MODULE_PARM(lappl2, "s");
+MODULE_PARM_DESC(lappl2, "Application name for 3rd C7000 box.");
+MODULE_PARM(lappl3, "s");
+MODULE_PARM_DESC(lappl3, "Application name for 4th C7000 box.");
+
+MODULE_PARM(lhost0, "s");
+MODULE_PARM_DESC(lhost0, "Host name for 1st C7000 box.");
+MODULE_PARM(lhost1, "s");
+MODULE_PARM_DESC(lhost1, "Host name for 2nd C7000 box.");
+MODULE_PARM(lhost2, "s");
+MODULE_PARM_DESC(lhost2, "Host name for 3rd C7000 box.");
+MODULE_PARM(lhost3, "s");
+MODULE_PARM_DESC(lhost3, "Host name for 4th C7000 box.");
+
+MODULE_PARM(uhost0, "s");
+MODULE_PARM_DESC(uhost0, "Unit name for 1st C7000 box.");
+MODULE_PARM(uhost1, "s");
+MODULE_PARM_DESC(uhost1, "Unit name for 2nd C7000 box.");
+MODULE_PARM(uhost2, "s");
+MODULE_PARM_DESC(uhost2, "Unit name for 3rd C7000 box.");
+MODULE_PARM(uhost3, "s");
+MODULE_PARM_DESC(uhost3, "Unit name for 4th C7000 box.");
+
+MODULE_PARM(uappl0, "s");
+MODULE_PARM_DESC(uappl0, "Unit application name for 1st C7000 box.");
+MODULE_PARM(uappl1, "s");
+MODULE_PARM_DESC(uappl1, "Unit application name for 2nd C7000 box.");
+MODULE_PARM(uappl2, "s");
+MODULE_PARM_DESC(uappl2, "Unit application name for 3rd C7000 box.");
+MODULE_PARM(uappl3, "s");
+MODULE_PARM_DESC(uappl3, "Unit application name for 4th C7000 box.");
+
+MODULE_PARM(dbg, "1i");
+MODULE_PARM_DESC(dbg, "Message level for debugging.");
+
+MODULE_PARM(noauto, "1i");
+MODULE_PARM_DESC(noauto, "Control automatic detection of unit base addresses.");
+
+/*
+	Structure used to manage unit buffers.
+*/
+
+struct	c7000_buffer {
+	ccw1_t			ccws[7];	/* channel program */
+	struct	c7000_buffer	*next;		/* list pointer */
+	char			*data;		/* pointer to actual data */
+	int			len;		/* length of the data */
+};
+
+/*
+	C7000 Control Block.
+ */
+
+struct	c7000_control_blk {
+	unsigned char	cmd;
+	unsigned char	ver;
+	unsigned char	link_id;
+	unsigned char	correlator;
+	unsigned char	ret_code;
+	unsigned char	resvd1[3];
+	unsigned char	unitname[NAMLEN];
+	unsigned char	hostname[NAMLEN];
+	unsigned short	rdsize;		/* read frame size   */
+	unsigned short	wrtsize;	/* write frame size  */
+	unsigned char	resvd2[4];
+};
+
+/*
+	Per unit structure contained within the c7000_controller structure.
+*/
+
+struct	c7000_unit {
+	ccw1_t				ccws[5];	/* control ccws */
+	int				devno;		/* device number */
+	int				irq;		/* subchannel number */
+	int				IO_active;	/* IO activity flag */
+	int				state;		/* fsm state */
+	int				retries;	/* retry counter */
+	unsigned long			flag_a;		/* bh activity flag */
+	devstat_t			devstat;	/* device status */
+#ifdef NEWSTUFF
+	wait_queue_head_t		wait;		/* sleep q head */
+#else
+	struct wait_queue		*wait;		/* sleep q pointer */
+#endif
+	struct c7000_controller		*cntlp;		/* controller pointer */
+	struct c7000_buffer		*free;		/* free buffer anchor */
+	struct c7000_buffer		*proc_head;	/* proc head */
+	struct c7000_buffer		*proc_tail;	/* proc tail */
+	struct c7000_buffer		*bh_head;	/* bh head */
+	struct c7000_buffer		*bh_tail;	/* bh tail */
+	struct tq_struct		tq;		/* bh scheduling */
+	char				senseid[SIDL];	/* sense id data */
+	struct c7000_control_blk	control_blk;	/* control block */
+	unsigned char			sigsmod;	/* sigsmod flag */
+	unsigned char			readhdr[4];	/* read header */
+	unsigned char			readff;		/* readff flag */
+};
+
+/*
+	Private structure pointed to by dev->priv.
+*/
+
+struct c7000_controller {
+	struct	net_device_stats	stats;		/* statistics */
+	STRUCT_NET_DEVICE		*dev;		/* -> device struct */
+	unsigned int			base_addr;	/* base address */
+	char				lappl[NAMLEN];	/* local appl */
+	char				lhost[NAMLEN];	/* local host */
+	char				uappl[NAMLEN];	/* unit appl */
+	char				uhost[NAMLEN];	/* unit host */
+	unsigned char			version;	/* version = 2 */
+	unsigned char			linkid;		/* link id */
+	struct	c7000_unit		cunits[NUNITS];	/* embedded units */
+#ifdef NEWSTUFF
+	int				tbusy;
+#endif
+};
+
+/*
+	This is the structure returned by the C7000_READHDR_CCW.
+*/
+
+struct	c7000_rd_header {
+	unsigned short	len;	/* packet length */
+	unsigned char	cmd;	/* command code */
+	unsigned char	flag;	/* flag */
+};
+
+/*
+	Set the device structure transmission busy flag.
+*/
+
+#ifdef NEWSTUFF
+#define c7000_set_busy(dev) netif_stop_queue(dev)
+#else
+static __inline__ void
+c7000_set_busy(STRUCT_NET_DEVICE *dev)
+{
+	dev->tbusy = 1;
+	eieio();
+	return;
+}
+#endif
+	
+/*
+	Clear the device structure transmission busy flag.
+*/
+
+#ifdef NEWSTUFF
+#define c7000_clear_busy(dev) netif_wake_queue(dev)
+#else
+static __inline__ void
+c7000_clear_busy(STRUCT_NET_DEVICE *dev)
+{
+	dev->tbusy = 0;
+	eieio();
+	return;
+}
+#endif
+
+/*
+	Extract the device structure transmission busy flag.
+*/
+
+#ifdef NEWSTUFF
+#define c7000_check_busy(dev) netif_queue_stopped(dev)
+#else
+static __inline__ int
+c7000_check_busy(STRUCT_NET_DEVICE *dev)
+{
+	eieio();
+	return(dev->tbusy);
+}
+#endif
+
+/*
+	Set a bit in the device structure transmission busy flag.
+*/
+
+static __inline__ void
+c7000_setbit_busy(int nr, STRUCT_NET_DEVICE *dev)
+{
+#ifdef NEWSTUFF
+	netif_stop_queue(dev);
+	test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
+#else
+	set_bit(nr, (void *)&dev->tbusy);
+#endif
+	return;
+}
+
+/*
+	Clear a bit in the device structure transmission busy flag.
+*/
+
+static __inline__ void
+c7000_clearbit_busy(int nr, STRUCT_NET_DEVICE *dev)
+{
+#ifdef NEWSTUFF
+	clear_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
+	netif_wake_queue(dev);
+#else
+	clear_bit(nr, (void *)&dev->tbusy);
+#endif
+	return;
+}
+
+/*
+	Test and set a bit in the device structure transmission busy flag.
+*/
+
+static __inline__ int
+c7000_ts_busy(int nr, STRUCT_NET_DEVICE *dev)
+{
+#ifdef NEWSTUFF
+	netif_stop_queue(dev);
+	return test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
+#else
+	return(test_and_set_bit(nr, (void *)&dev->tbusy));
+#endif
+}
+
+/*
+	Set the C7000 controller in the error state.
+*/
+
+static void
+c7000_error(struct c7000_controller *ccp)
+{
+	int			i;
+	struct	c7000_unit	*cup;
+	STRUCT_NET_DEVICE	*dev = ccp->dev;
+
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+		cup->state = C7000_ERROR;
+	}
+
+	if (dev != NULL)
+#ifdef NEWSTUFF
+		/* RBH XXX Should we be doing this? */
+		dev->state &= ~__LINK_STATE_START;
+#else
+		dev->flags &= ~IFF_RUNNING;
+#endif
+
+	CPrintk(0, "c7000: c7000_error: base unit 0x%x is down\n", ccp->base_addr);
+	return;
+}
+
+/*
+	Based on the SENSE ID information, fill in the
+	controller name.  Note that this is the SENSE ID
+	information saved by LINUX/390 at boot time.
+*/
+
+static int
+c7000_check_type(senseid_t *id)
+{
+
+	switch (id->cu_type) {
+
+		case C7000_CU_TYPE:
+
+			if (id->cu_model == C7000_CU_MODEL) {
+				controller = "C7000  ";
+ 				return(0);
+			}
+
+			break;
+
+                default:
+			break;
+	}
+
+	return(-1);
+}
+
+/*
+	Check the device information for the controller.
+*/
+
+static int
+c7000_check_devices(int devno)
+{
+	int		i;
+	s390_dev_info_t	temp;
+
+	/*
+		Get the SENSE ID information for each device.
+	*/
+
+	for (i = devno; i < (devno + NUNITS); i++) {
+
+		if (get_dev_info_by_devno(devno, &temp) != 0)
+			return(-1);
+		
+		if (c7000_check_type(&temp.sid_data) == -1)
+			return(-1);
+	}
+
+	CPrintk(1, "c7000: c7000_check_devices: device type is %s\n", controller);
+	return(0);
+}
+
+/*
+	Issue a halt I/O to device pointed to by cup.
+*/
+
+static int
+c7000_haltio(struct c7000_unit *cup)
+{
+	__u32			parm;
+	__u8			flags = 0x00;
+	__u32			saveflags;
+	DECLARE_WAITQUEUE(wait, current);
+	int			rc;
+
+	s390irq_spin_lock_irqsave(cup->irq, saveflags);
+	parm = (unsigned long)cup;
+
+	if ((rc = halt_IO(cup->irq, parm, flags)) != 0) {
+		s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+		return(rc);
+	}
+
+	/*
+		Wait for the halt I/O to finish.
+	*/
+
+	add_wait_queue(&cup->wait, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+	schedule();
+	remove_wait_queue(&cup->wait, &wait);
+	return(0);
+}
+
+/*
+	Issue a start I/O to device pointed to by cup.
+*/
+
+static int
+c7000_doio(struct c7000_unit *cup)
+{
+	__u32			parm;
+	__u8			flags = 0x00;
+	__u32			saveflags;
+	DECLARE_WAITQUEUE(wait, current);
+	int			rc;
+
+	/*
+		Do no further I/O while the device is in the ERROR, STOP
+		or STOPPED state.
+	*/
+
+	if (cup->state == C7000_ERROR || cup->state == C7000_STOP || cup->state == C7000_STOPPED)
+		return(-1);
+
+	s390irq_spin_lock_irqsave(cup->irq, saveflags);
+	parm = (unsigned long)cup;
+
+	if ((rc = do_IO(cup->irq, &cup->ccws[0], parm, 0xff, flags)) != 0) {
+		s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+		return(rc);
+	}
+	
+	/*
+		Wait for the I/O to complete.
+	*/
+
+	add_wait_queue(&cup->wait, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+	schedule();
+	remove_wait_queue(&cup->wait, &wait);
+
+	/*
+		Interrupt handling may have marked the device in ERROR.
+	*/
+
+	if (cup->state == C7000_ERROR)
+		return(-1);
+
+	return(0);
+}
+
+/*
+	Build a channel program to do a sense id channel program.
+*/
+
+static void
+c7000_bld_senseid_chpgm(struct c7000_unit *cup)
+{
+	ccw1_t	*ccwp;
+
+	ccwp = &cup->ccws[0];
+	ccwp->cmd_code = C7000_SID_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->senseid);
+	ccwp->count = SIDL;
+	ccwp++;
+	ccwp->cmd_code = C7000_NOOP_CCW;
+	ccwp->flags = CCW_FLAG_SLI;
+	ccwp->cda = (__u32)NULL;
+	ccwp->count = 1;
+	return;
+}
+
+/*
+	Build a channel program to write a control message.
+*/
+
+static void
+c7000_bld_wrtctl_chpgm(struct c7000_unit *cup)
+{
+	ccw1_t	*ccwp;
+
+	ccwp = &cup->ccws[0];
+	ccwp->cmd_code = C7000_WRITE_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->control_blk);
+	ccwp->count = sizeof(struct c7000_control_blk);
+	ccwp++;
+	ccwp->cmd_code = C7000_READFF_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->readff);
+	ccwp->count = C7000_READFFL;
+	ccwp++;
+	ccwp->cmd_code = C7000_TIC_CCW;
+	ccwp->flags = 0;
+	ccwp->cda = (__u32)virt_to_phys(ccwp + 1);
+	ccwp->count = 0;
+	ccwp++;
+	ccwp->cmd_code = C7000_NOOP_CCW;
+	ccwp->flags = CCW_FLAG_SLI;
+	ccwp->cda = (__u32)NULL;
+	ccwp->count = 1;
+	return;
+}
+
+/*
+	Build a write channel program to write the indicated buffer.
+*/
+
+static void
+c7000_bld_wrt_chpgm(struct c7000_unit *cup, struct c7000_buffer *buf)
+{
+	ccw1_t				*ccwp;
+	struct	c7000_controller	*ccp = cup->cntlp;
+
+	ccwp = &buf->ccws[0];
+	ccwp->cmd_code = C7000_WRITE_CCW | (ccp->linkid << 3);
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(buf->data);
+	ccwp->count = buf->len;
+	ccwp++;
+	ccwp->cmd_code = C7000_READFF_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(buf->data + C7000_DATAL + C7000_READHDRL);
+	ccwp->count = C7000_READFFL;
+	ccwp++;
+	ccwp->cmd_code = C7000_TIC_CCW;
+	ccwp->flags = 0;
+	ccwp->cda = (__u32)virt_to_phys(ccwp + 1);
+	ccwp->count = 0;
+	ccwp++;
+	ccwp->cmd_code = C7000_NOOP_CCW;
+	ccwp->flags = (CCW_FLAG_SLI);
+	ccwp->cda = (__u32)NULL;
+	ccwp->count = 1;
+	return;
+}
+
+/*
+	Build a channel program to read a control message.
+*/
+
+static void
+c7000_bld_readctl_chpgm(struct c7000_unit *cup)
+{
+	ccw1_t	*ccwp;
+
+	ccwp = &cup->ccws[0];
+	ccwp->cmd_code = C7000_READ_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->control_blk);
+	ccwp->count = sizeof(struct c7000_control_blk);
+	ccwp++;
+	ccwp->cmd_code = C7000_READHDR_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->readhdr);
+	ccwp->count = C7000_READHDRL;
+	ccwp++;
+	ccwp->cmd_code = C7000_SIGSMOD_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->sigsmod);
+	ccwp->count = C7000_SIGSMODL;
+	ccwp++;
+	ccwp->cmd_code = C7000_TIC_CCW;
+	ccwp->flags = 0;
+	ccwp->cda = (__u32)virt_to_phys(ccwp + 1);
+	ccwp->count = 0;
+	ccwp++;
+	ccwp->cmd_code = C7000_NOOP_CCW;
+	ccwp->flags = (CCW_FLAG_SLI);
+	ccwp->cda = (__u32)NULL;
+	ccwp->count = 1;
+	return;
+}
+
+/*
+	Build a channel program to read the indicated buffer.
+*/
+
+static void
+c7000_bld_read_chpgm(struct c7000_unit *cup, struct c7000_buffer *buf)
+{
+	ccw1_t	*ccwp;
+
+	ccwp = &buf->ccws[0];
+	ccwp->cmd_code = C7000_READ_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(buf->data);
+	ccwp->count = C7000_DATAL;
+	ccwp++;
+	ccwp->cmd_code = C7000_READHDR_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(buf->data + C7000_DATAL);
+	ccwp->count = C7000_READHDRL;
+	ccwp++;
+	ccwp->cmd_code = C7000_SIGSMOD_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC);
+	ccwp->cda = (__u32)virt_to_phys(&cup->sigsmod);
+	ccwp->count = C7000_SIGSMODL;
+	ccwp++;
+	ccwp->cmd_code = C7000_TIC_CCW;
+	ccwp->flags = 0;
+	ccwp->cda = (__u32)virt_to_phys(ccwp + 3);
+	ccwp->count = 0;
+	ccwp++;
+	ccwp->cmd_code = C7000_READFF_CCW;
+	ccwp->flags = (CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI);
+	ccwp->cda = (__u32)virt_to_phys(&cup->readff);
+	ccwp->count = C7000_READFFL;
+	ccwp++;
+	ccwp->cmd_code = C7000_TIC_CCW;
+	ccwp->flags = 0;
+	ccwp->cda = (__u32)virt_to_phys(ccwp + 1);
+	ccwp->count = 0;
+	ccwp++;
+	ccwp->cmd_code = C7000_NOOP_CCW;
+	ccwp->flags = (CCW_FLAG_SLI);
+	ccwp->cda = (__u32)NULL;
+	ccwp->count = 1;
+	return;
+}
+
+/*
+	Allocate buffer structure headers and buffers for all units
+	A return value of 0 means that all allocations worked.  A -1
+	means that an allocation failed.  It is expected that the caller
+	will call c7000_free_buffers when -1 is returned.
+*/
+
+static int
+c7000_alloc_buffers(STRUCT_NET_DEVICE *dev)
+{
+	int				i;
+	int				j;
+	char				*data;
+	struct	c7000_buffer		*bufptr;
+	struct	c7000_controller	*ccp = (struct c7000_controller *) dev->priv;
+	struct	c7000_unit		*cup;
+	
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+		cup->free = NULL;
+
+		for (j = 0; j < C7000_MAXBUF; j++) {
+			bufptr = kmalloc(sizeof(struct c7000_buffer), GFP_KERNEL);
+			data = kmalloc(C7000_BUFSIZE, GFP_KERNEL);
+
+			if (bufptr == NULL)
+			{
+				if(data)
+					kfree(data);
+				return(-1);
+			}
+
+			/*
+				Place filled in buffer header on free anchor.
+			*/
+
+			bufptr->next = cup->free;
+			bufptr->data = data;
+			bufptr->len = 0;
+			cup->free = bufptr;
+
+			if (data == NULL)
+				return(-1);
+
+			memset(data, '\0', C7000_BUFSIZE);
+		}
+
+	}
+
+	CPrintk(1, "c7000: c7000_alloc_buffers: allocated buffers for base unit 0x%lx\n", dev->base_addr);
+	return(0);
+}
+
+/*
+	Free buffers on a chain.
+*/
+
+static void
+c7000_free_chain(struct c7000_buffer *buf)
+{
+	char			*data;
+	struct	c7000_buffer	*bufptr = buf;
+	struct	c7000_buffer	*tmp;
+
+	while (bufptr != NULL) {
+		data = bufptr->data;
+
+		if (data != NULL)
+			kfree(data);
+
+		tmp = bufptr;
+		bufptr = bufptr->next;
+		kfree(tmp);
+	}
+
+	return;
+}
+
+/*
+	Free buffers on all possible chains for all units.
+*/
+
+static void
+c7000_free_buffers(STRUCT_NET_DEVICE *dev)
+{
+	int				i;
+	struct	c7000_controller	*ccp = (struct c7000_controller *) dev->priv;
+	struct	c7000_unit	*cup;
+	
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+		c7000_free_chain(cup->free);
+		cup->free = NULL;
+		c7000_free_chain(cup->proc_head);
+		cup->proc_head = cup->proc_tail = NULL;
+		c7000_free_chain(cup->bh_head);
+		cup->bh_head = cup->bh_tail = NULL;
+	}
+
+	CPrintk(1, "c7000: c7000_free_buffers: freed buffers for base unit 0x%lx\n", dev->base_addr);
+	return;
+}
+
+/*
+	Obtain a free buffer.  Return a pointer to the c7000_buffer
+	structure OR NULL.
+*/
+
+struct c7000_buffer *
+c7000_get_buffer(struct c7000_unit *cup) 
+{
+	struct	c7000_buffer	*buf;
+
+	buf = cup->free;
+
+	if (buf == NULL)
+		return(NULL);
+
+	cup->free = buf->next;
+	buf->next = NULL;
+	return(buf);
+}
+
+/*
+	Release a buffer to the free list.
+*/
+
+void
+c7000_release_buffer(struct c7000_unit *cup, struct c7000_buffer *buf)
+{
+	struct	c7000_buffer	*tmp;
+
+	tmp = cup->free;
+	cup->free = buf;
+	buf->next = tmp;
+	return;
+}
+
+/*
+	Queue a buffer on the end of the processing (proc) chain.
+*/
+
+void
+c7000_queue_buffer(struct c7000_unit *cup, struct c7000_buffer *buf)
+{
+	buf->next = NULL;
+
+	if (cup->proc_head == NULL) {
+		cup->proc_head = cup->proc_tail = buf;
+		return;
+	}
+
+	cup->proc_tail->next = buf;
+	cup->proc_tail = buf;
+	return;
+}
+
+/*
+	Dequeue a buffer from the start of the processing (proc) chain.
+*/
+
+struct c7000_buffer *
+c7000_dequeue_buffer(struct c7000_unit *cup)
+{
+	struct	c7000_buffer	*buf = cup->proc_head;
+
+	if (buf == NULL)
+		return(NULL);
+
+	cup->proc_head = buf->next;
+
+	if (cup->proc_head == NULL)
+		cup->proc_tail = NULL;
+
+	buf->next = NULL;
+	return(buf);
+}
+
+/*
+	Queue a buffer on the end of the bh routine chain.
+*/
+
+void
+c7000_queue_bh_buffer(struct c7000_unit *cup, struct c7000_buffer *buf)
+{
+	buf->next = NULL;
+
+	if (cup->bh_head == NULL) {
+		cup->bh_head = cup->bh_tail = buf;
+		return;
+	}
+
+	cup->bh_tail->next = buf;
+	cup->bh_tail = buf;
+	return;
+}
+
+/*
+	Dequeue a buffer from the start of the bh routine chain.
+*/
+
+struct c7000_buffer *
+c7000_dequeue_bh_buffer(struct c7000_unit *cup)
+{
+	struct	c7000_buffer	*buf = cup->bh_head;
+
+	if (buf == NULL)
+		return(NULL);
+
+	cup->bh_head = buf->next;
+
+	if (cup->bh_head == NULL)
+		cup->bh_tail = NULL;
+
+	buf->next = NULL;
+	return(buf);
+}
+
+/*
+	Build up a list of buffers to read.  Each buffer is described
+	by one c7000_buffer structure.  The c7000_buffer structure
+	contains a channel segment that will read that one buffer.
+	The channel program segments are chained together via TIC
+	CCWS.
+*/
+
+static int
+c7000_bld_read_chain(struct c7000_unit *cup)
+{
+	struct	c7000_buffer	*buf, *pbuf = NULL;
+	struct	c7000_rd_header	*head;
+	int			num = 0;
+
+	while (cup->free != NULL) {
+
+		/*
+			Obtain a buffer for a read channel segment.
+		*/
+
+		if ((buf = c7000_get_buffer(cup)) == NULL) {
+			CPrintk(0, "c7000: c7000_bld_read_chain: can not obtain a read buffer for unit 0x%x\n", cup->devno);
+			return(-ENOMEM);
+		}
+
+		num++;
+		buf->len = 0;
+
+		/*
+			Clear out the read header flag.
+		*/
+
+		head = (struct c7000_rd_header *)(buf->data + C7000_DATAL);
+		head->flag = 0x00;
+		c7000_queue_buffer(cup, buf);
+
+		/*
+			Build the read channel program segment.
+		*/
+
+		c7000_bld_read_chpgm(cup, buf);
+
+		/*
+			Chain the prior (if any) channel program segment to
+			this one.
+		*/
+
+		if (pbuf != NULL)
+			pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]);
+
+		pbuf = buf;
+	}
+
+	CPrintk(1, "c7000: c7000_bld_read_chain: chained %d buffers for unit 0x%x\n", num, cup->devno);
+	return(0);
+}
+
+/*
+	Build up a list of buffers to write.  Each buffer is described
+	by one c7000_buffer structure.  The c7000_buffer structure
+	contains a channel segment that will write that one buffer.
+	The channel program segments are chained together via TIC
+	CCWS.
+*/
+
+static void
+c7000_bld_wrt_chain(struct c7000_unit *cup)
+{
+	struct	c7000_buffer	*buf = cup->proc_head, *pbuf = NULL;
+	int			num = 0;
+
+	while (buf != NULL) {
+		c7000_bld_wrt_chpgm(cup, buf);
+
+		/*
+			Chain the channel program segments together.
+		*/
+
+		if (pbuf != NULL)
+			pbuf->ccws[2].cda = (__u32)virt_to_phys(&buf->ccws[0]);
+
+		pbuf = buf;
+		buf = buf->next;
+		num++;
+	}
+
+	CPrintk(1, "c7000: c7000_bld_wrt_chain: chained %d buffers for unit 0x%x\n", num, cup->devno);
+	return;
+}
+
+/*
+	Interrupt handler bottom half (bh) routine.
+	Process all of the buffers on the c7000_unit bh chain.
+	The bh chain is populated by the interrupt routine when
+	a READ channel program completes on a buffer.
+*/
+
+static void
+c7000_irq_bh(struct c7000_unit *cup)
+{
+	struct	c7000_buffer		*buf, *pbuf;
+	struct	c7000_rd_header		*head;	
+	struct	sk_buff			*skb;
+	struct	c7000_controller	*ccp;
+	STRUCT_NET_DEVICE		*dev;
+	int				rc;
+	__u16				data_length;
+	__u32				parm;
+	__u8				flags = 0x00;
+	__u32				saveflags;
+
+	ccp = cup->cntlp;
+	dev = ccp->dev;
+
+	s390irq_spin_lock_irqsave(cup->irq, saveflags);
+
+	/*
+		Process all buffers sent to bh by the interrupt routine.
+	*/
+
+	while (cup->bh_head != NULL) {
+		buf = c7000_dequeue_bh_buffer(cup);
+
+		/*
+			Deference the data as a c7000 header.
+		*/
+
+		head = (struct c7000_rd_header *)(buf->data + C7000_DATAL);
+
+		/*
+			If it is a control message, release the buffer and 
+			continue the loop.
+		*/
+
+		if (C7000_LINKID(head->cmd) == 0) {
+			CPrintk(0, "c7000: c7000_irq_bh: unexpected control command %d on unit 0x%x\n", head->cmd, cup->devno);
+			c7000_release_buffer(cup, buf);
+			continue;
+		}
+			
+		/*
+			Allocate a socket buffer.
+		*/
+
+		data_length = head->len;
+		skb = dev_alloc_skb(data_length);
+
+		/*
+			Copy the data to the skb.
+			Send it to the upper layers.
+		*/
+
+		if (skb != NULL) {
+			memcpy(skb_put(skb, data_length), buf->data, data_length);
+			skb->dev = dev;
+			skb->protocol = htons(ETH_P_IP);
+			skb->pkt_type = PACKET_HOST;
+			skb->mac.raw = skb->data;
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			netif_rx(skb);
+			ccp->stats.rx_packets++;
+		} else {
+			CPrintk(0, "c7000: c7000_irq_bh: can not allocate a skb for unit 0x%x\n", cup->devno);
+			ccp->stats.rx_dropped++;
+		}
+
+		/*
+			Rechain the buffer on the processing list.
+		*/
+
+		head->flag = 0x00;
+		buf->len = 0;
+		pbuf = cup->proc_tail;
+		c7000_queue_buffer(cup, buf);
+
+		/*
+			Rechain the buffer on the running channel program.
+		*/
+
+		if (pbuf != NULL)
+			pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]);
+
+	}
+
+	/*
+		Restart the READ channel program if IO_active is 0.
+	*/
+
+	if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) {
+
+		if ((rc = c7000_bld_read_chain(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_irq_bh: can not build read chain for unit 0x%x, return code %d\n", cup->devno, rc);
+			c7000_error(cup->cntlp);
+			clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a);
+			s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+			return;
+		}
+
+		parm = (__u32)cup;
+		cup->state = C7000_READ;
+
+		if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
+			CPrintk(0, "c7000: c7000_irq_bh: can not start READ IO to unit 0x%x, return code %d\n", cup->devno, rc);
+			c7000_error(cup->cntlp);
+			clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a);
+			s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+			return;
+		}
+
+		CPrintk(1, "c7000: c7000_irq_bh: started READ IO to unit 0x%x\n", cup->devno);
+	}
+			
+	/*
+		Clear the bh active indication.
+	*/
+
+	clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a);
+	s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+	return;
+}
+
+/*
+	Send a system validate control command to a unit.
+*/
+
+static int
+c7000_send_sysval(struct c7000_unit *cup)
+{
+	int				rc;
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_control_blk	*ctlblkp = &(cup->control_blk);
+
+	CPrintk(1, "c7000: c7000_send_sysval: send sysval for device 0x%x\n", cup->devno);
+
+	/*
+		Build the system validate control message.
+	*/
+
+	memset(ctlblkp, '\0', sizeof(struct c7000_control_blk));
+	ctlblkp->cmd = C7000_SYS_VALIDATE;
+	ctlblkp->correlator = 0;
+	ctlblkp->link_id = ccp->linkid;
+	ctlblkp->ver = ccp->version; 
+	memcpy(ctlblkp->hostname, ccp->lhost, NAMLEN);
+	memcpy(ctlblkp->unitname, ccp->uhost, NAMLEN);
+	ctlblkp->rdsize = C7000_DATAL;
+        ctlblkp->wrtsize = C7000_DATAL;
+
+	/*
+		Build the channel program.
+	*/
+
+	c7000_bld_wrtctl_chpgm(cup);
+
+	/*
+		Do the IO and wait for write to complete.
+	*/
+
+	if ((rc = c7000_doio(cup)) != 0) {
+		CPrintk(0, "c7000: c7000_send_sysval failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+/*
+	Send a system validate response control command to a unit.
+*/
+
+static int
+c7000_send_sysval_resp(struct c7000_unit *cup, unsigned char correlator, int ret_code)
+{
+	int				rc;
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_control_blk	*ctlblkp = &(cup->control_blk);
+
+	CPrintk(1, "c7000: c7000_send_sysval_resp: send sysval response for device 0x%x\n", cup->devno);
+
+	/*
+		Build the system validate response control message.
+	*/
+
+	memset(ctlblkp, '\0', sizeof(struct c7000_control_blk));
+	ctlblkp->cmd = C7000_SYS_VALIDATE_RESP;
+	ctlblkp->correlator = correlator;
+	ctlblkp->ret_code = ret_code;
+	ctlblkp->link_id = ccp->linkid;
+	ctlblkp->ver = ccp->version; 
+	memcpy(ctlblkp->hostname, ccp->lhost, NAMLEN);
+	memcpy(ctlblkp->unitname, ccp->uhost, NAMLEN);
+	ctlblkp->rdsize = C7000_DATAL;
+        ctlblkp->wrtsize = C7000_DATAL;
+
+	/*
+		Build the channel program.
+	*/
+
+	c7000_bld_wrtctl_chpgm(cup);
+
+	/*
+		Do the IO and wait for write to complete.
+	*/
+
+	if ((rc = c7000_doio(cup)) != 0) {
+		CPrintk(0, "c7000: c7000_send_sysval_resp failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+/*
+	Check the information read in a SYS_VALIDATE control message.
+*/
+
+static int
+c7000_checkinfo(struct c7000_unit *cup)
+{
+	struct	c7000_controller	*ccp = cup->cntlp;
+ 	struct	c7000_control_blk	*ctlblkp = &cup->control_blk;
+	int				ret_code = 0;
+
+	if (memcmp(ccp->lhost, ctlblkp->hostname, NAMLEN) ||
+		memcmp(ccp->uhost, ctlblkp->unitname, NAMLEN))
+		ret_code = Err_Names_not_Matched;
+
+	if (ctlblkp->ver != ccp->version)
+		ret_code = Err_Wrong_Version;
+
+        if ((ctlblkp->rdsize < C7000_DATAL) || (ctlblkp->wrtsize < C7000_DATAL))
+		ret_code = Err_Wrong_Frame_Size;
+
+	if (ret_code != 0)
+		CPrintk(0, "c7000: c7000_checkinfo: ret_code %d for device 0x%x\n", ret_code, cup->devno);
+
+	return(ret_code);
+}
+
+/*
+	Keep reading until a sysval response comes in or an error.
+*/
+
+static int
+c7000_get_sysval_resp(struct c7000_unit *cup)
+{
+	struct	c7000_controller	*ccp = cup->cntlp;
+	int				resp = 1;
+	int				req = 1;
+	int				rc;
+	int				ret_code = 0;
+
+	CPrintk(1, "c7000: c7000_get_sysval_resp: get sysval response for unit 0x%x\n", cup->devno);
+
+	/*
+		Wait for the response to C7000_SYS_VALIDATE and for an
+		inbound C7000_SYS_VALIDATE.
+	*/
+
+	while (resp || req) {
+
+		/*
+			Build the read channel program.
+		*/
+
+		c7000_bld_readctl_chpgm(cup);
+
+		if ((rc = c7000_doio(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_get_sysval_resp: failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+			return(-1);
+		}
+
+		/*
+			Process the control message.
+		*/
+
+		switch (cup->control_blk.cmd) {
+
+			/*
+				Check that response is positive and return
+				with success. Otherwise, return with an
+				error.
+			*/
+
+			case C7000_SYS_VALIDATE_RESP:
+
+				if (cup->control_blk.ret_code == 0)
+					resp = 0;
+				else {
+					CPrintk(0, "c7000: c7000_get_sysval_resp: receive sysval response for device 0x%x, return code %d\n",
+						cup->devno,
+						cup->control_blk.ret_code);
+					return(-1);
+				}
+
+				break;
+
+			/*
+				Check that the request is reasonable and
+				send a SYS_VALIDATE_RESP.  Otherwise,
+				return with an error.
+			*/
+
+			case C7000_SYS_VALIDATE:
+				CPrintk(1, "c7000: c7000_get_sysval_resp: receive sysval for device 0x%x\n", cup->devno);
+				req = 0;
+				ret_code = c7000_checkinfo(cup);
+
+				if (c7000_send_sysval_resp(&ccp->cunits[C7000_WR], cup->control_blk.correlator, ret_code) != 0)
+					return(-1);
+
+				if (ret_code != 0)
+					return(-1);
+
+				break;
+
+			/*
+				Anything else is unexpected and will result
+				in a return with an error.
+			*/
+
+			default:
+				CPrintk(0, "c7000: c7000_get_sysval_resp: receive unexpected command for device 0x%x, command %d\n", cup->devno, cup->control_blk.cmd);
+				return(-1);
+				break;
+		}
+
+	}
+
+	return(0);
+}
+
+/*
+	Send a connection confirm control message.
+*/
+
+static int
+c7000_conn_confrm(struct c7000_unit *cup, unsigned char correlator, int linkid)
+{
+	int				rc;
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_control_blk	*ctlblkp = &(cup->control_blk);
+
+	CPrintk(1, "c7000: c7000_conn_confrm: send the connection confirmation message for unit 0x%x\n", cup->devno);
+
+	/*
+		Build the connection confirm control message.
+	*/
+
+	memset(ctlblkp, '\0', sizeof(struct c7000_control_blk));
+	ctlblkp->cmd = C7000_CONN_CONFRM;
+	ctlblkp->ver = ccp->version;
+	ctlblkp->link_id = linkid;
+	ctlblkp->correlator = correlator;
+	ctlblkp->rdsize = 0;
+	ctlblkp->wrtsize = 0;
+	memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN);
+	memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN);
+
+	/*
+		Build the channel program.
+	*/
+
+	c7000_bld_wrtctl_chpgm(cup);
+
+	/*
+		Do the IO and wait for write to complete.
+	*/
+
+	if ((rc = c7000_doio(cup)) != 0) {
+		CPrintk(0, "c7000: c7000_conn_confrm: failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+/*
+	Send a connection request control message.
+*/
+
+static int
+c7000_send_conn(struct c7000_unit *cup)
+{
+	int				rc;
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_control_blk	*ctlblkp = &(cup->control_blk);
+
+	CPrintk(1, "c7000: c7000_send_conn: send the connection request message for unit 0x%x\n", cup->devno);
+
+	/*
+		Build the connection request control message.
+	*/
+
+	memset(ctlblkp, '\0', sizeof(struct c7000_control_blk));
+	ctlblkp->cmd = C7000_CONN_REQ;
+	ctlblkp->ver = ccp->version;
+	ctlblkp->link_id = 0;
+	ctlblkp->correlator = 0;
+	ctlblkp->rdsize = C7000_DATAL;
+	ctlblkp->wrtsize = C7000_DATAL;
+	memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN);
+	memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN);
+
+	/*
+		Build the channel program.
+	*/
+
+	c7000_bld_wrtctl_chpgm(cup);
+
+	/*
+		Do the IO and wait for write to complete.
+	*/
+
+	if ((rc = c7000_doio(cup)) != 0) {
+		CPrintk(0, "c7000: c7000_send_conn: failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+/*
+	Send a disconnect control message to the link with the value of
+	linkid.
+*/
+
+static int
+c7000_send_disc(struct c7000_unit *cup, int linkid)
+{
+	int				rc;
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_control_blk	*ctlblkp = &(cup->control_blk);
+
+	CPrintk(1, "c7000: c7000_send_disc: send disconnect message for unit 0x%x\n", cup->devno);
+
+	/*
+		Build the disconnect control message.
+	*/
+
+	memset(ctlblkp, '\0', sizeof(struct c7000_control_blk));
+	ctlblkp->cmd = C7000_DISCONN;
+	ctlblkp->ver = ccp->version;
+	ctlblkp->link_id = linkid;
+	ctlblkp->correlator = 0;
+	ctlblkp->rdsize = C7000_DATAL;
+	ctlblkp->wrtsize = C7000_DATAL;
+	memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN);
+	memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN);
+
+	/*
+		Build the channel program.
+	*/
+
+	c7000_bld_wrtctl_chpgm(cup);
+
+	/*
+		Do the IO and wait for write to complete.
+	*/
+
+	if ((rc = c7000_doio(cup)) != 0) {
+		CPrintk(0, "c7000: c7000_send_disc: failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+/*
+	Resolve the race condition based on the link identifier value.
+	The adapter microcode assigns the identifiers.  A higher value implies
+	that the race was lost. A side effect of this function is that
+	ccp->linkid is set to the link identifier to be used for this
+	connection (provided that 0 is returned).
+*/
+
+static int
+c7000_resolve_race(struct c7000_unit *cup, int local_linkid, int remote_linkid)
+{
+	struct c7000_controller 	*ccp = cup->cntlp;
+
+	CPrintk(1, "c7000: c7000_resolve_race: for unit 0x%x, local linkid %d, remote linkid %d\n", cup->devno, local_linkid, remote_linkid);
+
+	/*
+		This local link identifier should not be zero..
+	*/
+
+	if (local_linkid == 0) {
+		CPrintk(0, "c7000: c7000_resolve_race: error for unit 0x%x, local linkid is null\n", cup->devno);
+		return(-1);
+	}
+
+	/*
+		This indicates that there is no race.  Just use our
+		local link identifier.
+	*/
+
+	if (remote_linkid == 0) {
+		ccp->linkid = local_linkid;
+		return(0);
+	}
+
+	/*
+		Send a connection confirm message if we lost the race to
+		the winning link identifier.
+
+		Either way, save the winning link identifier.
+	*/
+
+	if (local_linkid > remote_linkid) {
+
+		if (c7000_conn_confrm(&ccp->cunits[C7000_WR], cup->control_blk.correlator, remote_linkid) != 0) {
+			CPrintk(0, "c7000: c7000_resolve_race: failed for unit 0x%x\n", cup->devno);
+			return(-1);
+		}
+
+		ccp->linkid = remote_linkid;
+	} else {
+		ccp->linkid = local_linkid;
+	}
+
+	return(0);
+}
+
+/*
+	Get connected by processing the connection request/response/confirm
+	control messages.  A connection request has already been sent by
+	calling function c7000_send_conn.
+*/
+
+static int
+c7000_get_conn(struct c7000_unit *cup)
+{
+	struct c7000_controller 	*ccp = cup->cntlp;
+	int				rc;
+	int				cont = 1;
+	int				remote_linkid = 0;
+	int				local_linkid = 0;
+
+	CPrintk(1, "c7000: c7000_get_conn: read the connected message for unit 0x%x\n", cup->devno);
+	ccp->linkid = 0;
+
+	while (cont == 1) {
+
+		/*
+			Build the read channel program.
+		*/
+
+		c7000_bld_readctl_chpgm(cup);
+
+		/*
+			Start the channel program to read a control message.
+		*/
+
+		if ((rc = c7000_doio(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_get_conn: failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+			return(-1);
+		}
+
+		/*
+			Process the control message that was received based
+			on the command code.
+		*/
+
+		CPrintk(1, "c7000: c7000_get_conn: received command %d for unit 0x%x\n", cup->control_blk.cmd, cup->devno);
+
+		switch(cup->control_blk.cmd) {
+
+			/*
+				Save the remote link_id in the message for
+				a check in c7000_resolve_race.
+			*/
+
+			case C7000_CONN_REQ:
+				remote_linkid = cup->control_blk.link_id;
+				break;
+
+			/*
+				A connection response received.  Resolve
+				the network race condition (if any) by
+				comparing the link identifier values.
+			*/
+
+			case C7000_CONN_RESP:
+
+				if (cup->control_blk.ret_code != 0) {
+					CPrintk(0, "c7000: c7000_get_conn: failed for unit 0x%x , connection response return code %d\n",
+						cup->devno, cup->control_blk.ret_code);
+					return(-1);
+				}
+
+				local_linkid = cup->control_blk.link_id;
+
+				if (c7000_resolve_race(cup, local_linkid, remote_linkid) != 0)
+					return(-1);
+
+				break;
+
+			/*
+				Got a confirmation to our connection request.
+				Disconnect the remote link identifier (if any).
+				Break out of the loop.
+			*/
+
+			case C7000_CONN_CONFRM:
+
+				if (remote_linkid != 0) {
+
+					if (c7000_send_disc(&ccp->cunits[C7000_WR], remote_linkid) != 0) {
+						CPrintk(0, "c7000: c7000_get_conn: send disconnect failed for unit 0x%x\n", cup->devno);
+						return(-1);
+					}
+
+				}
+
+				cont = 0;
+				break;
+
+			/*
+				Got a disconnect to our connection request.
+				Break out of the loop.
+			*/
+
+			case C7000_DISCONN:
+				cont = 0;
+				break;
+
+			/*
+				Anything else must be an error.
+				Return with an error immediately.
+			*/
+
+			default:
+				CPrintk(0, "c7000: c7000_get_conn: failed for unit 0x%x unexpected command %d\n",
+					cup->devno, cup->control_blk.cmd);
+				return(-1);
+		}
+
+	}
+
+	/*
+		Be sure that we now have a link identifier.
+	*/
+
+	if (ccp->linkid == 0)
+		return(-1);
+
+	return(0);
+}
+
+/*
+	Get statistics method.
+*/
+
+struct net_device_stats *
+c7000_stats(STRUCT_NET_DEVICE *dev)
+{
+	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
+
+	return(&ccp->stats);
+}
+
+/*
+	Open method.
+*/
+
+static int
+c7000_open(STRUCT_NET_DEVICE *dev)
+{
+	int				i;
+	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
+	struct	c7000_unit		*cup;
+	int				rc;
+	__u32				parm;
+	__u8				flags = 0x00;
+
+	c7000_set_busy(dev);
+
+	/*
+		Allocate space for the unit buffers.
+	*/
+
+	if (c7000_alloc_buffers(dev) == -1) {
+		CPrintk(0, "c7000: c7000_open: can not allocate buffer space for base unit 0x%lx\n", dev->base_addr);
+		c7000_free_buffers(dev);  /* free partially allocated buffers */
+		c7000_clear_busy(dev);
+		return(-ENOMEM);
+	}
+	
+	/*
+		Perform the initialization for all units.
+	*/
+
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+
+		/*
+			Initialize task queue structure used for the bottom
+			half routine.
+		*/
+
+#ifndef NEWSTUFF
+		cup->tq.next = NULL;
+#endif
+		cup->tq.sync = 0;
+		cup->tq.routine = (void *)(void *)c7000_irq_bh;
+		cup->tq.data = cup;
+		cup->state = C7000_HALT;
+#ifdef NEWSTUFF
+		init_waitqueue_head(&cup->wait);
+#endif
+		CPrintk(1, "c7000: c7000_open: issuing halt to unit 0x%x\n", cup->devno);
+
+		/*
+			Issue a halt I/O to the unit
+		*/
+
+		if ((rc = c7000_haltio(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_open: halt_IO failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+			continue;
+		}
+
+		cup->IO_active = 0;
+		cup->flag_a = 0;
+		cup->sigsmod = 0x00;
+
+		CPrintk(1, "c7000: c7000_open: halt complete for unit 0x%x\n", cup->devno);
+	}
+
+	/*
+		On each subchannel send a sense id.
+	*/
+
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+
+		/*
+			Build SENSE ID channel program.
+		*/
+
+		c7000_bld_senseid_chpgm(cup);
+	
+		/*
+			Issue the start I/O for SENSE ID channel program.
+		*/
+
+		CPrintk(1, "c7000: c7000_open: issuing SENSEID to unit 0x%x\n", cup->devno);
+
+		if ((rc = c7000_doio(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_open: SENSEID failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+			c7000_clear_busy(dev);
+			return(-EIO);
+		}
+	
+		CPrintk(1, "c7000: c7000_open: SENSEID complete for unit 0x%x\n", cup->devno);
+	}
+
+	/*
+		Send the system validation control message.
+	*/
+
+	cup = &ccp->cunits[C7000_WR];
+
+	if (c7000_send_sysval(cup) != 0) {
+		CPrintk(0, "c7000: c7000_open: can not send sysval for unit 0x%x\n", cup->devno);
+		c7000_clear_busy(dev);
+		return(-EIO);
+	}
+
+	CPrintk(1, "c7000: c7000_open: successfully sent sysval for unit 0x%x\n", cup->devno);
+	/*
+		Get the system validation response message.
+	*/
+
+	cup = &ccp->cunits[C7000_RD];
+
+	if (c7000_get_sysval_resp(cup) != 0) {
+		CPrintk(0, "c7000: c7000_open: can not read sysval response for unit 0x%x\n", cup->devno);
+		c7000_clear_busy(dev);
+		return(-EIO);
+	}
+
+	CPrintk(1, "c7000: c7000_open: successfully received sysval reply for unit 0x%x\n", cup->devno);
+	ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_CONNECT;
+
+	cup = &ccp->cunits[C7000_WR];
+
+	/*
+		Send a connection request.
+	*/
+
+	if (c7000_send_conn(cup) != 0) {
+		CPrintk(0, "c7000: c7000_open: connection failed for unit 0x%x\n", cup->devno);
+		c7000_clear_busy(dev);
+		return(-EIO);
+	}
+
+	cup = &ccp->cunits[C7000_RD];
+
+	/*
+		Get the response to our connection request Note that a
+		network race may occur.  This is handled in c7000_get_conn.
+	*/
+
+	if (c7000_get_conn(cup) != 0) {
+		CPrintk(0, "c7000: c7000_open: unit 0x%x has connected\n", cup->devno);
+		c7000_clear_busy(dev);
+		return(-EIO);
+	}
+
+	CPrintk(1, "c7000: c7000_open: successfully received connection request for unit 0x%x\n", cup->devno);
+	ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_READY;
+
+	/*
+		Clear the interface statistics.
+	*/
+
+	memset(&ccp->stats, '\0', sizeof(struct net_device_stats));
+
+	if ((rc = c7000_bld_read_chain(cup)) != 0) {
+		c7000_clear_busy(dev);
+		return(rc);
+	}
+
+	/*
+		Start the C7000_READ channel program but do not wait for it's
+		completion.
+	*/
+
+	cup->state = C7000_READ;
+	parm = (__u32) cup;
+	set_bit(0, (void *)&cup->IO_active);
+
+	if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
+		CPrintk(0, "c7000: c7000_open: READ failed with return code %d for unit 0x%x\n", rc, cup->devno);
+		c7000_error(cup->cntlp);
+		clear_bit(0, (void *)&cup->IO_active);
+		c7000_clear_busy(dev);
+		return(-EIO);
+	}
+
+#ifdef NEWSTUFF
+	netif_start_queue(dev);
+#else
+	dev->start = 1;
+#endif
+	CPrintk(0, "c7000: c7000_open: base unit 0x%lx is opened\n", dev->base_addr);
+	c7000_clear_busy(dev);
+	MOD_INC_USE_COUNT;	/* increment module usage count */
+	return(0);
+}
+
+/*
+	Stop method.
+*/
+
+static int
+c7000_stop(STRUCT_NET_DEVICE *dev)
+{
+	int				i;
+	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
+	struct	c7000_unit		*cup;
+	int				rc;
+
+#ifdef NEWSTUFF
+/* nothing? */
+#else
+	dev->start = 0;
+#endif
+	c7000_set_busy(dev);
+
+	/*
+		Send a disconnect message.
+	*/
+
+	ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_DISC;
+	cup = &ccp->cunits[C7000_WR];
+
+	if (c7000_send_disc(cup, ccp->linkid) != 0) {
+		CPrintk(0, "c7000: c7000_stop: send of disconnect message failed for unit 0x%x\n", cup->devno);
+	}
+
+	CPrintk(1, "c7000: c7000_stop: successfully sent disconnect message to unit 0x%x\n", cup->devno);
+
+	/*
+		Issue a halt I/O to all units.
+	*/
+
+	for (i = 0; i < NUNITS; i++) {
+		cup = &ccp->cunits[i];
+		cup->state = C7000_STOP;
+		CPrintk(1, "c7000: c7000_stop: issuing halt to unit 0x%x\n", cup->devno);
+
+		if ((rc = c7000_haltio(cup)) != 0) {
+			CPrintk(0, "c7000: c7000_stop: halt_IO failed with rc = %d for unit 0x%x\n", rc, cup->devno);
+			continue;
+		}
+
+		CPrintk(1, "c7000: c7000_stop: halt complete for unit 0x%x\n", cup->devno);
+	}
+
+	c7000_free_buffers(dev);
+	CPrintk(0, "c7000: c7000_stop: base unit 0x%lx is stopped\n", dev->base_addr);
+	MOD_DEC_USE_COUNT;	/* Decrement module usage count */
+	return(0);
+}
+
+/*
+	Configure the interface.
+*/
+
+static int
+c7000_config(STRUCT_NET_DEVICE *dev, struct ifmap *map)
+{
+	CPrintk(1, "c7000: c7000_config: entered for base unit 0x%lx\n", dev->base_addr);
+	return(0);
+}
+
+/*
+	Transmit a packet.
+*/
+
+static int
+c7000_xmit(struct sk_buff *skb, STRUCT_NET_DEVICE *dev)
+{
+	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
+	struct	c7000_unit		*cup;
+	__u32				saveflags;
+	__u32				parm;
+	__u8				flags = 0x00;
+	struct	c7000_buffer		*buf, *pbuf;
+	int				rc;
+
+	CPrintk(1, "c7000: c7000_xmit: entered for base unit 0x%lx\n", dev->base_addr);
+
+	/*
+		When the skb pointer is NULL return.
+	*/
+
+	if (skb == NULL) {
+		CPrintk(0, "c7000: c7000_xmit: skb pointer is null for base unit 0x%lx\n", dev->base_addr);
+		ccp->stats.tx_dropped++;
+		return(-EIO);
+	}
+
+	cup = &ccp->cunits[C7000_WR];
+
+	/*
+		Lock the irq.
+	*/
+
+	s390irq_spin_lock_irqsave(cup->irq, saveflags);
+	
+	/*
+		When the device transmission busy flag is on , no data
+		can be sent.  Unlock the irq and return EBUSY.
+	*/
+
+	if (c7000_check_busy(dev)) {
+		CPrintk(1, "c7000: c7000_xmit: c7000_check_busy returns true for base unit 0x%lx\n", dev->base_addr);
+		s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+		return(-EBUSY);
+	}
+
+	/*
+		Set the device transmission busy flag on atomically.
+	*/
+
+	if (c7000_ts_busy(TB_TX, dev)) {
+		CPrintk(1, "c7000: c7000_xmit: c7000_ts_busy returns true for base unit 0x%lx\n", dev->base_addr);
+		s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+		return(-EBUSY);
+	}
+
+	CPrintk(1, "c7000: c7000_xmit: set TB_TX for unit 0x%x\n", cup->devno);
+
+	/*
+		Obtain a free buffer.  If none are free then mark tbusy
+		with TB_NOBUFFER and return EBUSY.
+	*/
+
+	if ((buf = c7000_get_buffer(cup)) == NULL) {
+		CPrintk(1, "c7000: c7000_xmit: setting TB_NOBUFFER for base unit 0x%lx\n", dev->base_addr);
+		c7000_setbit_busy(TB_NOBUFFER, dev);
+		c7000_clearbit_busy(TB_TX, dev);
+		s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+		return(-EBUSY);
+	}
+
+	CPrintk(1, "c7000: c7000_xmit: Got buffer for unit 0x%x\n", cup->devno);
+
+	/*
+		Save the length of the skb data and then copy it to the
+		buffer.  Queue the buffer on the processing list.
+	*/
+
+	buf->len = skb->len;
+	memcpy(buf->data, skb->data, skb->len);
+	memset(buf->data + C7000_DATAL + C7000_READHDRL, '\0', C7000_READFFL);
+	pbuf = cup->proc_tail;
+	c7000_queue_buffer(cup, buf);
+
+	/*
+		Chain the buffer to the running channel program.
+	*/
+
+	if (test_bit(0, (void *)&cup->IO_active) && pbuf != NULL) {
+		c7000_bld_wrt_chpgm(cup, buf);
+		pbuf->ccws[2].cda = (__u32)virt_to_phys(&buf->ccws[0]);
+	}
+
+	/*
+		Free the socket buffer.
+	*/
+
+	dev_kfree_skb(skb);
+
+	/*
+		If the unit is not currently doing IO, build a channel
+		program and start the IO for the buffers on the processing
+		chain.
+	*/
+
+	if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) {
+		CPrintk(1, "c7000: c7000_xmit: start IO for unit 0x%x\n", cup->devno);
+		c7000_bld_wrt_chain(cup);
+		parm = (__u32) cup;
+		cup->state = C7000_WRITE;
+
+		if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
+			CPrintk(0, "c7000: c7000_xmit: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno);
+			c7000_error(cup->cntlp);
+			c7000_clearbit_busy(TB_TX, dev);
+			s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+			return(-EIO);
+		}
+
+		dev->trans_start = jiffies;
+		CPrintk(1, "c7000: c7000_xmit: do_IO succeeds for unit 0x%x\n", cup->devno);
+	}
+		
+	/*
+		If the free chain is now NULL, set the TB_NOBUFFER flag.
+	*/
+
+	if (cup->free == NULL) {
+		CPrintk(1, "c7000: c7000_xmit: setting TB_NOBUFFER for base unit 0x%lx\n", dev->base_addr);
+		c7000_setbit_busy(TB_NOBUFFER, dev);
+	}
+
+	c7000_clearbit_busy(TB_TX, dev);
+	s390irq_spin_unlock_irqrestore(cup->irq, saveflags);
+	CPrintk(1, "c7000: c7000_xmit: exits for unit 0x%x\n", cup->devno);
+	return(0);
+}
+
+/*
+	Handle an ioctl from a user process.
+*/
+
+static int
+c7000_ioctl(STRUCT_NET_DEVICE *dev, struct ifreq *ifr, int cmd)
+{
+	CPrintk(1, "c7000: c7000_ioctl: entered for base unit 0x%lx with cmd %d\n", dev->base_addr, cmd);
+	return(0);
+}
+
+/*
+	Analyze the interrupt status and return a value
+	that identifies the type.
+*/
+
+static enum c7000_rupt
+c7000_check_csw(devstat_t *devstat)
+{
+
+	/*
+		Check for channel detected conditions (except PCI).
+	*/
+
+	if ((devstat->cstat & ~SCHN_STAT_PCI) != 0) {
+		CPrintk(0, "c7000: c7000_check_csw: channel status 0x%x for unit 0x%x\n", devstat->cstat, devstat->devno);
+		return(C7000_CHANERR);
+	}
+
+	/*
+		Fast path the normal cases.
+	*/
+
+	if (devstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+		return(C7000_NORMAL);
+
+	if (devstat->cstat == SCHN_STAT_PCI)
+		return(C7000_NORMAL);
+
+	/*
+		Check for exceptions.
+	*/
+
+	if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+		CPrintk(0, "c7000: c7000_check_csw: unit check for unit 0x%x, sense byte0 0x%2.2x\n", devstat->devno, devstat->ii.sense.data[0]);
+
+		if (devstat->ii.sense.data[0] == C7000_BOX_RESET)
+			return(C7000_UCK_RESET);
+		else
+			return(C7000_UCK);
+
+	} else if (devstat->dstat & DEV_STAT_UNIT_EXCEP) {
+		CPrintk(0, "c7000: c7000_check_csw: unit exception for unit 0x%x\n", devstat->devno);
+		return(C7000_UE);
+
+	} else if (devstat->dstat & DEV_STAT_ATTENTION) {
+		CPrintk(0, "c7000: c7000_check_csw: attention for unit 0x%x\n", devstat->devno);
+		return(C7000_ATTN);
+
+	} else if (devstat->dstat & DEV_STAT_BUSY) {
+		CPrintk(0, "c7000: c7000_check_csw: busy for unit 0x%x\n", devstat->devno);
+		return(C7000_BUSY);
+
+	} else {
+		CPrintk(0, "c7000: c7000_check_csw: channel status 0x%2.2x , device status 0x%2.2x, devstat flags 0x%8.8x for unit 0x%x\n",
+			devstat->cstat, devstat->dstat, devstat->flag, devstat->devno);
+		return(C7000_OTHER);
+	}
+
+	/* NOT REACHED */
+
+}
+
+/*
+	Retry the last CCW chain to the unit.
+*/
+
+static void
+c7000_retry_io(struct c7000_unit *cup)
+{
+	int	rc;
+	__u32	parm;
+	__u8	flags = 0x00;
+	ccw1_t	*ccwp;
+
+	if (++cup->retries > C7000_MAX_RETRIES) {
+		c7000_error(cup->cntlp);
+		CPrintk(0, "c7000: c7000_retry_io: retry IO for unit 0x%x exceeds maximum retry count\n", cup->devno);
+		return;
+	}
+
+	set_bit(0, (void *)&cup->IO_active);
+	parm = (__u32)cup;
+
+	if (cup->state == C7000_READ || cup->state == C7000_WRITE)
+		ccwp = &cup->proc_head->ccws[0];
+	else
+		ccwp = &cup->ccws[0];
+
+	if ((rc = do_IO(cup->irq, ccwp, parm, 0xff, flags)) != 0) {
+		CPrintk(0, "c7000: c7000_retry_io: can not retry IO for unit 0x%x, return code %d\n", cup->devno, rc);
+		clear_bit(0, (void *)&cup->IO_active);
+		c7000_error(cup->cntlp);
+	}
+
+	CPrintk(1, "c7000: c7000_retry_io: retry IO for unit 0x%x, retry count %d\n", cup->devno, cup->retries);
+	return;
+}
+
+/*
+	Process a read interrupt by scanning the list of buffers
+	for ones that have completed and queue them for the bottom
+	half to process.
+*/
+
+static void
+c7000_proc_rintr(struct c7000_unit *cup)
+{
+	struct	c7000_buffer	*buf;
+	struct	c7000_rd_header	*head;
+	int			num_read = 0;
+
+	while (cup->proc_head != NULL) {
+		head = (struct c7000_rd_header *)(cup->proc_head->data + C7000_DATAL);
+
+		/*
+			The flag byte in the read header will be set to
+			FLAG_FF when the buffer has been read.
+		*/
+
+		if (head->flag != FLAG_FF)
+			break;
+		
+		/*
+			Dequeue the buffer from the proc chain
+			and enqueue it on the bh chain for
+			the bh routine to process.
+		*/
+
+		buf = c7000_dequeue_buffer(cup);
+		c7000_queue_bh_buffer(cup, buf);
+		num_read++;
+	}
+
+	CPrintk(1, "c7000: c7000_proc_rintr: %d buffers read for unit 0x%x\n", num_read, cup->devno);
+	return;
+}
+
+/*
+	Process all completed buffers on the proc chain.
+	A buffer is completed if it's READFF flag is FLAG_FF.
+*/
+
+static int
+c7000_proc_wintr(struct c7000_unit *cup)
+{
+	struct	c7000_controller	*ccp = cup->cntlp;
+	struct	c7000_buffer		*buf;
+	int				num_write = 0;
+
+	if (cup->proc_head == NULL) {
+		CPrintk(0, "c7000: c7000_proc_wintr: unexpected NULL processing chain pointer for unit 0x%x\n", cup->devno);
+		return(num_write);
+	}
+
+	while (cup->proc_head != NULL) {
+
+		/*
+			Check if the buffer has completed.
+		*/
+
+		if (*(cup->proc_head->data + C7000_DATAL + C7000_READHDRL) != FLAG_FF)
+			break;
+
+		/*
+			Remove buffer from top of processing chain.
+			Place it on free list.
+		*/
+
+		buf = c7000_dequeue_buffer(cup);
+		c7000_release_buffer(cup, buf);
+		num_write++;
+
+		/*
+			Update transmitted packets statistic.
+		*/
+
+		ccp->stats.tx_packets++;
+	}
+
+	CPrintk(1, "c7000: c7000_proc_wintr: %d buffers written for unit 0x%x\n", num_write, cup->devno);
+	return(num_write);
+}
+
+/*
+	Interrupt handler.
+*/
+
+static void
+c7000_intr(int irq, void *initparm, struct pt_regs *regs)
+{
+	devstat_t			*devstat = ((devstat_t *) initparm);
+	struct	c7000_unit		*cup = NULL;
+	struct	c7000_controller	*ccp = NULL;
+	STRUCT_NET_DEVICE		*dev = NULL;
+	__u32				parm;
+	__u8				flags = 0x00;
+	int				rc;
+
+	/*
+		Discard unsolicited interrupts
+	*/
+
+	if (devstat->intparm == 0) {
+		CPrintk(0, "c7000: c7000_intr: unsolicited interrupt for device 0x%x, cstat = 0x%2.2x, dstat = 0x%2.2x, flag = 0x%8.8x\n",
+			devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
+		return;
+	}
+
+	/*
+		Obtain the c7000_unit structure pointer.
+	*/
+
+	cup = (struct c7000_unit *)(devstat->intparm);
+
+	/*
+		Obtain the c7000_controller structure and device structure
+		pointers.
+	*/
+
+	if (cup == NULL) {
+		CPrintk(0, "c7000: c7000_intr: c7000_unit pointer is NULL in devstat\n");
+		return;
+	}
+
+	ccp = cup->cntlp;
+
+	if (ccp == NULL) {
+		CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure 0x%x for unit 0x%x\n", (int)cup, cup->devno);
+		return;
+	}
+
+	dev = ccp->dev;
+
+	if (dev == NULL) {
+		CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure 0x%x for unit 0x%x\n", (int)ccp, cup->devno);
+		return;
+	}
+
+	/*
+		Finite state machine (fsm) handling.
+	*/
+
+	CPrintk(1, "c7000: c7000_intr: entered with state %d flag 0x%8.8x for unit 0x%x\n", cup->state, devstat->flag, cup->devno);
+
+	switch(cup->state) {
+
+		/*
+			Not expected to be here when in INIT state.
+		*/
+
+		case C7000_INIT:
+
+			break;
+
+		/*
+			Enter state C7000_SID and wakeup the sleeping
+			process in c7000_open.
+		*/
+
+		case C7000_HALT:
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			cup->state = C7000_SID;
+			wake_up(&cup->wait);
+			break;
+		
+		/*
+			Enter state C7000_SYSVAL and wakeup the sleeping
+			process in c7000_open.
+		*/
+			
+		case C7000_SID:
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			if (c7000_check_csw(devstat) != 0) {
+				c7000_retry_io(cup);
+
+				if (cup->state == C7000_ERROR)
+					wake_up(&cup->wait);
+
+				break;
+			}
+
+			cup->retries = 0;
+			cup->state = C7000_SYSVAL;
+			wake_up(&cup->wait);
+			break;
+
+		/*
+			Wakeup the sleeping process in c7000_open.
+		*/
+
+		case C7000_SYSVAL:
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			if (c7000_check_csw(devstat) != 0) {
+				c7000_retry_io(cup);
+
+				if (cup->state == C7000_ERROR)
+					wake_up(&cup->wait);
+
+				break;
+			}
+
+			cup->retries = 0;
+			wake_up(&cup->wait);
+			break;
+
+		/*
+			Wakeup the sleeping process in c7000_open.
+		*/
+
+		case C7000_CONNECT:
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			if (c7000_check_csw(devstat) != 0) {
+				c7000_retry_io(cup);
+
+				if (cup->state == C7000_ERROR)
+					wake_up(&cup->wait);
+
+				break;
+			}
+
+			cup->retries = 0;
+			wake_up(&cup->wait);
+			break;
+
+		/*
+			Not expected to be entered here.
+		*/
+
+		case C7000_READY:
+			break;
+
+		/*
+			Process the data that was just read.
+		*/
+
+		case C7000_READ:
+
+			if ((devstat->flag & (DEVSTAT_PCI | DEVSTAT_FINAL_STATUS)) == 0)
+				break;
+
+			CPrintk(1, "c7000: c7000_intr: process read interrupt for unit 0x%x , devstat flag = 0x%8.8x\n", cup->devno, devstat->flag);
+
+			/*
+				Check for serious errors.
+			*/
+
+			if (c7000_check_csw(devstat) != 0) {
+				ccp->stats.rx_errors++;
+				c7000_error(cup->cntlp);
+				break;
+			}
+
+			/*
+				Build the bottom half buffer list.
+			*/
+
+			c7000_proc_rintr(cup);
+
+			/*
+				When final status is received clear
+				the IO active bit.
+			*/
+
+			if (devstat->flag & DEVSTAT_FINAL_STATUS) {
+				clear_bit(0, (void *)&cup->IO_active);
+			}
+
+			/*
+				If there are free buffers redrive the IO.
+			*/
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) &&
+			    (cup->free != NULL)) {
+				c7000_bld_read_chain(cup);
+				parm = (__u32)cup;
+				set_bit(0, (void *)&cup->IO_active);
+
+				if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
+					clear_bit(0, (void *)&cup->IO_active);
+					CPrintk(0, "c7000: c7000_intr: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno);
+					c7000_error(cup->cntlp);
+					break;
+				}
+
+				CPrintk(1, "c7000: c7000_intr: started read io for unit 0x%x\n", cup->devno);
+			}
+
+			/*
+				Initiate bottom half routine to process
+				data that was read.
+			*/
+
+			if (test_and_set_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a) == 0) {
+				queue_task(&cup->tq, &tq_immediate);
+				mark_bh(IMMEDIATE_BH);
+			}
+
+			break;
+
+		/*
+			Free the transmitted buffers and restart the channel
+			process (if necessary).
+		*/
+
+		case C7000_WRITE:
+
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			if (c7000_check_csw(devstat) != 0) {
+				ccp->stats.tx_errors++;
+				c7000_error(cup->cntlp);
+				break;
+			}
+
+			/*
+				If at least one buffer was freed, clear
+				the NOBUFFER indication.
+			*/
+
+			if (c7000_proc_wintr(cup) != 0) {
+				c7000_clearbit_busy(TB_NOBUFFER, dev);
+			}
+
+			/*
+				Restart the channel program if there are more
+				buffers on the processing chain.
+			*/
+
+			if (cup->proc_head != NULL) {
+				c7000_bld_wrt_chain(cup);
+				parm = (__u32)cup;
+				set_bit(0, (void *)&cup->IO_active);
+
+				if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
+					CPrintk(0, "c7000: c7000_intr: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno);
+					clear_bit(0, (void *)&cup->IO_active);
+					c7000_error(cup->cntlp);
+					break;
+				}
+
+				dev->trans_start = jiffies;
+			} else {
+				clear_bit(0, (void *)&cup->IO_active);
+				cup->state = C7000_READY;
+			}
+
+			break;
+
+		/*
+			Disconnect message completed.  Wakeup the
+			sleeping process in c7000_stop.
+		*/
+
+		case C7000_DISC:
+			if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0)
+				break;
+
+			if (c7000_check_csw(devstat) != 0) {
+				c7000_retry_io(cup);
+
+				if (cup->state == C7000_ERROR)
+					wake_up(&cup->wait);
+
+				break;
+			}
+
+			cup->retries = 0;
+			wake_up(&cup->wait);
+			break;
+
+		/*
+			Subchannel is now halted.  Wakeup the sleeping
+			process in c7000_stop.  Set the state to C7000_STOPPED.
+		*/
+
+		case C7000_STOP:
+
+			cup->state = C7000_STOPPED;
+			wake_up(&cup->wait);
+			break;
+
+		/*
+			When in error state, stay there until the
+			interface is recycled.
+		*/
+
+		case C7000_ERROR:
+
+			break;
+
+		/*
+			Should not reach here
+		*/
+
+		default:
+			CPrintk(0, "c7000: c7000_intr: entered default case for unit 0x%x, state %d\n", cup->devno, cup->state);
+			break;
+
+	}
+
+	CPrintk(1, "c7000: c7000_intr: exited with state %d for unit 0x%x\n", cup->state, cup->devno);
+	return;
+}
+
+/*
+	Fill in system validation name padding it with blanks.
+*/
+
+static void
+c7000_fill_name(char *dst, char *src)
+{
+	char	*tmp = dst;
+	int	i;
+
+	for (i = 0; i < NAMLEN; i++, tmp++) 
+		*tmp = ' ';
+
+	for (i = 0; i < NAMLEN && *src != '\0'; i++)
+		*dst++ = *src++;
+
+	return;
+}
+
+/*
+	Initialization routine called when the device is registered.
+*/
+
+static int
+c7000_init(STRUCT_NET_DEVICE *dev)
+{
+	struct	c7000_controller	*ccp;
+	int				i;
+	int				unitaddr;
+	int				irq;
+
+	/*
+		Find the position of base_addr in the bases array.
+	*/
+
+	for (i = 0; i < MAX_C7000; i++) 
+		if (bases[i] == dev->base_addr)
+			break;
+
+	if (i == MAX_C7000)
+		return(-ENODEV);
+
+	/*
+		Make sure it is a C7000 type of device.
+	*/
+
+	if (c7000_check_devices(dev->base_addr) != 0) {
+		CPrintk(0, "c7000: c7000_init: base unit 0x%lx is not the right type\n", dev->base_addr);
+		return(-ENODEV);
+	}
+
+	/*
+		Initialize the device structure functions.
+		Note that ARP is not done on the CLAW interface.
+		There is no ethernet header.
+	*/
+
+	dev->mtu = C7000_DATAL;
+	dev->hard_header_len = 0;
+        dev->addr_len = 0;
+        dev->type = ARPHRD_SLIP;
+        dev->tx_queue_len = C7000_TXQUEUE_LEN;
+	dev->flags = IFF_NOARP;   
+	dev->open = c7000_open;
+	dev->stop = c7000_stop;
+	dev->set_config = c7000_config;
+	dev->hard_start_xmit = c7000_xmit;
+	dev->do_ioctl = c7000_ioctl;
+	dev->get_stats = c7000_stats;
+
+	/*
+		Allocate space for a private data structure.
+	*/
+
+	if ((ccp = dev->priv = kmalloc(sizeof(struct c7000_controller), GFP_KERNEL)) == NULL) {
+		CPrintk(0, "c7000: c7000_init: base unit 0x%lx can not be initialized\n", dev->base_addr);
+		return(-ENOMEM);
+	}
+
+	CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address 0x%x\n", (int)ccp);
+	memset(ccp, '\0', sizeof(struct c7000_controller));
+	ccp->dev = dev;
+	ccp->base_addr = dev->base_addr;
+
+	/*
+		Populate the system validation name with default values.
+	*/
+
+	c7000_fill_name(ccp->lappl, C7000_DFLT_LAPPL);
+	c7000_fill_name(ccp->lhost, C7000_DFLT_LHOST);
+	c7000_fill_name(ccp->uappl, C7000_DFLT_UAPPL);
+	c7000_fill_name(ccp->uhost, C7000_DFLT_UHOST);
+
+	/*
+		When values have been supplied, replace the prior defaults.
+	*/
+
+	if (i == 0) {
+
+		if (lappl0 != NULL)
+			c7000_fill_name(ccp->lappl, lappl0);
+
+		if (lhost0 != NULL)
+			c7000_fill_name(ccp->lhost, lhost0);
+
+		if (uappl0 != NULL)
+			c7000_fill_name(ccp->uappl, uappl0);
+
+		if (uhost0 != NULL)
+			c7000_fill_name(ccp->uhost, uhost0);
+
+	} else if (i == 1) {
+
+		if (lappl1 != NULL)
+			c7000_fill_name(ccp->lappl, lappl1);
+
+		if (lhost1 != NULL)
+			c7000_fill_name(ccp->lhost, lhost1);
+
+		if (uappl1 != NULL)
+			c7000_fill_name(ccp->uappl, uappl1);
+
+		if (uhost1 != NULL)
+			c7000_fill_name(ccp->uhost, uhost1);
+
+	} else if (i == 2) {
+
+		if (lappl2 != NULL)
+			c7000_fill_name(ccp->lappl, lappl2);
+
+		if (lhost2 != NULL)
+			c7000_fill_name(ccp->lhost, lhost2);
+
+		if (uappl2 != NULL)
+			c7000_fill_name(ccp->uappl, uappl2);
+
+		if (uhost2 != NULL)
+			c7000_fill_name(ccp->uhost, uhost2);
+
+	} else {
+
+		if (lappl3 != NULL)
+			c7000_fill_name(ccp->lappl, lappl3);
+
+		if (lhost3 != NULL)
+			c7000_fill_name(ccp->lhost, lhost3);
+
+		if (uappl3 != NULL)
+			c7000_fill_name(ccp->uappl, uappl3);
+
+		if (uhost3 != NULL)
+			c7000_fill_name(ccp->uhost, uhost3);
+
+	}
+
+	CPrintk(1, "c7000: c7000_init: lappl = %8.8s lhost = %8.8s uappl = %8.8s uhost = %8.8s for base unit 0x%x\n", ccp->lappl, ccp->lhost, ccp->uappl, ccp->uhost, ccp->base_addr);
+	ccp->version = 2;
+	ccp->linkid = 0;
+
+	/*
+		Initialize the fields in the embedded cunits
+		array.  This type of controller occupies a range
+		of three contiguous device numbers.
+	*/
+
+	for (i = 0; i < NUNITS; i++) {
+		unitaddr = dev->base_addr + i;
+
+		/*
+			Get the subchannel number.
+		*/
+
+		if ((irq = ccp->cunits[i].irq = get_irq_by_devno(unitaddr)) == -1) {
+			CPrintk(0, "c7000: c7000_init: can not get subchannel for unit 0x%x\n", unitaddr);
+			return(-ENODEV);
+		}
+
+		/*
+			Get control of the subchannel.
+		*/
+
+		if (request_irq(irq, c7000_intr, SA_INTERRUPT, dev->name, &ccp->cunits[i].devstat) != 0) {
+			CPrintk(0, "c7000: c7000_init: can not get control of subchannel 0x%x for unit 0x%x\n", irq, unitaddr);
+			return(-EBUSY);
+		}
+
+		CPrintk(1, "c7000: c7000_init: obtained control of subchannel 0x%x for unit 0x%x\n", irq, unitaddr);
+		ccp->cunits[i].devno = unitaddr;
+		ccp->cunits[i].IO_active = 0;
+		ccp->cunits[i].state = C7000_INIT;
+		ccp->cunits[i].cntlp = ccp;
+		CPrintk(1, "c7000: c7000_init: initialized unit 0x%x on subchannel 0x%x\n", unitaddr, irq);
+	}
+		
+	return(0);
+}
+
+/*
+	Probe for the Cisco 7000 unit base addresses.
+*/
+
+static void
+c7000_probe(void)
+{
+	s390_dev_info_t	d;
+	int		i;
+	int		j;
+	int		idx;
+
+	/*
+		Probe for up to MAX_C7000 devices.
+		Get the first irq into variable idx.
+	*/
+	
+	idx = get_irq_first();
+
+	for (j = 0; j < MAX_C7000; j++) {
+
+		if (idx < 0)
+			break;
+
+		/*
+			Continue scanning the irq's.  Variable idx
+			maintains the location from the prior scan.
+		*/
+
+		for (i = idx; i >= 0; i = get_irq_next(i)) {
+
+			/*
+				Ignore invalid irq's.
+			*/
+
+			if (get_dev_info_by_irq(i, &d) < 0)
+				continue;
+
+			/*
+				A Cisco 7000 is defined as a 3088 model
+				type 0x61.
+			*/
+
+			if (d.sid_data.cu_type == C7000_CU_TYPE &&
+			    d.sid_data.cu_model == C7000_CU_MODEL) {
+				CPrintk(0, "c7000_probe: unit probe found 0x%x\n", d.devno);
+				bases[j] = d.devno;
+
+				/*
+					Skip the write irq and setup idx
+					to probe for the next box.
+				*/
+
+				idx = get_irq_next(i + 1);
+				break;
+			}
+
+		}
+
+	}
+
+	return;
+}
+
+/*
+	Module loading.  Register each C7000 interface found via probing
+	or insmod command parameters.
+*/
+
+int
+init_module(void)
+{
+	int		result;
+	int		i;
+
+	for (i = 0 ; i < MAX_C7000; i++)
+		bases[i] = -1;
+
+	/*
+		Perform automatic detection provided it has not been disabled
+		by the noauto parameter. 
+	*/
+
+	if (noauto == 0)
+		c7000_probe();
+
+	/*
+		Populate bases array from the module basex parameters replacing
+		what probing found above.
+	*/
+
+	if (base0 != -1)
+		bases[0] = base0;
+
+	if (base1 != -1)
+		bases[1] = base1;
+
+	if (base2 != -1)
+		bases[2] = base2;
+
+	if (base3 != -1)
+		bases[3] = base3;
+
+	for (i = 0; i < MAX_C7000; i++) {
+
+		if (bases[i] == -1)
+			continue;
+		
+		/*
+			Initialize the device structure.
+		*/
+
+		memset(&c7000_devices[i], '\0', sizeof(STRUCT_NET_DEVICE));
+#ifdef NEWSTUFF
+		strcpy(c7000_devices[i].name, ifnames[i]);
+#else
+		c7000_devices[i].name = &ifnames[i][0];
+#endif
+		c7000_devices[i].base_addr = bases[i];
+		c7000_devices[i].init = c7000_init;
+
+		/*
+			Register the device.  This creates the interface
+			such as ci0.
+		*/
+
+		if ((result = register_netdev(&c7000_devices[i])) != 0)  {
+			CPrintk(0, "c7000: init_module: error %d registering base unit 0x%x\n",
+				result, bases[i]);
+			c7000_devices[i].base_addr = -1;
+		} else {
+			CPrintk(1, "c7000: init_module: registered base unit 0x%x on interface %s\n", bases[i], ifnames[i]);
+		}
+
+	}
+
+	CPrintk(0, "c7000: init_module: module loaded\n");
+	return(0);
+}
+
+/*
+	Module unloading.  Unregister the interface and free kernel
+	allocated memory.
+*/
+
+void
+cleanup_module(void)
+{
+	int				i;
+	int				j;
+	struct	c7000_controller	*ccp;
+
+	for (i = 0; i < MAX_C7000; i++) {
+
+		if (bases[i] == -1)
+			continue;
+
+		/*
+			If the device was registered, it must be unregistered
+			prior to unloading the module.
+		*/
+
+		if (c7000_devices[i].base_addr != -1) {
+
+			ccp = (struct c7000_controller *) c7000_devices[i].priv;
+
+			if (ccp != NULL) {
+				
+				for (j = 0; j < NUNITS ; j++) {
+					CPrintk(1, "c7000: clean_module: free subchannel 0x%x for unit 0x%x\n", ccp->cunits[j].irq, ccp->cunits[j].devno);
+					free_irq(ccp->cunits[j].irq, &ccp->cunits[j].devstat);
+				}
+
+				CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address 0x%x\n", (int)ccp);
+				kfree(ccp);
+			}
+
+			unregister_netdev(&c7000_devices[i]);
+		}
+
+		bases[i] = -1;
+	}
+
+	CPrintk(0, "c7000: clean_module: module unloaded\n");
+	return;
+}
diff -urN linux-2.4.21-bk3/drivers/sound/esssolo1.c linux-2.4.21-bk4/drivers/sound/esssolo1.c
--- linux-2.4.21-bk3/drivers/sound/esssolo1.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.21-bk4/drivers/sound/esssolo1.c	2003-07-08 02:59:47.000000000 -0700
@@ -2378,9 +2378,9 @@
 	return 0;
 
  err:
-	unregister_sound_dsp(s->dev_dmfm);
+	unregister_sound_special(s->dev_dmfm);
  err_dev4:
-	unregister_sound_dsp(s->dev_midi);
+	unregister_sound_midi(s->dev_midi);
  err_dev3:
 	unregister_sound_mixer(s->dev_mixer);
  err_dev2:
@@ -2391,13 +2391,13 @@
  err_irq:
 	if (s->gameport.io)
 		release_region(s->gameport.io, GAMEPORT_EXTENT);
-	release_region(s->iobase, IOBASE_EXTENT);
+	release_region(s->mpubase, MPUBASE_EXTENT);
  err_region4:
-	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- err_region3:
 	release_region(s->ddmabase, DDMABASE_EXTENT);
+ err_region3:
+	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
  err_region2:
-	release_region(s->mpubase, MPUBASE_EXTENT);
+	release_region(s->iobase, IOBASE_EXTENT);
  err_region1:
 	kfree(s);
 	return ret;
diff -urN linux-2.4.21-bk3/fs/Config.in linux-2.4.21-bk4/fs/Config.in
--- linux-2.4.21-bk3/fs/Config.in	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/fs/Config.in	2003-07-08 02:59:48.000000000 -0700
@@ -5,6 +5,8 @@
 comment 'File systems'
 
 bool 'Quota support' CONFIG_QUOTA
+dep_tristate '  VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
+
 tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
 
diff -urN linux-2.4.21-bk3/fs/Makefile linux-2.4.21-bk4/fs/Makefile
--- linux-2.4.21-bk3/fs/Makefile	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/fs/Makefile	2003-07-08 02:59:48.000000000 -0700
@@ -7,20 +7,17 @@
 
 O_TARGET := fs.o
 
-export-objs :=	filesystems.o open.o dcache.o buffer.o
+export-objs :=	filesystems.o open.o dcache.o buffer.o dquot.o
 mod-subdirs :=	nls
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
 		fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o xattr.o
+		filesystems.o namespace.o seq_file.o xattr.o quota.o
 
-ifeq ($(CONFIG_QUOTA),y)
-obj-y += dquot.o
-else
-obj-y += noquot.o
-endif
+obj-$(CONFIG_QUOTA)		+= dquot.o quota_v1.o
+obj-$(CONFIG_QFMT_V2)		+= quota_v2.o
 
 subdir-$(CONFIG_PROC_FS)	+= proc
 subdir-y			+= partitions
diff -urN linux-2.4.21-bk3/fs/bfs/dir.c linux-2.4.21-bk4/fs/bfs/dir.c
--- linux-2.4.21-bk3/fs/bfs/dir.c	2002-02-25 11:38:07.000000000 -0800
+++ linux-2.4.21-bk4/fs/bfs/dir.c	2003-07-08 02:59:48.000000000 -0700
@@ -256,7 +256,6 @@
 	struct buffer_head * bh;
 	struct bfs_dirent * de;
 	int block, sblock, eblock, off;
-	kdev_t dev;
 	int i;
 
 	dprintf("name=%s, namelen=%d\n", name, namelen);
@@ -266,7 +265,6 @@
 	if (namelen > BFS_NAMELEN)
 		return -ENAMETOOLONG;
 
-	dev = dir->i_dev;
 	sblock = dir->iu_sblock;
 	eblock = dir->iu_eblock;
 	for (block=sblock; block<=eblock; block++) {
@@ -308,11 +306,9 @@
 {
 	unsigned long block, offset;
 	struct buffer_head * bh;
-	struct bfs_sb_info * info;
 	struct bfs_dirent * de;
 
 	*res_dir = NULL;
-	info = &dir->i_sb->u.bfs_sb;
 	if (namelen > BFS_NAMELEN)
 		return NULL;
 	bh = NULL;
diff -urN linux-2.4.21-bk3/fs/binfmt_elf.c linux-2.4.21-bk4/fs/binfmt_elf.c
--- linux-2.4.21-bk3/fs/binfmt_elf.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/fs/binfmt_elf.c	2003-07-08 02:59:48.000000000 -0700
@@ -444,6 +444,7 @@
 	struct elfhdr interp_elf_ex;
   	struct exec interp_ex;
 	char passed_fileno[6];
+	struct files_struct *files, *ftmp;
 	
 	/* Get the exec-header */
 	elf_ex = *((struct elfhdr *) bprm->buf);
@@ -475,10 +476,17 @@
 	retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size);
 	if (retval < 0)
 		goto out_free_ph;
+		
+	files = current->files;		/* Refcounted so ok */
+	if(unshare_files() < 0)
+		goto out_free_ph;
 
+	/* exec will make our files private anyway, but for the a.out
+	   loader stuff we need to do it earlier */
+	   
 	retval = get_unused_fd();
 	if (retval < 0)
-		goto out_free_ph;
+		goto out_free_fh;
 	get_file(bprm->file);
 	fd_install(elf_exec_fileno = retval, bprm->file);
 
@@ -593,6 +601,9 @@
 	if (retval)
 		goto out_free_dentry;
 
+	/* Discard our unneeded old files struct */
+	put_files_struct(files);
+
 	/* OK, This is the point of no return */
 	current->mm->start_data = 0;
 	current->mm->end_data = 0;
@@ -711,7 +722,8 @@
 			printk(KERN_ERR "Unable to load interpreter\n");
 			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
-			return 0;
+			retval = -ENOEXEC; /* Nobody gets to see this, but.. */
+			goto out;
 		}
 	}
 
@@ -797,6 +809,10 @@
 		kfree(elf_interpreter);
 out_free_file:
 	sys_close(elf_exec_fileno);
+out_free_fh:
+	ftmp = current->files;
+	current->files = files;
+	put_files_struct(ftmp);
 out_free_ph:
 	kfree(elf_phdata);
 	goto out;
diff -urN linux-2.4.21-bk3/fs/binfmt_som.c linux-2.4.21-bk4/fs/binfmt_som.c
--- linux-2.4.21-bk3/fs/binfmt_som.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/fs/binfmt_som.c	2003-07-08 02:59:48.000000000 -0700
@@ -213,7 +213,7 @@
 			(char *) hpuxhdr, size);
 	if (retval < 0)
 		goto out_free;
-
+#error "Fix security hole before enabling me"
 	retval = get_unused_fd();
 	if (retval < 0)
 		goto out_free;
diff -urN linux-2.4.21-bk3/fs/buffer.c linux-2.4.21-bk4/fs/buffer.c
--- linux-2.4.21-bk3/fs/buffer.c	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/fs/buffer.c	2003-07-08 02:59:48.000000000 -0700
@@ -336,7 +336,7 @@
 
 	lock_kernel();
 	sync_inodes_sb(sb);
-	DQUOT_SYNC(dev);
+	DQUOT_SYNC_SB(sb);
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
@@ -360,7 +360,7 @@
 
 	lock_kernel();
 	sync_inodes(dev);
-	DQUOT_SYNC(dev);
+	DQUOT_SYNC_DEV(dev);
 	sync_supers(dev, 1);
 	unlock_kernel();
 
@@ -2827,7 +2827,7 @@
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
 	} while (hash_table == NULL && --order > 0);
-	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+	printk(KERN_INFO "Buffer cache hash table entries: %d (order: %d, %ld bytes)\n",
 	       nr_hash, order, (PAGE_SIZE << order));
 
 	if (!hash_table)
diff -urN linux-2.4.21-bk3/fs/dcache.c linux-2.4.21-bk4/fs/dcache.c
--- linux-2.4.21-bk3/fs/dcache.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/dcache.c	2003-07-08 02:59:48.000000000 -0700
@@ -702,13 +702,25 @@
  
 struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
 {
+	struct dentry *dentry = NULL;
+
+	spin_lock(&dcache_lock);
+	dentry = __d_lookup(parent,name);
+	if (dentry)
+		__dget_locked(dentry);
+	spin_unlock(&dcache_lock);
+	return dentry;
+}
+
+struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)  
+{
+
 	unsigned int len = name->len;
 	unsigned int hash = name->hash;
 	const unsigned char *str = name->name;
 	struct list_head *head = d_hash(parent,hash);
 	struct list_head *tmp;
 
-	spin_lock(&dcache_lock);
 	tmp = head->next;
 	for (;;) {
 		struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
@@ -728,12 +740,9 @@
 			if (memcmp(dentry->d_name.name, str, len))
 				continue;
 		}
-		__dget_locked(dentry);
 		dentry->d_vfs_flags |= DCACHE_REFERENCED;
-		spin_unlock(&dcache_lock);
 		return dentry;
 	}
-	spin_unlock(&dcache_lock);
 	return NULL;
 }
 
diff -urN linux-2.4.21-bk3/fs/dquot.c linux-2.4.21-bk4/fs/dquot.c
--- linux-2.4.21-bk3/fs/dquot.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/fs/dquot.c	2003-07-08 02:59:48.000000000 -0700
@@ -35,7 +35,7 @@
  *		Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99
  *
  *		Used struct list_head instead of own list struct
- *		Invalidation of dquots with dq_count > 0 no longer possible
+ *		Invalidation of referenced dquots is no longer possible
  *		Improved free_dquots list management
  *		Quota and i_blocks are now updated in one place to avoid races
  *		Warnings are now delayed so we won't block in critical section
@@ -45,6 +45,10 @@
  *		Added dynamic quota structure allocation
  *		Jan Kara <jack@suse.cz> 12/2000
  *
+ *		Rewritten quota interface. Implemented new quota format and
+ *		formats registering.
+ *		Jan Kara, <jack@suse.cz>, 2001,2002
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -59,20 +63,53 @@
 #include <linux/tty.h>
 #include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 
-#define __DQUOT_VERSION__	"dquot_6.4.0"
+static char *quotatypes[] = INITQFNAMES;
+static struct quota_format_type *quota_formats;	/* List of registered formats */
 
-int nr_dquots, nr_free_dquots;
+int register_quota_format(struct quota_format_type *fmt)
+{
+	lock_kernel();
+	fmt->qf_next = quota_formats;
+	quota_formats = fmt;
+	unlock_kernel();
+	return 0;
+}
 
-static char *quotatypes[] = INITQFNAMES;
+void unregister_quota_format(struct quota_format_type *fmt)
+{
+	struct quota_format_type **actqf;
 
-static inline struct quota_mount_options *sb_dqopt(struct super_block *sb)
+	lock_kernel();
+	for (actqf = &quota_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next);
+	if (*actqf)
+		*actqf = (*actqf)->qf_next;
+	unlock_kernel();
+}
+
+static struct quota_format_type *find_quota_format(int id)
 {
-	return &sb->s_dquot;
+	struct quota_format_type *actqf;
+
+	lock_kernel();
+	for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next);
+	if (actqf && !try_inc_mod_count(actqf->qf_owner))
+		actqf = NULL;
+	unlock_kernel();
+	return actqf;
+}
+
+static void put_quota_format(struct quota_format_type *fmt)
+{
+	if (fmt->qf_owner)
+		__MOD_DEC_USE_COUNT(fmt->qf_owner);
 }
 
 /*
@@ -85,11 +122,11 @@
  * list is used for the sync and invalidate operations, which must look
  * at every dquot.
  *
- * Unused dquots (dq_count == 0) are added to the free_dquots list when
- * freed, and this list is searched whenever we need an available dquot.
- * Dquots are removed from the list as soon as they are used again, and
- * nr_free_dquots gives the number of dquots on the list. When dquot is
- * invalidated it's completely released from memory.
+ * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
+ * and this list is searched whenever we need an available dquot.  Dquots are
+ * removed from the list as soon as they are used again, and
+ * dqstats.free_dquots gives the number of dquots on the list. When
+ * dquot is invalidated it's completely released from memory.
  *
  * Dquots with a specific identity (device, type and id) are placed on
  * one of the dquot_hash[] hash chains. The provides an efficient search
@@ -115,35 +152,39 @@
 static LIST_HEAD(free_dquots);
 static struct list_head dquot_hash[NR_DQHASH];
 
-static struct dqstats dqstats;
+struct dqstats dqstats;
 
 static void dqput(struct dquot *);
 static struct dquot *dqduplicate(struct dquot *);
 
-static inline char is_enabled(struct quota_mount_options *dqopt, short type)
+static inline void get_dquot_ref(struct dquot *dquot)
 {
-	switch (type) {
-		case USRQUOTA:
-			return((dqopt->flags & DQUOT_USR_ENABLED) != 0);
-		case GRPQUOTA:
-			return((dqopt->flags & DQUOT_GRP_ENABLED) != 0);
-	}
-	return(0);
+	dquot->dq_count++;
+}
+
+static inline void put_dquot_ref(struct dquot *dquot)
+{
+	dquot->dq_count--;
+}
+
+static inline void get_dquot_dup_ref(struct dquot *dquot)
+{
+	dquot->dq_dup_ref++;
 }
 
-static inline char sb_has_quota_enabled(struct super_block *sb, short type)
+static inline void put_dquot_dup_ref(struct dquot *dquot)
 {
-	return is_enabled(sb_dqopt(sb), type);
+	dquot->dq_dup_ref--;
 }
 
-static inline int const hashfn(kdev_t dev, unsigned int id, short type)
+static inline int const hashfn(struct super_block *sb, unsigned int id, int type)
 {
-	return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
+	return((HASHDEV(sb->s_dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
 }
 
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
-	struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+	struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
 	list_add(&dquot->dq_hash, head);
 }
 
@@ -153,14 +194,14 @@
 	INIT_LIST_HEAD(&dquot->dq_hash);
 }
 
-static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type)
+static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
 
 	for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) {
 		dquot = list_entry(head, struct dquot, dq_hash);
-		if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type)
+		if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type)
 			return dquot;
 	}
 	return NODQUOT;
@@ -170,14 +211,14 @@
 static inline void put_dquot_head(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, &free_dquots);
-	nr_free_dquots++;
+	dqstats.free_dquots++;
 }
 
 /* Add a dquot to the tail of the free list */
 static inline void put_dquot_last(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, free_dquots.prev);
-	nr_free_dquots++;
+	dqstats.free_dquots++;
 }
 
 /* Move dquot to the head of free list (it must be already on it) */
@@ -193,7 +234,7 @@
 		return;
 	list_del(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_free);
-	nr_free_dquots--;
+	dqstats.free_dquots--;
 }
 
 static inline void put_inuse(struct dquot *dquot)
@@ -201,12 +242,12 @@
 	/* We add to the back of inuse list so we don't have to restart
 	 * when traversing this list and we block */
 	list_add(&dquot->dq_inuse, inuse_list.prev);
-	nr_dquots++;
+	dqstats.allocated_dquots++;
 }
 
 static inline void remove_inuse(struct dquot *dquot)
 {
-	nr_dquots--;
+	dqstats.allocated_dquots--;
 	list_del(&dquot->dq_inuse);
 }
 
@@ -243,6 +284,7 @@
 	wake_up(&dquot->dq_wait_lock);
 }
 
+/* Wait for dquot to be unused */
 static void __wait_dquot_unused(struct dquot *dquot)
 {
 	DECLARE_WAITQUEUE(wait, current);
@@ -258,85 +300,56 @@
 	current->state = TASK_RUNNING;
 }
 
-/*
- *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
- */
-static void write_dquot(struct dquot *dquot)
+/* Wait for all duplicated dquot references to be dropped */
+static void __wait_dup_drop(struct dquot *dquot)
 {
-	short type = dquot->dq_type;
-	struct file *filp;
-	mm_segment_t fs;
-	loff_t offset;
-	ssize_t ret;
-	struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem;
-	struct dqblk dqbuf;
-
-	down(sem);
-	filp = dquot->dq_sb->s_dquot.files[type];
-	offset = dqoff(dquot->dq_id);
-	fs = get_fs();
-	set_fs(KERNEL_DS);
+	DECLARE_WAITQUEUE(wait, current);
 
-	/*
-	 * Note: clear the DQ_MOD flag unconditionally,
-	 * so we don't loop forever on failure.
-	 */
-	memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk));
-	dquot->dq_flags &= ~DQ_MOD;
-	ret = 0;
-	if (filp)
-		ret = filp->f_op->write(filp, (char *)&dqbuf, 
-					sizeof(struct dqblk), &offset);
-	if (ret != sizeof(struct dqblk))
-		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
-			kdevname(dquot->dq_dev));
-
-	set_fs(fs);
-	up(sem);
-	dqstats.writes++;
-}
-
-static void read_dquot(struct dquot *dquot)
-{
-	short type = dquot->dq_type;
-	struct file *filp;
-	mm_segment_t fs;
-	loff_t offset;
+	add_wait_queue(&dquot->dq_wait_free, &wait);
+repeat:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	if (dquot->dq_dup_ref) {
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&dquot->dq_wait_free, &wait);
+	current->state = TASK_RUNNING;
+}
 
-	filp = dquot->dq_sb->s_dquot.files[type];
-	if (filp == (struct file *)NULL)
-		return;
+static int read_dqblk(struct dquot *dquot)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
 	lock_dquot(dquot);
-	if (!dquot->dq_sb)	/* Invalidated quota? */
-		goto out_lock;
-	/* Now we are sure filp is valid - the dquot isn't invalidated */
-	down(&dquot->dq_sb->s_dquot.dqio_sem);
-	offset = dqoff(dquot->dq_id);
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
-	up(&dquot->dq_sb->s_dquot.dqio_sem);
-	set_fs(fs);
-
-	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
-	    dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)
-		dquot->dq_flags |= DQ_FAKE;
-	dqstats.reads++;
-out_lock:
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+	up(&dqopt->dqio_sem);
 	unlock_dquot(dquot);
+	return ret;
+}
+
+static int commit_dqblk(struct dquot *dquot)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+	up(&dqopt->dqio_sem);
+	return ret;
 }
 
 /* Invalidate all dquots on the list, wait for all users. Note that this function is called
  * after quota is disabled so no new quota might be created. As we only insert to the end of
  * inuse list, we don't have to restart searching... */
-static void invalidate_dquots(struct super_block *sb, short type)
+static void invalidate_dquots(struct super_block *sb, int type)
 {
 	struct dquot *dquot;
 	struct list_head *head;
 
 restart:
-	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
 		if (dquot->dq_sb != sb)
 			continue;
@@ -359,37 +372,107 @@
 	}
 }
 
-int sync_dquots(kdev_t dev, short type)
+static int vfs_quota_sync(struct super_block *sb, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
+	struct quota_info *dqopt = sb_dqopt(sb);
+	int cnt;
 
-	lock_kernel();
 restart:
-	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
-		if (dev && dquot->dq_dev != dev)
+		if (sb && dquot->dq_sb != sb)
 			continue;
                 if (type != -1 && dquot->dq_type != type)
 			continue;
 		if (!dquot->dq_sb)	/* Invalidated? */
 			continue;
-		if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED)))
+		if (!dquot_dirty(dquot) && !(dquot->dq_flags & DQ_LOCKED))
 			continue;
-		/* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */
-		dquot->dq_count++;
+		/* Get reference to quota so it won't be invalidated. get_dquot_ref()
+		 * is enough since if dquot is locked/modified it can't be
+		 * on the free list */
+		get_dquot_ref(dquot);
 		if (dquot->dq_flags & DQ_LOCKED)
 			wait_on_dquot(dquot);
-		if (dquot->dq_flags & DQ_MOD)
-			write_dquot(dquot);
+		if (dquot_dirty(dquot))
+			commit_dqblk(dquot);
 		dqput(dquot);
 		goto restart;
 	}
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt))
+			dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt]))
+			dqopt->ops[cnt]->write_file_info(sb, cnt);
 	dqstats.syncs++;
-	unlock_kernel();
+
 	return 0;
 }
 
+static struct super_block *get_super_to_sync(int type)
+{
+	struct list_head *head;
+	int cnt, dirty;
+
+restart:
+	spin_lock(&sb_lock);
+	list_for_each(head, &super_blocks) {
+		struct super_block *sb = list_entry(head, struct super_block, s_list);
+
+		for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++)
+			if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt)
+			    && sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY)
+				dirty = 1;
+		if (!dirty)
+			continue;
+		sb->s_count++;
+		spin_unlock(&sb_lock);
+		down_read(&sb->s_umount);
+		if (!sb->s_root) {
+			drop_super(sb);
+			goto restart;
+		}
+		return sb;
+	}
+	spin_unlock(&sb_lock);
+	return NULL;
+}
+
+void sync_dquots_dev(kdev_t dev, int type)
+{
+	struct super_block *sb;
+
+	if (dev) {
+		if ((sb = get_super(dev))) {
+			lock_kernel();
+			if (sb->s_qcop->quota_sync)
+				sb->s_qcop->quota_sync(sb, type);
+			unlock_kernel();
+			drop_super(sb);
+		}
+	}
+	else {
+		while ((sb = get_super_to_sync(type))) {
+			lock_kernel();
+			if (sb->s_qcop->quota_sync)
+				sb->s_qcop->quota_sync(sb, type);
+			unlock_kernel();
+			drop_super(sb);
+		}
+	}
+}
+
+void sync_dquots_sb(struct super_block *sb, int type)
+{
+	lock_kernel();
+	if (sb->s_qcop->quota_sync)
+		sb->s_qcop->quota_sync(sb, type);
+	unlock_kernel();
+}
+
 /* Free unused dquots from cache */
 static void prune_dqcache(int count)
 {
@@ -408,19 +491,38 @@
 	}
 }
 
+/*
+ * This is called from kswapd when we think we need some
+ * more memory, but aren't really sure how much. So we
+ * carefully try to free a _bit_ of our dqcache, but not
+ * too much.
+ *
+ * Priority:
+ *   1 - very urgent: shrink everything
+ *   ...
+ *   6 - base-level: try to shrink a bit.
+ */
+
 int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
 {
+	int count = 0;
+
 	lock_kernel();
-	prune_dqcache(nr_free_dquots / (priority + 1));
+	count = dqstats.free_dquots / priority;
+	prune_dqcache(count);
 	unlock_kernel();
 	return kmem_cache_shrink(dquot_cachep);
 }
 
-/* NOTE: If you change this function please check whether dqput_blocks() works right... */
+/*
+ * Put reference to dquot
+ * NOTE: If you change this function please check whether dqput_blocks() works right...
+ */
 static void dqput(struct dquot *dquot)
 {
 	if (!dquot)
 		return;
+#ifdef __DQUOT_PARANOIA
 	if (!dquot->dq_count) {
 		printk("VFS: dqput: trying to free free dquot\n");
 		printk("VFS: device %s, dquot of %s %d\n",
@@ -428,33 +530,38 @@
 			dquot->dq_id);
 		return;
 	}
+#endif
 
 	dqstats.drops++;
 we_slept:
+	if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) {	/* Last unduplicated reference? */
+		__wait_dup_drop(dquot);
+		goto we_slept;
+	}
 	if (dquot->dq_count > 1) {
 		/* We have more than one user... We can simply decrement use count */
-		dquot->dq_count--;
+		put_dquot_ref(dquot);
 		return;
 	}
-	if (dquot->dq_flags & DQ_MOD) {
-		write_dquot(dquot);
+	if (dquot_dirty(dquot)) {
+		commit_dqblk(dquot);
 		goto we_slept;
 	}
 
 	/* sanity check */
 	if (!list_empty(&dquot->dq_free)) {
 		printk(KERN_ERR "dqput: dquot already on free list??\n");
-		dquot->dq_count--;	/* J.K. Just decrementing use count seems safer... */
+		put_dquot_ref(dquot);
 		return;
 	}
-	dquot->dq_count--;
+	put_dquot_ref(dquot);
 	/* If dquot is going to be invalidated invalidate_dquots() is going to free it so */
 	if (!(dquot->dq_flags & DQ_INVAL))
 		put_dquot_last(dquot);	/* Place at end of LRU free queue */
 	wake_up(&dquot->dq_wait_free);
 }
 
-static struct dquot *get_empty_dquot(void)
+static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 {
 	struct dquot *dquot;
 
@@ -468,6 +575,9 @@
 	INIT_LIST_HEAD(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_inuse);
 	INIT_LIST_HEAD(&dquot->dq_hash);
+	dquot->dq_sb = sb;
+	dquot->dq_dev = sb->s_dev;
+	dquot->dq_type = type;
 	dquot->dq_count = 1;
 	/* all dquots go on the inuse_list */
 	put_inuse(dquot);
@@ -475,11 +585,11 @@
 	return dquot;
 }
 
-static struct dquot *dqget(struct super_block *sb, unsigned int id, short type)
+static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
 {
-	unsigned int hashent = hashfn(sb->s_dev, id, type);
+	unsigned int hashent = hashfn(sb, id, type);
 	struct dquot *dquot, *empty = NODQUOT;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
+	struct quota_info *dqopt = sb_dqopt(sb);
 
 we_slept:
         if (!is_enabled(dqopt, type)) {
@@ -488,23 +598,21 @@
                 return NODQUOT;
 	}
 
-	if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) {
+	if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) {
 		if (empty == NODQUOT) {
-			if ((empty = get_empty_dquot()) == NODQUOT)
+			if ((empty = get_empty_dquot(sb, type)) == NODQUOT)
 				schedule();	/* Try to wait for a moment... */
 			goto we_slept;
 		}
 		dquot = empty;
-        	dquot->dq_id = id;
-        	dquot->dq_type = type;
-        	dquot->dq_dev = sb->s_dev;
-        	dquot->dq_sb = sb;
+		dquot->dq_id = id;
 		/* hash it first so it can be found */
 		insert_dquot_hash(dquot);
-        	read_dquot(dquot);
+		read_dqblk(dquot);
 	} else {
-		if (!dquot->dq_count++)
+		if (!dquot->dq_count)
 			remove_free_dquot(dquot);
+		get_dquot_ref(dquot);
 		dqstats.cache_hits++;
 		wait_on_dquot(dquot);
 		if (empty)
@@ -516,30 +624,47 @@
 		dqput(dquot);
 		return NODQUOT;
 	}
-	dquot->dq_referenced++;
+	++dquot->dq_referenced;
 	dqstats.lookups++;
 
 	return dquot;
 }
 
+/* Duplicate reference to dquot got from inode */
 static struct dquot *dqduplicate(struct dquot *dquot)
 {
 	if (dquot == NODQUOT)
 		return NODQUOT;
-	dquot->dq_count++;
+	get_dquot_ref(dquot);
 	if (!dquot->dq_sb) {
 		printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n");
-		dquot->dq_count--;
+		put_dquot_ref(dquot);
 		return NODQUOT;
 	}
 	if (dquot->dq_flags & DQ_LOCKED)
 		printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n");
+	get_dquot_dup_ref(dquot);
 	dquot->dq_referenced++;
 	dqstats.lookups++;
+
 	return dquot;
 }
 
-static int dqinit_needed(struct inode *inode, short type)
+/* Put duplicated reference */
+static void dqputduplicate(struct dquot *dquot)
+{
+	if (!dquot->dq_dup_ref) {
+		printk(KERN_ERR "VFS: dqputduplicate(): Duplicated dquot put without duplicate reference.\n");
+		return;
+	}
+	put_dquot_dup_ref(dquot);
+	if (!dquot->dq_dup_ref)
+		wake_up(&dquot->dq_wait_free);
+	put_dquot_ref(dquot);
+	dqstats.drops++;
+}
+
+static int dqinit_needed(struct inode *inode, int type)
 {
 	int cnt;
 
@@ -553,16 +678,13 @@
 	return 0;
 }
 
-static void add_dquot_ref(struct super_block *sb, short type)
+static void add_dquot_ref(struct super_block *sb, int type)
 {
 	struct list_head *p;
 
-	if (!sb->dq_op)
-		return;	/* nothing to do */
-
 restart:
 	file_list_lock();
-	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+	list_for_each(p, &sb->s_files) {
 		struct file *filp = list_entry(p, struct file, f_list);
 		struct inode *inode = filp->f_dentry->d_inode;
 		if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
@@ -582,13 +704,15 @@
 /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
 static inline int dqput_blocks(struct dquot *dquot)
 {
-	if (dquot->dq_count == 1)
+	if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1)
+		return 1;
+	if (dquot->dq_count <= 1 && dquot->dq_flags & DQ_MOD)
 		return 1;
 	return 0;
 }
 
 /* Remove references to dquots from inode - add dquot to list for freeing if needed */
-int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head)
+int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head)
 {
 	struct dquot *dquot = inode->i_dquot[type];
 	int cnt;
@@ -635,38 +759,38 @@
 
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
-	dquot->dq_curinodes += number;
-	dquot->dq_flags |= DQ_MOD;
+	dquot->dq_dqb.dqb_curinodes += number;
+	mark_dquot_dirty(dquot);
 }
 
-static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number)
+static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
 {
-	dquot->dq_curblocks += number;
-	dquot->dq_flags |= DQ_MOD;
+	dquot->dq_dqb.dqb_curspace += number;
+	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
 {
-	if (dquot->dq_curinodes > number)
-		dquot->dq_curinodes -= number;
+	if (dquot->dq_dqb.dqb_curinodes > number)
+		dquot->dq_dqb.dqb_curinodes -= number;
 	else
-		dquot->dq_curinodes = 0;
-	if (dquot->dq_curinodes < dquot->dq_isoftlimit)
-		dquot->dq_itime = (time_t) 0;
+		dquot->dq_dqb.dqb_curinodes = 0;
+	if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
+		dquot->dq_dqb.dqb_itime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_INODES;
-	dquot->dq_flags |= DQ_MOD;
+	mark_dquot_dirty(dquot);
 }
 
-static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number)
+static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
 {
-	if (dquot->dq_curblocks > number)
-		dquot->dq_curblocks -= number;
+	if (dquot->dq_dqb.dqb_curspace > number)
+		dquot->dq_dqb.dqb_curspace -= number;
 	else
-		dquot->dq_curblocks = 0;
-	if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
-		dquot->dq_btime = (time_t) 0;
+		dquot->dq_dqb.dqb_curspace = 0;
+	if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
+		dquot->dq_dqb.dqb_btime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_BLKS;
-	dquot->dq_flags |= DQ_MOD;
+	mark_dquot_dirty(dquot);
 }
 
 static inline int need_print_warning(struct dquot *dquot, int flag)
@@ -707,22 +831,22 @@
 	tty_write_message(current->tty, quotatypes[dquot->dq_type]);
 	switch (warntype) {
 		case IHARDWARN:
-			msg = " file limit reached.\n";
+			msg = " file limit reached.\r\n";
 			break;
 		case ISOFTLONGWARN:
-			msg = " file quota exceeded too long.\n";
+			msg = " file quota exceeded too long.\r\n";
 			break;
 		case ISOFTWARN:
-			msg = " file quota exceeded.\n";
+			msg = " file quota exceeded.\r\n";
 			break;
 		case BHARDWARN:
-			msg = " block limit reached.\n";
+			msg = " block limit reached.\r\n";
 			break;
 		case BSOFTLONGWARN:
-			msg = " block quota exceeded too long.\n";
+			msg = " block quota exceeded too long.\r\n";
 			break;
 		case BSOFTWARN:
-			msg = " block quota exceeded.\n";
+			msg = " block quota exceeded.\r\n";
 			break;
 	}
 	tty_write_message(current->tty, msg);
@@ -739,7 +863,10 @@
 
 static inline char ignore_hardlimit(struct dquot *dquot)
 {
-	return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type];
+	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+	return capable(CAP_SYS_RESOURCE) &&
+	    (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH));
 }
 
 static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
@@ -748,60 +875,60 @@
 	if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
 		return QUOTA_OK;
 
-	if (dquot->dq_ihardlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
+	if (dquot->dq_dqb.dqb_ihardlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
 		*warntype = IHARDWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_isoftlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-	    dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
+	if (dquot->dq_dqb.dqb_isoftlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+	    dquot->dq_dqb.dqb_itime && CURRENT_TIME >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
 		*warntype = ISOFTLONGWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_isoftlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-	    dquot->dq_itime == 0) {
+	if (dquot->dq_dqb.dqb_isoftlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+	    dquot->dq_dqb.dqb_itime == 0) {
 		*warntype = ISOFTWARN;
-		dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type];
+		dquot->dq_dqb.dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
 	}
 
 	return QUOTA_OK;
 }
 
-static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype)
+static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
 {
 	*warntype = 0;
-	if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
+	if (space <= 0 || dquot->dq_flags & DQ_FAKE)
 		return QUOTA_OK;
 
-	if (dquot->dq_bhardlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit &&
+	if (dquot->dq_dqb.dqb_bhardlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
 			*warntype = BHARDWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_bsoftlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
-	    dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
+	if (dquot->dq_dqb.dqb_bsoftlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+	    dquot->dq_dqb.dqb_btime && CURRENT_TIME >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
 			*warntype = BSOFTLONGWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_bsoftlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
-	    dquot->dq_btime == 0) {
+	if (dquot->dq_dqb.dqb_bsoftlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+	    dquot->dq_dqb.dqb_btime == 0) {
 		if (!prealloc) {
 			*warntype = BSOFTWARN;
-			dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type];
+			dquot->dq_dqb.dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
 		}
 		else
 			/*
@@ -815,148 +942,15 @@
 }
 
 /*
- * Initialize a dquot-struct with new quota info. This is used by the
- * system call interface functions.
- */ 
-static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk)
-{
-	struct dquot *dquot;
-	int error = -EFAULT;
-	struct dqblk dq_dqblk;
-
-	if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk)))
-		return error;
-
-	if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
-		/* We can't block while changing quota structure... */
-		if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) {
-			dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
-			dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
-			dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
-			dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
-		}
-
-		if ((flags & SET_QUOTA) || (flags & SET_USE)) {
-			if (dquot->dq_isoftlimit &&
-			    dquot->dq_curinodes < dquot->dq_isoftlimit &&
-			    dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
-				dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type];
-			dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
-			if (dquot->dq_curinodes < dquot->dq_isoftlimit)
-				dquot->dq_flags &= ~DQ_INODES;
-			if (dquot->dq_bsoftlimit &&
-			    dquot->dq_curblocks < dquot->dq_bsoftlimit &&
-			    dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit)
-				dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type];
-			dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
-			if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
-				dquot->dq_flags &= ~DQ_BLKS;
-		}
-
-		if (id == 0) {
-			dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime;
-			dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime;
-		}
-
-		if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
-		    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
-			dquot->dq_flags |= DQ_FAKE;
-		else
-			dquot->dq_flags &= ~DQ_FAKE;
-
-		dquot->dq_flags |= DQ_MOD;
-		dqput(dquot);
-	}
-	return 0;
-}
-
-static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk)
-{
-	struct dquot *dquot;
-	struct dqblk data;
-	int error = -ESRCH;
-
-	if (!sb || !sb_has_quota_enabled(sb, type))
-		goto out;
-	dquot = dqget(sb, id, type);
-	if (dquot == NODQUOT)
-		goto out;
-
-	memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));        /* We copy data to preserve them from changing */
-	dqput(dquot);
-	error = -EFAULT;
-	if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk)))
-		error = 0;
-out:
-	return error;
-}
-
-static int get_stats(caddr_t addr)
-{
-	int error = -EFAULT;
-	struct dqstats stats;
-
-	dqstats.allocated_dquots = nr_dquots;
-	dqstats.free_dquots = nr_free_dquots;
-
-	/* make a copy, in case we page-fault in user space */
-	memcpy(&stats, &dqstats, sizeof(struct dqstats));
-	if (!copy_to_user(addr, &stats, sizeof(struct dqstats)))
-		error = 0;
-	return error;
-}
-
-static int quota_root_squash(struct super_block *sb, short type, int *addr)
-{
-	int new_value, error;
-
-	if (!sb)
-		return(-ENODEV);
-
-	error = -EFAULT;
-	if (!copy_from_user(&new_value, addr, sizeof(int))) {
-		sb_dqopt(sb)->rsquash[type] = new_value;
-		error = 0;
-	}
-	return error;
-}
-
-#if 0	/* We are not going to support filesystems without i_blocks... */
-/*
- * This is a simple algorithm that calculates the size of a file in blocks.
- * This is only used on filesystems that do not have an i_blocks count.
- */
-static u_long isize_to_blocks(loff_t isize, size_t blksize_bits)
-{
-	u_long blocks;
-	u_long indirect;
-
-	if (!blksize_bits)
-		blksize_bits = BLOCK_SIZE_BITS;
-	blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0);
-	if (blocks > 10) {
-		indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
-		if (blocks > (10 + 256)) {
-			indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
-			if (blocks > (10 + 256 + (256 << 8)))
-				indirect++; /* triple indirect blocks */
-		}
-		blocks += indirect;
-	}
-	return blocks;
-}
-#endif
-
-/*
  * Externally referenced functions through dquot_operations in inode.
  *
  * Note: this is a blocking operation.
  */
-void dquot_initialize(struct inode *inode, short type)
+void dquot_initialize(struct inode *inode, int type)
 {
 	struct dquot *dquot[MAXQUOTAS];
 	unsigned int id = 0;
-	short cnt;
+	int cnt;
 
 	if (IS_NOQUOTA(inode))
 		return;
@@ -1002,7 +996,7 @@
 void dquot_drop(struct inode *inode)
 {
 	struct dquot *dquot;
-	short cnt;
+	int cnt;
 
 	inode->i_flags &= ~S_QUOTA;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1017,7 +1011,7 @@
 /*
  * This operation can block, but only after everything is updated
  */
-int dquot_alloc_block(struct inode *inode, unsigned long number, char warn)
+int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
 {
 	int cnt, ret = NO_QUOTA;
 	struct dquot *dquot[MAXQUOTAS];
@@ -1038,16 +1032,16 @@
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (dquot[cnt] == NODQUOT)
 			continue;
-		dquot_incr_blocks(dquot[cnt], number);
+		dquot_incr_space(dquot[cnt], number);
 	}
-	inode->i_blocks += number << (BLOCK_SIZE_BITS - 9);
+	inode_add_bytes(inode, number);
 	/* NOBLOCK End */
 	ret = QUOTA_OK;
 warn_put_all:
 	flush_warnings(dquot, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (dquot[cnt] != NODQUOT)
-			dqput(dquot[cnt]);
+			dqputduplicate(dquot[cnt]);
 	return ret;
 }
 
@@ -1084,16 +1078,16 @@
 	flush_warnings(dquot, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (dquot[cnt] != NODQUOT)
-			dqput(dquot[cnt]);
+			dqputduplicate(dquot[cnt]);
 	return ret;
 }
 
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_block(struct inode *inode, unsigned long number)
+void dquot_free_space(struct inode *inode, qsize_t number)
 {
-	unsigned short cnt;
+	unsigned int cnt;
 	struct dquot *dquot;
 
 	/* NOBLOCK Start */
@@ -1101,10 +1095,10 @@
 		dquot = dqduplicate(inode->i_dquot[cnt]);
 		if (dquot == NODQUOT)
 			continue;
-		dquot_decr_blocks(dquot, number);
-		dqput(dquot);
+		dquot_decr_space(dquot, number);
+		dqputduplicate(dquot);
 	}
-	inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9);
+	inode_sub_bytes(inode, number);
 	/* NOBLOCK End */
 }
 
@@ -1113,7 +1107,7 @@
  */
 void dquot_free_inode(const struct inode *inode, unsigned long number)
 {
-	unsigned short cnt;
+	unsigned int cnt;
 	struct dquot *dquot;
 
 	/* NOBLOCK Start */
@@ -1122,7 +1116,7 @@
 		if (dquot == NODQUOT)
 			continue;
 		dquot_decr_inodes(dquot, number);
-		dqput(dquot);
+		dqputduplicate(dquot);
 	}
 	/* NOBLOCK End */
 }
@@ -1134,7 +1128,7 @@
  */
 int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
-	unsigned long blocks;
+	qsize_t space;
 	struct dquot *transfer_from[MAXQUOTAS];
 	struct dquot *transfer_to[MAXQUOTAS];
 	int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid,
@@ -1164,7 +1158,7 @@
 		}
 	}
 	/* NOBLOCK START: From now on we shouldn't block */
-	blocks = (inode->i_blocks >> 1);
+	space = inode_get_bytes(inode);
 	/* Build the transfer_from list and check the limits */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		/* The second test can fail when quotaoff is in progress... */
@@ -1174,7 +1168,7 @@
 		if (transfer_from[cnt] == NODQUOT)	/* Can happen on quotafiles (quota isn't initialized on them)... */
 			continue;
 		if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA ||
-		    check_bdq(transfer_to[cnt], blocks, 0, warntype+cnt) == NO_QUOTA)
+		    check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA)
 			goto warn_put_all;
 	}
 
@@ -1189,10 +1183,10 @@
 			continue;
 
 		dquot_decr_inodes(transfer_from[cnt], 1);
-		dquot_decr_blocks(transfer_from[cnt], blocks);
+		dquot_decr_space(transfer_from[cnt], space);
 
 		dquot_incr_inodes(transfer_to[cnt], 1);
-		dquot_incr_blocks(transfer_to[cnt], blocks);
+		dquot_incr_space(transfer_to[cnt], space);
 
 		if (inode->i_dquot[cnt] == NODQUOT)
 			BUG();
@@ -1208,39 +1202,29 @@
 warn_put_all:
 	flush_warnings(transfer_to, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		/* First we must put duplicate - otherwise we might deadlock */
 		if (transfer_to[cnt] != NODQUOT)
-			dqput(transfer_to[cnt]);
+			dqputduplicate(transfer_to[cnt]);
 		if (transfer_from[cnt] != NODQUOT)
 			dqput(transfer_from[cnt]);
 	}
 	return ret;
 }
 
-static int __init dquot_init(void)
-{
-	int i;
-
-	for (i = 0; i < NR_DQHASH; i++)
-		INIT_LIST_HEAD(dquot_hash + i);
-	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
-	return 0;
-}
-__initcall(dquot_init);
-
 /*
  * Definitions of diskquota operations.
  */
 struct dquot_operations dquot_operations = {
-	dquot_initialize,		/* mandatory */
-	dquot_drop,			/* mandatory */
-	dquot_alloc_block,
-	dquot_alloc_inode,
-	dquot_free_block,
-	dquot_free_inode,
-	dquot_transfer
+	initialize:	dquot_initialize,		/* mandatory */
+	drop:		dquot_drop,			/* mandatory */
+	alloc_space:	dquot_alloc_space,
+	alloc_inode:	dquot_alloc_inode,
+	free_space:	dquot_free_space,
+	free_inode:	dquot_free_inode,
+	transfer:	dquot_transfer
 };
 
-static inline void set_enable_flags(struct quota_mount_options *dqopt, short type)
+static inline void set_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
 		case USRQUOTA:
@@ -1252,7 +1236,7 @@
 	}
 }
 
-static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type)
+static inline void reset_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
 		case USRQUOTA:
@@ -1265,16 +1249,15 @@
 }
 
 /* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(struct super_block *, short);
+extern void remove_dquot_ref(struct super_block *, int);
 
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int quota_off(struct super_block *sb, short type)
+int vfs_quota_off(struct super_block *sb, int type)
 {
-	struct file *filp;
-	short cnt;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
+	int cnt;
+	struct quota_info *dqopt = sb_dqopt(sb);
 
 	lock_kernel();
 	if (!sb)
@@ -1292,51 +1275,48 @@
 		/* Note: these are blocking operations */
 		remove_dquot_ref(sb, cnt);
 		invalidate_dquots(sb, cnt);
+		if (info_dirty(&dqopt->info[cnt]))
+			dqopt->ops[cnt]->write_file_info(sb, cnt);
+		if (dqopt->ops[cnt]->free_file_info)
+			dqopt->ops[cnt]->free_file_info(sb, cnt);
+		put_quota_format(dqopt->info[cnt].dqi_format);
 
-		filp = dqopt->files[cnt];
+		fput(dqopt->files[cnt]);
 		dqopt->files[cnt] = (struct file *)NULL;
-		dqopt->inode_expire[cnt] = 0;
-		dqopt->block_expire[cnt] = 0;
-		fput(filp);
-	}	
+		dqopt->info[cnt].dqi_flags = 0;
+		dqopt->info[cnt].dqi_igrace = 0;
+		dqopt->info[cnt].dqi_bgrace = 0;
+		dqopt->ops[cnt] = NULL;
+	}
 	up(&dqopt->dqoff_sem);
 out:
 	unlock_kernel();
 	return 0;
 }
 
-static inline int check_quotafile_size(loff_t size)
-{
-	ulong blocks = size >> BLOCK_SIZE_BITS;
-	size_t off = size & (BLOCK_SIZE - 1);
-
-	return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk));
-}
-
-static int quota_on(struct super_block *sb, short type, char *path)
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
 {
-	struct file *f;
+	struct file *f = NULL;
 	struct inode *inode;
-	struct dquot *dquot;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
-	char *tmp;
+	struct quota_info *dqopt = sb_dqopt(sb);
+	struct quota_format_type *fmt = find_quota_format(format_id);
 	int error;
 
-	if (is_enabled(dqopt, type))
-		return -EBUSY;
+	if (!fmt)
+		return -ESRCH;
+	if (is_enabled(dqopt, type)) {
+		error = -EBUSY;
+		goto out_fmt;
+	}
 
 	down(&dqopt->dqoff_sem);
-	tmp = getname(path);
-	error = PTR_ERR(tmp);
-	if (IS_ERR(tmp))
-		goto out_lock;
 
-	f = filp_open(tmp, O_RDWR, 0600);
-	putname(tmp);
+	f = filp_open(path, O_RDWR, 0600);
 
 	error = PTR_ERR(f);
 	if (IS_ERR(f))
 		goto out_lock;
+	dqopt->files[type] = f;
 	error = -EIO;
 	if (!f->f_op || !f->f_op->read || !f->f_op->write)
 		goto out_f;
@@ -1345,134 +1325,197 @@
 	if (!S_ISREG(inode->i_mode))
 		goto out_f;
 	error = -EINVAL;
-	if (inode->i_size == 0 || !check_quotafile_size(inode->i_size))
+	if (!fmt->qf_ops->check_quota_file(sb, type))
 		goto out_f;
 	/* We don't want quota on quota files */
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
 
-	dqopt->files[type] = f;
-	sb->dq_op = &dquot_operations;
+	dqopt->ops[type] = fmt->qf_ops;
+	dqopt->info[type].dqi_format = fmt;
+	if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0)
+		goto out_f;
 	set_enable_flags(dqopt, type);
 
-	dquot = dqget(sb, 0, type);
-	dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME;
-	dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME;
-	dqput(dquot);
-
 	add_dquot_ref(sb, type);
 
 	up(&dqopt->dqoff_sem);
 	return 0;
 
 out_f:
-	filp_close(f, NULL);
+	if (f)
+		filp_close(f, NULL);
+	dqopt->files[type] = NULL;
 out_lock:
 	up(&dqopt->dqoff_sem);
+out_fmt:
+	put_quota_format(fmt);
 
 	return error; 
 }
 
-/*
- * This is the system call interface. This communicates with
- * the user-level programs. Currently this only supports diskquota
- * calls. Maybe we need to add the process quotas etc. in the future,
- * but we probably should use rlimits for that.
- */
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+/* Generic routine for getting common part of quota structure */
+static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
 {
-	int cmds = 0, type = 0, flags = 0;
-	kdev_t dev;
-	struct super_block *sb = NULL;
-	int ret = -EINVAL;
+	struct mem_dqblk *dm = &dquot->dq_dqb;
 
-	lock_kernel();
-	cmds = cmd >> SUBCMDSHIFT;
-	type = cmd & SUBCMDMASK;
+	di->dqb_bhardlimit = dm->dqb_bhardlimit;
+	di->dqb_bsoftlimit = dm->dqb_bsoftlimit;
+	di->dqb_curspace = dm->dqb_curspace;
+	di->dqb_ihardlimit = dm->dqb_ihardlimit;
+	di->dqb_isoftlimit = dm->dqb_isoftlimit;
+	di->dqb_curinodes = dm->dqb_curinodes;
+	di->dqb_btime = dm->dqb_btime;
+	di->dqb_itime = dm->dqb_itime;
+	di->dqb_valid = QIF_ALL;
+}
 
-	if ((u_int) type >= MAXQUOTAS)
-		goto out;
-	if (id & ~0xFFFF)
-		goto out;
+int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+	struct dquot *dquot = dqget(sb, id, type);
 
-	ret = -EPERM;
-	switch (cmds) {
-		case Q_SYNC:
-		case Q_GETSTATS:
-			break;
-		case Q_GETQUOTA:
-			if (((type == USRQUOTA && current->euid != id) ||
-			     (type == GRPQUOTA && !in_egroup_p(id))) &&
-			    !capable(CAP_SYS_ADMIN))
-				goto out;
-			break;
-		default:
-			if (!capable(CAP_SYS_ADMIN))
-				goto out;
-	}
-
-	ret = -EINVAL;
-	dev = NODEV;
-	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
-		mode_t mode;
-		struct nameidata nd;
-
-		ret = user_path_walk(special, &nd);
-		if (ret)
-			goto out;
-
-		dev = nd.dentry->d_inode->i_rdev;
-		mode = nd.dentry->d_inode->i_mode;
-		path_release(&nd);
-
-		ret = -ENOTBLK;
-		if (!S_ISBLK(mode))
-			goto out;
-		ret = -ENODEV;
-		sb = get_super(dev);
-		if (!sb)
-			goto out;
-	}
-
-	ret = -EINVAL;
-	switch (cmds) {
-		case Q_QUOTAON:
-			ret = quota_on(sb, type, (char *) addr);
-			goto out;
-		case Q_QUOTAOFF:
-			ret = quota_off(sb, type);
-			goto out;
-		case Q_GETQUOTA:
-			ret = get_quota(sb, id, type, (struct dqblk *) addr);
-			goto out;
-		case Q_SETQUOTA:
-			flags |= SET_QUOTA;
-			break;
-		case Q_SETUSE:
-			flags |= SET_USE;
-			break;
-		case Q_SETQLIM:
-			flags |= SET_QLIMIT;
-			break;
-		case Q_SYNC:
-			ret = sync_dquots(dev, type);
-			goto out;
-		case Q_GETSTATS:
-			ret = get_stats(addr);
-			goto out;
-		case Q_RSQUASH:
-			ret = quota_root_squash(sb, type, (int *) addr);
-			goto out;
-		default:
-			goto out;
-	}
-
-	ret = -NODEV;
-	if (sb && sb_has_quota_enabled(sb, type))
-		ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
-out:
-	if (sb)
-		drop_super(sb);
-	unlock_kernel();
-	return ret;
+	if (!dquot)
+		return -EINVAL;
+	do_get_dqblk(dquot, di);
+	dqput(dquot);
+	return 0;
+}
+
+/* Generic routine for setting common part of quota structure */
+static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+{
+	struct mem_dqblk *dm = &dquot->dq_dqb;
+	int check_blim = 0, check_ilim = 0;
+
+	if (di->dqb_valid & QIF_SPACE) {
+		dm->dqb_curspace = di->dqb_curspace;
+		check_blim = 1;
+	}
+	if (di->dqb_valid & QIF_BLIMITS) {
+		dm->dqb_bsoftlimit = di->dqb_bsoftlimit;
+		dm->dqb_bhardlimit = di->dqb_bhardlimit;
+		check_blim = 1;
+	}
+	if (di->dqb_valid & QIF_INODES) {
+		dm->dqb_curinodes = di->dqb_curinodes;
+		check_ilim = 1;
+	}
+	if (di->dqb_valid & QIF_ILIMITS) {
+		dm->dqb_isoftlimit = di->dqb_isoftlimit;
+		dm->dqb_ihardlimit = di->dqb_ihardlimit;
+		check_ilim = 1;
+	}
+	if (di->dqb_valid & QIF_BTIME)
+		dm->dqb_btime = di->dqb_btime;
+	if (di->dqb_valid & QIF_ITIME)
+		dm->dqb_itime = di->dqb_itime;
+
+	if (check_blim) {
+		if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) {
+			dm->dqb_btime = 0;
+			dquot->dq_flags &= ~DQ_BLKS;
+		}
+		else if (!(di->dqb_valid & QIF_BTIME))	/* Set grace only if user hasn't provided his own... */
+			dm->dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+	}
+	if (check_ilim) {
+		if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
+			dm->dqb_itime = 0;
+			dquot->dq_flags &= ~DQ_INODES;
+		}
+		else if (!(di->dqb_valid & QIF_ITIME))	/* Set grace only if user hasn't provided his own... */
+			dm->dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+	}
+	if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
+		dquot->dq_flags &= ~DQ_FAKE;
+	else
+		dquot->dq_flags |= DQ_FAKE;
+	dquot->dq_flags |= DQ_MOD;
+}
+
+int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+	struct dquot *dquot = dqget(sb, id, type);
+
+	if (!dquot)
+		return -EINVAL;
+	do_set_dqblk(dquot, di);
+	dqput(dquot);
+	return 0;
+}
+
+/* Generic routine for getting common part of quota file information */
+int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+	ii->dqi_bgrace = mi->dqi_bgrace;
+	ii->dqi_igrace = mi->dqi_igrace;
+	ii->dqi_flags = mi->dqi_flags & DQF_MASK;
+	ii->dqi_valid = IIF_ALL;
+	return 0;
+}
+
+/* Generic routine for setting common part of quota file information */
+int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+	if (ii->dqi_valid & IIF_BGRACE)
+		mi->dqi_bgrace = ii->dqi_bgrace;
+	if (ii->dqi_valid & IIF_IGRACE)
+		mi->dqi_igrace = ii->dqi_igrace;
+	if (ii->dqi_valid & IIF_FLAGS)
+		mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK);
+	mark_info_dirty(mi);
+	return 0;
+}
+
+struct quotactl_ops vfs_quotactl_ops = {
+	quota_on:	vfs_quota_on,
+	quota_off:	vfs_quota_off,
+	quota_sync:	vfs_quota_sync,
+	get_info:	vfs_get_dqinfo,
+	set_info:	vfs_set_dqinfo,
+	get_dqblk:	vfs_get_dqblk,
+	set_dqblk:	vfs_set_dqblk
+};
+
+static ctl_table fs_dqstats_table[] = {
+	{FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec},
+	{},
+};
+
+static ctl_table fs_table[] = {
+	{FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table},
+	{},
+};
+
+static ctl_table sys_table[] = {
+	{CTL_FS, "fs", NULL, 0, 0555, fs_table},
+	{},
+};
+
+static int __init dquot_init(void)
+{
+	int i;
+
+	register_sysctl_table(sys_table, 0);
+	for (i = 0; i < NR_DQHASH; i++)
+		INIT_LIST_HEAD(dquot_hash + i);
+	printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__);
+
+	return 0;
 }
+__initcall(dquot_init);
+
+EXPORT_SYMBOL(register_quota_format);
+EXPORT_SYMBOL(unregister_quota_format);
+EXPORT_SYMBOL(dqstats);
diff -urN linux-2.4.21-bk3/fs/exec.c linux-2.4.21-bk4/fs/exec.c
--- linux-2.4.21-bk3/fs/exec.c	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/fs/exec.c	2003-07-08 02:59:48.000000000 -0700
@@ -563,6 +563,7 @@
 	char * name;
 	int i, ch, retval;
 	struct signal_struct * oldsig;
+	struct files_struct * files;
 
 	/*
 	 * Make sure we have a private signal table
@@ -571,6 +572,18 @@
 	retval = make_private_signals();
 	if (retval) goto flush_failed;
 
+	/*
+	 * Make sure we have private file handles. Ask the
+	 * fork helper to do the work for us and the exit
+	 * helper to do the cleanup of the old one.
+	 */
+	 
+	files = current->files;		/* refcounted so safe to hold */
+	retval = unshare_files();
+	if(retval)
+		goto flush_failed;
+	put_files_struct(files);
+	
 	/* 
 	 * Release all of the old mmap stuff
 	 */
diff -urN linux-2.4.21-bk3/fs/inode.c linux-2.4.21-bk4/fs/inode.c
--- linux-2.4.21-bk3/fs/inode.c	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/fs/inode.c	2003-07-08 02:59:48.000000000 -0700
@@ -106,6 +106,7 @@
 		atomic_set(&inode->i_writecount, 0);
 		inode->i_size = 0;
 		inode->i_blocks = 0;
+		inode->i_bytes = 0;
 		inode->i_generation = 0;
 		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
 		inode->i_pipe = NULL;
diff -urN linux-2.4.21-bk3/fs/intermezzo/journal.c linux-2.4.21-bk4/fs/intermezzo/journal.c
--- linux-2.4.21-bk3/fs/intermezzo/journal.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/fs/intermezzo/journal.c	2003-07-08 02:59:48.000000000 -0700
@@ -617,8 +617,7 @@
 
         CDEBUG(D_CACHE, "looking up: %s\n", path);
 
-        if (path_init(path, LOOKUP_PARENT, nd))
-                error = path_walk(path, nd);
+        error = path_lookup(path, LOOKUP_PARENT, nd);
         if (error) {
                 EXIT;
                 return error;
diff -urN linux-2.4.21-bk3/fs/intermezzo/presto.c linux-2.4.21-bk4/fs/intermezzo/presto.c
--- linux-2.4.21-bk3/fs/intermezzo/presto.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/fs/intermezzo/presto.c	2003-07-08 02:59:48.000000000 -0700
@@ -53,8 +53,7 @@
 
         ENTRY;
         err = 0;
-        if (path_init(name, flags, nd)) 
-                err = path_walk(name, nd);
+        err = path_lookup(name, flags, nd);
         return err;
 }
 
diff -urN linux-2.4.21-bk3/fs/intermezzo/vfs.c linux-2.4.21-bk4/fs/intermezzo/vfs.c
--- linux-2.4.21-bk3/fs/intermezzo/vfs.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/intermezzo/vfs.c	2003-07-08 02:59:48.000000000 -0700
@@ -702,8 +702,7 @@
 
         /* this looks up the parent */
 //        if (path_init(pathname, LOOKUP_FOLLOW | LOOKUP_POSITIVE, &nd))
-        if (path_init(pathname,  LOOKUP_PARENT, &nd))
-                error = path_walk(pathname, &nd);
+        error = path_lookup(pathname,  LOOKUP_PARENT, &nd);
         if (error) {
                 EXIT;
                 goto exit;
@@ -855,12 +854,10 @@
                 struct nameidata nd, old_nd;
 
                 error = 0;
-                if (path_init(from, LOOKUP_POSITIVE, &old_nd))
-                        error = path_walk(from, &old_nd);
+                error = path_lookup(from, LOOKUP_POSITIVE, &old_nd);
                 if (error)
                         goto exit;
-                if (path_init(to, LOOKUP_PARENT, &nd))
-                        error = path_walk(to, &nd);
+                error = path_lookup(to, LOOKUP_PARENT, &nd);
                 if (error)
                         goto out;
                 error = -EXDEV;
@@ -1062,8 +1059,7 @@
         if(IS_ERR(name))
                 return PTR_ERR(name);
 
-        if (path_init(name, LOOKUP_PARENT, &nd))
-                error = path_walk(name, &nd);
+        error = path_lookup(name, LOOKUP_PARENT, &nd);
         if (error)
                 goto exit;
         error = -EISDIR;
@@ -1223,8 +1219,7 @@
                 goto exit_from;
         }
 
-        if (path_init(to, LOOKUP_PARENT, &nd)) 
-                error = path_walk(to, &nd);
+        error = path_lookup(to, LOOKUP_PARENT, &nd);
         if (error) {
                 EXIT;
                 goto exit_to;
@@ -1381,8 +1376,7 @@
                 return error;
         }
 
-        if (path_init(pathname, LOOKUP_PARENT, &nd))
-                error = path_walk(pathname, &nd);
+        error = path_lookup(pathname, LOOKUP_PARENT, &nd);
         if (error)
                 goto out_name;
 
@@ -1527,8 +1521,7 @@
                 return PTR_ERR(name);
         }
 
-        if (path_init(name, LOOKUP_PARENT, &nd))
-                error = path_walk(name, &nd);
+        error = path_lookup(name, LOOKUP_PARENT, &nd);
         if (error) {
                 EXIT;
                 goto exit;
@@ -1693,8 +1686,7 @@
         if (IS_ERR(tmp))
                 return PTR_ERR(tmp);
 
-        if (path_init(tmp, LOOKUP_PARENT, &nd))
-                error = path_walk(tmp, &nd);
+        error = path_lookup(tmp, LOOKUP_PARENT, &nd);
         if (error)
                 goto out;
         dentry = lookup_create(&nd, 0);
@@ -1973,14 +1965,11 @@
 
         ENTRY;
 
-        if (path_init(oldname, LOOKUP_PARENT, &oldnd))
-                error = path_walk(oldname, &oldnd);
-
+        error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
         if (error)
                 goto exit;
 
-        if (path_init(newname, LOOKUP_PARENT, &newnd))
-                error = path_walk(newname, &newnd);
+        error = path_lookup(newname, LOOKUP_PARENT, &newnd);
         if (error)
                 goto exit1;
 
diff -urN linux-2.4.21-bk3/fs/ioctl.c linux-2.4.21-bk4/fs/ioctl.c
--- linux-2.4.21-bk3/fs/ioctl.c	2001-02-09 11:29:44.000000000 -0800
+++ linux-2.4.21-bk4/fs/ioctl.c	2003-07-08 02:59:48.000000000 -0700
@@ -101,6 +101,16 @@
 				filp->f_flags &= ~FASYNC;
 			break;
 
+		case FIOQSIZE:
+			if (S_ISDIR(filp->f_dentry->d_inode->i_mode) ||
+			    S_ISREG(filp->f_dentry->d_inode->i_mode) ||
+			    S_ISLNK(filp->f_dentry->d_inode->i_mode)) {
+				loff_t res = inode_get_bytes(filp->f_dentry->d_inode);
+				error = copy_to_user((loff_t *)arg, &res, sizeof(res)) ? -EFAULT : 0;
+			}
+			else
+				error = -ENOTTY;
+			break;
 		default:
 			error = -ENOTTY;
 			if (S_ISREG(filp->f_dentry->d_inode->i_mode))
diff -urN linux-2.4.21-bk3/fs/namei.c linux-2.4.21-bk4/fs/namei.c
--- linux-2.4.21-bk3/fs/namei.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/namei.c	2003-07-08 02:59:48.000000000 -0700
@@ -263,7 +263,7 @@
 static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
 {
 	struct dentry * dentry = d_lookup(parent, name);
-
+	
 	if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
 		if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
 			dput(dentry);
@@ -273,6 +273,61 @@
 	return dentry;
 }
 
+/*for fastwalking*/
+static inline void unlock_nd(struct nameidata *nd)
+{
+	struct vfsmount *mnt = nd->old_mnt;
+	struct dentry *dentry = nd->old_dentry;
+	mntget(nd->mnt);
+	dget_locked(nd->dentry);
+	nd->old_mnt = NULL;
+	nd->old_dentry = NULL;
+	spin_unlock(&dcache_lock);
+	dput(dentry);
+	mntput(mnt);
+}
+
+static inline void lock_nd(struct nameidata *nd)
+{
+	spin_lock(&dcache_lock);
+	nd->old_mnt = nd->mnt;
+	nd->old_dentry = nd->dentry;
+}
+
+/*
+ * Short-cut version of permission(), for calling by
+ * path_walk(), when dcache lock is held.  Combines parts
+ * of permission() and vfs_permission(), and tests ONLY for
+ * MAY_EXEC permission.
+ *
+ * If appropriate, check DAC only.  If not appropriate, or
+ * short-cut DAC fails, then call permission() to do more
+ * complete permission check.
+ */
+static inline int exec_permission_lite(struct inode *inode)
+{
+	umode_t	mode = inode->i_mode;
+
+	if ((inode->i_op && inode->i_op->permission))
+		return -EAGAIN;
+
+	if (current->fsuid == inode->i_uid)
+		mode >>= 6;
+	else if (in_group_p(inode->i_gid))
+		mode >>= 3;
+
+	if (mode & MAY_EXEC)
+		return 0;
+
+	if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE))
+		return 0;
+
+	if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH))
+	return 0;
+
+	return -EACCES;
+}
+
 /*
  * This is called when everything else fails, and we actually have
  * to go to the low-level filesystem to find out what we should do..
@@ -354,10 +409,10 @@
 	return -ELOOP;
 }
 
-static inline int __follow_up(struct vfsmount **mnt, struct dentry **base)
+int follow_up(struct vfsmount **mnt, struct dentry **dentry)
 {
 	struct vfsmount *parent;
-	struct dentry *dentry;
+	struct dentry *mountpoint;
 	spin_lock(&dcache_lock);
 	parent=(*mnt)->mnt_parent;
 	if (parent == *mnt) {
@@ -365,18 +420,27 @@
 		return 0;
 	}
 	mntget(parent);
-	dentry=dget((*mnt)->mnt_mountpoint);
+	mountpoint=dget((*mnt)->mnt_mountpoint);
 	spin_unlock(&dcache_lock);
-	dput(*base);
-	*base = dentry;
+	dput(*dentry);
+	*dentry = mountpoint;
 	mntput(*mnt);
 	*mnt = parent;
 	return 1;
 }
 
-int follow_up(struct vfsmount **mnt, struct dentry **dentry)
+static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
 {
-	return __follow_up(mnt, dentry);
+	int res = 0;
+	while (d_mountpoint(*dentry)) {
+		struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
+		if (!mounted)
+			break;
+		*mnt = mounted;
+		*dentry = mounted->mnt_root;
+		res = 1;
+	}
+	return res;
 }
 
 static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
@@ -402,41 +466,83 @@
 	return __follow_down(mnt,dentry);
 }
  
-static inline void follow_dotdot(struct nameidata *nd)
+static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
 {
 	while(1) {
 		struct vfsmount *parent;
-		struct dentry *dentry;
-		read_lock(&current->fs->lock);
-		if (nd->dentry == current->fs->root &&
-		    nd->mnt == current->fs->rootmnt)  {
-			read_unlock(&current->fs->lock);
+		if (*dentry == current->fs->root &&
+		    *mnt == current->fs->rootmnt)
 			break;
-		}
-		read_unlock(&current->fs->lock);
-		spin_lock(&dcache_lock);
-		if (nd->dentry != nd->mnt->mnt_root) {
-			dentry = dget(nd->dentry->d_parent);
-			spin_unlock(&dcache_lock);
-			dput(nd->dentry);
-			nd->dentry = dentry;
+		if (*dentry != (*mnt)->mnt_root) {
+			*dentry = (*dentry)->d_parent;
 			break;
 		}
-		parent=nd->mnt->mnt_parent;
-		if (parent == nd->mnt) {
-			spin_unlock(&dcache_lock);
+		parent=(*mnt)->mnt_parent;
+		if (parent == *mnt)
 			break;
-		}
-		mntget(parent);
-		dentry=dget(nd->mnt->mnt_mountpoint);
-		spin_unlock(&dcache_lock);
-		dput(nd->dentry);
-		nd->dentry = dentry;
-		mntput(nd->mnt);
-		nd->mnt = parent;
+		*dentry=(*mnt)->mnt_mountpoint;
+		*mnt = parent;
 	}
-	while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))
-		;
+	follow_mount(mnt, dentry);
+}
+
+struct path {
+	struct vfsmount *mnt;
+	struct dentry *dentry;
+};
+
+/*
+ *  It's more convoluted than I'd like it to be, but... it's still fairly
+ *  small and for now I'd prefer to have fast path as straight as possible.
+ *  It _is_ time-critical.
+ */
+static int do_lookup(struct nameidata *nd, struct qstr *name,
+		     struct path *path, struct path *cached_path,
+		     int flags)
+{
+	struct vfsmount *mnt = nd->mnt;
+	struct dentry *dentry = __d_lookup(nd->dentry, name);
+
+	if (!dentry)
+		goto dcache_miss;
+	if (dentry->d_op && dentry->d_op->d_revalidate)
+		goto need_revalidate;
+done:
+	path->mnt = mnt;
+	path->dentry = dentry;
+	return 0;
+
+dcache_miss:
+	unlock_nd(nd);
+
+need_lookup:
+	dentry = real_lookup(nd->dentry, name, LOOKUP_CONTINUE);
+	if (IS_ERR(dentry))
+		goto fail;
+	mntget(mnt);
+relock:
+	dput(cached_path->dentry);
+	mntput(cached_path->mnt);
+	cached_path->mnt = mnt;
+	cached_path->dentry = dentry;
+	lock_nd(nd);
+	goto done;
+
+need_revalidate:
+	mntget(mnt);
+	dget_locked(dentry);
+	unlock_nd(nd);
+	if (dentry->d_op->d_revalidate(dentry, flags))
+		goto relock;
+	if (d_invalidate(dentry))
+		goto relock;
+	dput(dentry);
+	mntput(mnt);
+	goto need_lookup;
+
+fail:
+	lock_nd(nd);
+	return PTR_ERR(dentry);
 }
 
 /*
@@ -449,15 +555,15 @@
  */
 int link_path_walk(const char * name, struct nameidata *nd)
 {
-	struct dentry *dentry;
+	struct path next, pinned = {NULL, NULL};
 	struct inode *inode;
 	int err;
 	unsigned int lookup_flags = nd->flags;
-
+	
 	while (*name=='/')
 		name++;
 	if (!*name)
-		goto return_reval;
+		goto return_base;
 
 	inode = nd->dentry->d_inode;
 	if (current->link_count)
@@ -469,8 +575,12 @@
 		struct qstr this;
 		unsigned int c;
 
-		err = permission(inode, MAY_EXEC);
-		dentry = ERR_PTR(err);
+		err = exec_permission_lite(inode);
+		if (err == -EAGAIN) {
+			unlock_nd(nd);
+			err = permission(inode, MAY_EXEC);
+			lock_nd(nd);
+		}
  		if (err)
 			break;
 
@@ -504,7 +614,7 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				follow_dotdot(nd);
+				follow_dotdot(&nd->mnt, &nd->dentry);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
@@ -520,30 +630,30 @@
 				break;
 		}
 		/* This does the actual lookups.. */
-		dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
-		if (!dentry) {
-			dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
+		err = do_lookup(nd, &this, &next, &pinned, LOOKUP_CONTINUE);
+		if (err)
+			break;
 		/* Check mountpoints.. */
-		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-			;
+		follow_mount(&next.mnt, &next.dentry);
 
 		err = -ENOENT;
-		inode = dentry->d_inode;
+		inode = next.dentry->d_inode;
 		if (!inode)
-			goto out_dput;
+			break;
 		err = -ENOTDIR; 
 		if (!inode->i_op)
-			goto out_dput;
+			break;
 
 		if (inode->i_op->follow_link) {
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
+			mntget(next.mnt);
+			dget_locked(next.dentry);
+			unlock_nd(nd);
+			err = do_follow_link(next.dentry, nd);
+			dput(next.dentry);
+			mntput(next.mnt);
 			if (err)
 				goto return_err;
+			lock_nd(nd);
 			err = -ENOENT;
 			inode = nd->dentry->d_inode;
 			if (!inode)
@@ -552,8 +662,8 @@
 			if (!inode->i_op)
 				break;
 		} else {
-			dput(nd->dentry);
-			nd->dentry = dentry;
+			nd->mnt = next.mnt;
+			nd->dentry = next.dentry;
 		}
 		err = -ENOTDIR; 
 		if (!inode->i_op->lookup)
@@ -572,52 +682,47 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				follow_dotdot(nd);
+				follow_dotdot(&nd->mnt, &nd->dentry);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
-				goto return_reval;
+				goto return_base;
 		}
 		if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
 			err = nd->dentry->d_op->d_hash(nd->dentry, &this);
 			if (err < 0)
 				break;
 		}
-		dentry = cached_lookup(nd->dentry, &this, 0);
-		if (!dentry) {
-			dentry = real_lookup(nd->dentry, &this, 0);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
-		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-			;
-		inode = dentry->d_inode;
+		err = do_lookup(nd, &this, &next, &pinned, 0);
+		if (err)
+			break;
+		follow_mount(&next.mnt, &next.dentry);
+		inode = next.dentry->d_inode;
 		if ((lookup_flags & LOOKUP_FOLLOW)
 		    && inode && inode->i_op && inode->i_op->follow_link) {
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
+			mntget(next.mnt);
+			dget_locked(next.dentry);
+			unlock_nd(nd);
+			err = do_follow_link(next.dentry, nd);
+			dput(next.dentry);
+			mntput(next.mnt);
 			if (err)
 				goto return_err;
 			inode = nd->dentry->d_inode;
+			lock_nd(nd);
 		} else {
-			dput(nd->dentry);
-			nd->dentry = dentry;
+			nd->mnt = next.mnt;
+			nd->dentry = next.dentry;
 		}
 		err = -ENOENT;
 		if (!inode)
-			goto no_inode;
+			break;
 		if (lookup_flags & LOOKUP_DIRECTORY) {
 			err = -ENOTDIR; 
 			if (!inode->i_op || !inode->i_op->lookup)
 				break;
 		}
 		goto return_base;
-no_inode:
-		err = -ENOENT;
-		if (lookup_flags & (LOOKUP_POSITIVE|LOOKUP_DIRECTORY))
-			break;
-		goto return_base;
 lookup_parent:
 		nd->last = this;
 		nd->last_type = LAST_NORM;
@@ -627,33 +732,24 @@
 			nd->last_type = LAST_DOT;
 		else if (this.len == 2 && this.name[1] == '.')
 			nd->last_type = LAST_DOTDOT;
-return_reval:
-		/*
-		 * We bypassed the ordinary revalidation routines.
-		 * Check the cached dentry for staleness.
-		 */
-		dentry = nd->dentry;
-		if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
-			err = -ESTALE;
-			if (!dentry->d_op->d_revalidate(dentry, 0)) {
-				d_invalidate(dentry);
-				break;
-			}
-		}
 return_base:
+		unlock_nd(nd);
+		dput(pinned.dentry);
+		mntput(pinned.mnt);
 		return 0;
-out_dput:
-		dput(dentry);
-		break;
 	}
+	unlock_nd(nd);
 	path_release(nd);
 return_err:
+	dput(pinned.dentry);
+	mntput(pinned.mnt);
 	return err;
 }
 
 int path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
+	lock_nd(nd);
 	return link_path_walk(name, nd);
 }
 
@@ -738,28 +834,35 @@
 	return 1;
 }
 
-/* SMP-safe */
-int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
-{
-	int error = 0;
-	if (path_init(path, flags, nd))
-		error = path_walk(path, nd);
-	return error;
-}
-
 
-/* SMP-safe */
-int path_init(const char *name, unsigned int flags, struct nameidata *nd)
+int path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
-	if (*name=='/')
-		return walk_init_root(name,nd);
-	read_lock(&current->fs->lock);
-	nd->mnt = mntget(current->fs->pwdmnt);
-	nd->dentry = dget(current->fs->pwd);
-	read_unlock(&current->fs->lock);
-	return 1;
+	if (*name=='/') {
+		read_lock(&current->fs->lock);
+		if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+			nd->mnt = mntget(current->fs->altrootmnt);
+			nd->dentry = dget(current->fs->altroot);
+			read_unlock(&current->fs->lock);
+			if (__emul_lookup_dentry(name,nd))
+				return 0;
+			read_lock(&current->fs->lock);
+		}
+		read_unlock(&current->fs->lock);
+		spin_lock(&dcache_lock);
+		nd->mnt = current->fs->rootmnt;
+		nd->dentry = current->fs->root;
+	}
+	else{
+		spin_lock(&dcache_lock);
+		nd->mnt = current->fs->pwdmnt;
+		nd->dentry = current->fs->pwd;
+	}
+	nd->old_mnt = NULL;
+	nd->old_dentry = NULL;
+	current->total_link_count = 0;
+	return link_path_walk(name, nd);
 }
 
 /*
@@ -1964,6 +2067,7 @@
 			/* weird __emul_prefix() stuff did it */
 			goto out;
 	}
+	lock_nd(nd);
 	res = link_path_walk(link, nd);
 out:
 	if (current->link_count || res || nd->last_type!=LAST_NORM)
diff -urN linux-2.4.21-bk3/fs/namespace.c linux-2.4.21-bk4/fs/namespace.c
--- linux-2.4.21-bk3/fs/namespace.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/namespace.c	2003-07-08 02:59:48.000000000 -0700
@@ -23,6 +23,7 @@
 
 struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
 int do_remount_sb(struct super_block *sb, int flags, void * data);
+int __init init_rootfs(void);
 void kill_super(struct super_block *sb);
 extern int __init init_rootfs(void);
 
diff -urN linux-2.4.21-bk3/fs/nfsd/export.c linux-2.4.21-bk4/fs/nfsd/export.c
--- linux-2.4.21-bk3/fs/nfsd/export.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/fs/nfsd/export.c	2003-07-08 02:59:48.000000000 -0700
@@ -214,8 +214,7 @@
 
 	/* Look up the dentry */
 	err = 0;
-	if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd))
-		err = path_walk(nxp->ex_path, &nd);
+	err = path_lookup(nxp->ex_path, LOOKUP_POSITIVE, &nd);
 	if (err)
 		goto out_unlock;
 
@@ -411,8 +410,7 @@
 
 	err = -EPERM;
 	if (path) {
-		if (path_init(path, LOOKUP_POSITIVE, &nd) &&
-		    path_walk(path, &nd)) {
+		if (path_lookup(path, LOOKUP_POSITIVE, &nd))  {
 			printk("nfsd: exp_rootfh path not found %s", path);
 			return err;
 		}
diff -urN linux-2.4.21-bk3/fs/quota.c linux-2.4.21-bk4/fs/quota.c
--- linux-2.4.21-bk3/fs/quota.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/fs/quota.c	2003-07-08 02:59:48.000000000 -0700
@@ -0,0 +1,480 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  The interesting stuff is over in dquot.c, here
+ * we have symbols for initial quotactl(2) handling, the sysctl(2)
+ * variables, etc - things needed even when quota support disabled.
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/quotacompat.h>
+
+
+/* Check validity of quotactl */
+static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	if (type >= MAXQUOTAS)
+		return -EINVAL;
+	/* Is operation supported? */
+	if (!sb->s_qcop)
+		return -ENOSYS;
+
+	switch (cmd) {
+		case Q_GETFMT:
+			break;
+		case Q_QUOTAON:
+			if (!sb->s_qcop->quota_on)
+				return -ENOSYS;
+			break;
+		case Q_QUOTAOFF:
+			if (!sb->s_qcop->quota_off)
+				return -ENOSYS;
+			break;
+		case Q_SETINFO:
+			if (!sb->s_qcop->set_info)
+				return -ENOSYS;
+			break;
+		case Q_GETINFO:
+			if (!sb->s_qcop->get_info)
+				return -ENOSYS;
+			break;
+		case Q_SETQUOTA:
+			if (!sb->s_qcop->set_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_GETQUOTA:
+			if (!sb->s_qcop->get_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_SYNC:
+			if (!sb->s_qcop->quota_sync)
+				return -ENOSYS;
+			break;
+		case Q_XQUOTAON:
+		case Q_XQUOTAOFF:
+		case Q_XQUOTARM:
+			if (!sb->s_qcop->set_xstate)
+				return -ENOSYS;
+			break;
+		case Q_XGETQSTAT:
+			if (!sb->s_qcop->get_xstate)
+				return -ENOSYS;
+			break;
+		case Q_XSETQLIM:
+			if (!sb->s_qcop->set_xquota)
+				return -ENOSYS;
+			break;
+		case Q_XGETQUOTA:
+			if (!sb->s_qcop->get_xquota)
+				return -ENOSYS;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* Is quota turned on for commands which need it? */
+	switch (cmd) {
+		case Q_GETFMT:
+		case Q_GETINFO:
+		case Q_QUOTAOFF:
+		case Q_SETINFO:
+		case Q_SETQUOTA:
+		case Q_GETQUOTA:
+			if (!sb_has_quota_enabled(sb, type))
+				return -ESRCH;
+	}
+	/* Check privileges */
+	if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
+		if (((type == USRQUOTA && current->euid != id) ||
+		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		    !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	return 0;
+}
+
+/* Resolve device pathname to superblock */
+static struct super_block *resolve_dev(const char *path)
+{
+	int ret;
+	mode_t mode;
+	struct nameidata nd;
+	kdev_t dev;
+	struct super_block *sb;
+
+	ret = user_path_walk(path, &nd);
+	if (ret)
+		goto out;
+
+	dev = nd.dentry->d_inode->i_rdev;
+	mode = nd.dentry->d_inode->i_mode;
+	path_release(&nd);
+
+	ret = -ENOTBLK;
+	if (!S_ISBLK(mode))
+		goto out;
+	ret = -ENODEV;
+	sb = get_super(dev);
+	if (!sb)
+		goto out;
+	return sb;
+out:
+	return ERR_PTR(ret);
+}
+
+/* Copy parameters and call proper function */
+static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
+{
+	int ret;
+
+	switch (cmd) {
+		case Q_QUOTAON: {
+			char *pathname;
+
+			if (IS_ERR(pathname = getname(addr)))
+				return PTR_ERR(pathname);
+			ret = sb->s_qcop->quota_on(sb, type, id, pathname);
+			putname(pathname);
+			return ret;
+		}
+		case Q_QUOTAOFF:
+			return sb->s_qcop->quota_off(sb, type);
+
+		case Q_GETFMT: {
+			__u32 fmt;
+
+			fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
+			if (copy_to_user(addr, &fmt, sizeof(fmt)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_GETINFO: {
+			struct if_dqinfo info;
+
+			if ((ret = sb->s_qcop->get_info(sb, type, &info)))
+				return ret;
+			if (copy_to_user(addr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_SETINFO: {
+			struct if_dqinfo info;
+
+			if (copy_from_user(&info, addr, sizeof(info)))
+				return -EFAULT;
+			return sb->s_qcop->set_info(sb, type, &info);
+		}
+		case Q_GETQUOTA: {
+			struct if_dqblk idq;
+
+			if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
+				return ret;
+			if (copy_to_user(addr, &idq, sizeof(idq)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_SETQUOTA: {
+			struct if_dqblk idq;
+
+			if (copy_from_user(&idq, addr, sizeof(idq)))
+				return -EFAULT;
+			return sb->s_qcop->set_dqblk(sb, type, id, &idq);
+		}
+		case Q_SYNC:
+			return sb->s_qcop->quota_sync(sb, type);
+
+		case Q_XQUOTAON:
+		case Q_XQUOTAOFF:
+		case Q_XQUOTARM: {
+			__u32 flags;
+
+			if (copy_from_user(&flags, addr, sizeof(flags)))
+				return -EFAULT;
+			return sb->s_qcop->set_xstate(sb, flags, cmd);
+		}
+		case Q_XGETQSTAT: {
+			struct fs_quota_stat fqs;
+		
+			if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
+				return ret;
+			if (copy_to_user(addr, &fqs, sizeof(fqs)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_XSETQLIM: {
+			struct fs_disk_quota fdq;
+
+			if (copy_from_user(&fdq, addr, sizeof(fdq)))
+				return -EFAULT;
+		       return sb->s_qcop->set_xquota(sb, type, id, &fdq);
+		}
+		case Q_XGETQUOTA: {
+			struct fs_disk_quota fdq;
+
+			if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
+				return ret;
+			if (copy_to_user(addr, &fdq, sizeof(fdq)))
+				return -EFAULT;
+			return 0;
+		}
+		/* We never reach here unless validity check is broken */
+		default:
+			BUG();
+	}
+	return 0;
+}
+
+static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	if (type >= MAXQUOTAS)
+		return -EINVAL;
+	/* Is operation supported? */
+	/* sb==NULL for GETSTATS calls */
+	if (sb && !sb->s_qcop)
+		return -ENOSYS;
+
+	switch (cmd) {
+		case Q_COMP_QUOTAON:
+			if (!sb->s_qcop->quota_on)
+				return -ENOSYS;
+			break;
+		case Q_COMP_QUOTAOFF:
+			if (!sb->s_qcop->quota_off)
+				return -ENOSYS;
+			break;
+		case Q_COMP_SYNC:
+			if (!sb->s_qcop->quota_sync)
+				return -ENOSYS;
+			break;
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V1_SETQUOTA:
+			if (!sb->s_qcop->set_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V1_GETQUOTA:
+			if (!sb->s_qcop->get_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V1_RSQUASH:
+			if (!sb->s_qcop->set_info)
+				return -ENOSYS;
+			break;
+		case Q_V1_GETSTATS:
+			return 0;	/* GETSTATS need no other checks */
+		default:
+			return -EINVAL;
+	}
+
+	/* Is quota turned on for commands which need it? */
+	switch (cmd) {
+		case Q_V2_SETFLAGS:
+		case Q_V2_SETGRACE:
+		case Q_V2_SETINFO:
+		case Q_V2_GETINFO:
+		case Q_COMP_QUOTAOFF:
+		case Q_V1_RSQUASH:
+		case Q_V1_SETQUOTA:
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V2_SETQUOTA:
+		/* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
+		case Q_V2_SETUSE:
+		case Q_V1_GETQUOTA:
+		case Q_V2_GETQUOTA:
+			if (!sb_has_quota_enabled(sb, type))
+				return -ESRCH;
+	}
+	if (cmd != Q_COMP_QUOTAON &&
+	    cmd != Q_COMP_QUOTAOFF &&
+	    cmd != Q_COMP_SYNC &&
+	    sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD)
+		return -ESRCH;
+
+	/* Check privileges */
+	if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) {
+		if (((type == USRQUOTA && current->euid != id) ||
+		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		    !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC)
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	return 0;
+}
+
+static int v1_set_rsquash(struct super_block *sb, int type, int flag)
+{
+	struct if_dqinfo info;
+
+	info.dqi_valid = IIF_FLAGS;
+	info.dqi_flags = flag ? V1_DQF_RSQUASH : 0;
+	return sb->s_qcop->set_info(sb, type, &info);
+}
+
+static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+	int ret;
+
+	if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
+		return ret;
+	mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
+	mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
+	mdq->dqb_curinodes = idq.dqb_curinodes;
+	mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
+	mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
+	mdq->dqb_curblocks = toqb(idq.dqb_curspace);
+	mdq->dqb_itime = idq.dqb_itime;
+	mdq->dqb_btime = idq.dqb_btime;
+	if (id == 0) {	/* Times for id 0 are in fact grace times */
+		struct if_dqinfo info;
+
+		if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
+			return ret;
+		mdq->dqb_btime = info.dqi_bgrace;
+		mdq->dqb_itime = info.dqi_igrace;
+	}
+	return 0;
+}
+
+static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+	int ret;
+
+	idq.dqb_valid = 0;
+	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) {
+		idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
+		idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
+		idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
+		idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
+		idq.dqb_valid |= QIF_LIMITS;
+	}
+	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) {
+		idq.dqb_curinodes = mdq->dqb_curinodes;
+		idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS;
+		idq.dqb_valid |= QIF_USAGE;
+	}
+	ret = sb->s_qcop->set_dqblk(sb, type, id, &idq);
+	if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) {	/* Times for id 0 are in fact grace times */
+		struct if_dqinfo info;
+
+		info.dqi_bgrace = mdq->dqb_btime;
+		info.dqi_igrace = mdq->dqb_itime;
+		info.dqi_valid = IIF_BGRACE | IIF_IGRACE;
+		ret = sb->s_qcop->set_info(sb, type, &info);
+	}
+	return ret;
+}
+
+static void v1_get_stats(struct v1c_dqstats *dst)
+{
+	memcpy(dst, &dqstats, sizeof(dqstats));
+}
+
+/* Handle requests to old interface */
+static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
+{
+	int ret;
+
+	switch (cmd) {
+		case Q_COMP_QUOTAON: {
+			char *pathname;
+
+			if (IS_ERR(pathname = getname(addr)))
+				return PTR_ERR(pathname);
+			ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname);
+			putname(pathname);
+			return ret;
+		}
+		case Q_COMP_QUOTAOFF:
+			return sb->s_qcop->quota_off(sb, type);
+		case Q_COMP_SYNC:
+			return sb->s_qcop->quota_sync(sb, type);
+		case Q_V1_RSQUASH: {
+			int flag;
+
+			if (copy_from_user(&flag, addr, sizeof(flag)))
+				return -EFAULT;
+			return v1_set_rsquash(sb, type, flag);
+		}
+		case Q_V1_GETQUOTA: {
+			struct v1c_mem_dqblk mdq;
+
+			if ((ret = v1_get_dqblk(sb, type, id, &mdq)))
+				return ret;
+			if (copy_to_user(addr, &mdq, sizeof(mdq)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V1_SETQUOTA: {
+			struct v1c_mem_dqblk mdq;
+
+			if (copy_from_user(&mdq, addr, sizeof(mdq)))
+				return -EFAULT;
+			return v1_set_dqblk(sb, type, cmd, id, &mdq);
+		}
+		case Q_V1_GETSTATS: {
+			struct v1c_dqstats dst;
+
+			v1_get_stats(&dst);
+			if (copy_to_user(addr, &dst, sizeof(dst)))
+				return -EFAULT;
+			return 0;
+		}
+	}
+	BUG();
+	return 0;
+}
+
+/* Macros for short-circuiting the compatibility tests */
+#define NEW_COMMAND(c) ((c) & (0x80 << 16))
+#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
+
+/*
+ * This is the system call interface. This communicates with
+ * the user-level programs. Currently this only supports diskquota
+ * calls. Maybe we need to add the process quotas etc. in the future,
+ * but we probably should use rlimits for that.
+ */
+asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
+{
+	uint cmds, type;
+	struct super_block *sb = NULL;
+	int ret = -EINVAL;
+
+	lock_kernel();
+	cmds = cmd >> SUBCMDSHIFT;
+	type = cmd & SUBCMDMASK;
+
+	if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) {
+		ret = PTR_ERR(sb);
+		sb = NULL;
+		goto out;
+	}
+	if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) {
+		if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0)
+			goto out;
+		ret = do_compat_quotactl(sb, type, cmds, id, addr);
+		goto out;
+	}
+	if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
+		goto out;
+	ret = do_quotactl(sb, type, cmds, id, addr);
+out:
+	if (sb)
+		drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -urN linux-2.4.21-bk3/fs/quota_v1.c linux-2.4.21-bk4/fs/quota_v1.c
--- linux-2.4.21-bk3/fs/quota_v1.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/fs/quota_v1.c	2003-07-08 02:59:48.000000000 -0700
@@ -0,0 +1,239 @@
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/quota.h>
+#include <linux/dqblk_v1.h>
+#include <linux/quotaio_v1.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d)
+{
+	m->dqb_ihardlimit = d->dqb_ihardlimit;
+	m->dqb_isoftlimit = d->dqb_isoftlimit;
+	m->dqb_curinodes = d->dqb_curinodes;
+	m->dqb_bhardlimit = d->dqb_bhardlimit;
+	m->dqb_bsoftlimit = d->dqb_bsoftlimit;
+	m->dqb_curspace = d->dqb_curblocks << QUOTABLOCK_BITS;
+	m->dqb_itime = d->dqb_itime;
+	m->dqb_btime = d->dqb_btime;
+}
+
+static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
+{
+	d->dqb_ihardlimit = m->dqb_ihardlimit;
+	d->dqb_isoftlimit = m->dqb_isoftlimit;
+	d->dqb_curinodes = m->dqb_curinodes;
+	d->dqb_bhardlimit = m->dqb_bhardlimit;
+	d->dqb_bsoftlimit = m->dqb_bsoftlimit;
+	d->dqb_curblocks = toqb(m->dqb_curspace);
+	d->dqb_itime = m->dqb_itime;
+	d->dqb_btime = m->dqb_btime;
+}
+
+static int v1_read_dqblk(struct dquot *dquot)
+{
+	int type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	struct v1_disk_dqblk dqblk;
+
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+	if (filp == (struct file *)NULL)
+		return -EINVAL;
+
+	/* Now we are sure filp is valid */
+	offset = v1_dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
+	set_fs(fs);
+
+	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
+	if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
+	    dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0)
+		dquot->dq_flags |= DQ_FAKE;
+	dqstats.reads++;
+	return 0;
+}
+
+static int v1_commit_dqblk(struct dquot *dquot)
+{
+	short type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	ssize_t ret;
+	struct v1_disk_dqblk dqblk;
+
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+	offset = v1_dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	/*
+	 * Note: clear the DQ_MOD flag unconditionally,
+	 * so we don't loop forever on failure.
+	 */
+	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
+	dquot->dq_flags &= ~DQ_MOD;
+	if (dquot->dq_id == 0) {
+		dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
+		dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
+	}
+	ret = 0;
+	if (filp)
+		ret = filp->f_op->write(filp, (char *)&dqblk,
+					sizeof(struct v1_disk_dqblk), &offset);
+	if (ret != sizeof(struct v1_disk_dqblk)) {
+		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+			kdevname(dquot->dq_dev));
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	ret = 0;
+
+out:
+	set_fs(fs);
+	dqstats.writes++;
+	return ret;
+}
+
+/* Magics of new quota format */
+#define V2_INITQMAGICS {\
+	0xd9c01f11,     /* USRQUOTA */\
+	0xd9c01927      /* GRPQUOTA */\
+}
+
+/* Header of new quota format */
+struct v2_disk_dqheader {
+	__u32 dqh_magic;        /* Magic number identifying file */
+	__u32 dqh_version;      /* File version */
+};
+
+static int v1_check_quota_file(struct super_block *sb, int type)
+{
+	struct file *f = sb_dqopt(sb)->files[type];
+	struct inode *inode = f->f_dentry->d_inode;
+	ulong blocks;
+	size_t off; 
+	struct v2_disk_dqheader dqhead;
+	mm_segment_t fs;
+	ssize_t size;
+	loff_t offset = 0;
+	static const uint quota_magics[] = V2_INITQMAGICS;
+
+	if (!inode->i_size)
+		return 0;
+	blocks = inode->i_size >> BLOCK_SIZE_BITS;
+	off = inode->i_size & (BLOCK_SIZE - 1);
+	if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk))
+		return 0;
+	/* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
+	set_fs(fs);
+	if (size != sizeof(struct v2_disk_dqheader))
+		return 1;	/* Probably not new format */
+	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
+		return 1;	/* Definitely not new format */
+	printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", kdevname(sb->s_dev));
+        return 0;		/* Seems like a new format file -> refuse it */
+}
+
+static int v1_read_file_info(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	mm_segment_t fs;
+	loff_t offset;
+	struct file *filp = dqopt->files[type];
+	struct v1_disk_dqblk dqblk;
+	int ret;
+
+	down(&dqopt->dqio_sem);
+	offset = v1_dqoff(0);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	ret = 0;
+	dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
+	dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
+out:
+	up(&dqopt->dqio_sem);
+	set_fs(fs);
+	return ret;
+}
+
+static int v1_write_file_info(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	mm_segment_t fs;
+	struct file *filp = dqopt->files[type];
+	struct v1_disk_dqblk dqblk;
+	loff_t offset;
+	int ret;
+
+	down(&dqopt->dqio_sem);
+	dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
+	offset = v1_dqoff(0);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
+	dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
+	offset = v1_dqoff(0);
+	ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
+	if (ret == sizeof(struct v1_disk_dqblk))
+		ret = 0;
+	else if (ret > 0)
+		ret = -EIO;
+out:
+	up(&dqopt->dqio_sem);
+	set_fs(fs);
+	return ret;
+}
+
+static struct quota_format_ops v1_format_ops = {
+	check_quota_file:	v1_check_quota_file,
+	read_file_info:		v1_read_file_info,
+	write_file_info:	v1_write_file_info,
+	free_file_info:		NULL,
+	read_dqblk:		v1_read_dqblk,
+	commit_dqblk:		v1_commit_dqblk,
+};
+
+static struct quota_format_type v1_quota_format = {
+	qf_fmt_id:	QFMT_VFS_OLD,
+	qf_ops:		&v1_format_ops,
+	qf_owner:	THIS_MODULE
+};
+
+static int __init init_v1_quota_format(void)
+{
+        return register_quota_format(&v1_quota_format);
+}
+
+static void __exit exit_v1_quota_format(void)
+{
+        unregister_quota_format(&v1_quota_format);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_v1_quota_format);
+module_exit(exit_v1_quota_format);
+
diff -urN linux-2.4.21-bk3/fs/read_write.c linux-2.4.21-bk4/fs/read_write.c
--- linux-2.4.21-bk3/fs/read_write.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/read_write.c	2003-07-08 02:59:48.000000000 -0700
@@ -322,7 +322,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	if ((ret + (type == VERIFY_WRITE)) > 0)
 		dnotify_parent(file->f_dentry,
-			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
+			(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
 	return ret;
 }
 
diff -urN linux-2.4.21-bk3/fs/super.c linux-2.4.21-bk4/fs/super.c
--- linux-2.4.21-bk3/fs/super.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk4/fs/super.c	2003-07-08 02:59:48.000000000 -0700
@@ -27,6 +27,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/acct.h>
+#include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 
@@ -281,6 +282,8 @@
 		sema_init(&s->s_dquot.dqoff_sem, 1);
 		s->s_maxbytes = MAX_NON_LFS;
 		s->s_op = &empty_sops;
+		s->dq_op = sb_dquot_ops;
+		s->s_qcop = sb_quotactl_ops;
 	}
 	return s;
 }
diff -urN linux-2.4.21-bk3/include/asm-alpha/ioctls.h linux-2.4.21-bk4/include/asm-alpha/ioctls.h
--- linux-2.4.21-bk3/include/asm-alpha/ioctls.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/include/asm-alpha/ioctls.h	2003-07-08 02:59:48.000000000 -0700
@@ -9,6 +9,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 #define TIOCGETP	_IOR('t', 8, struct sgttyb)
 #define TIOCSETP	_IOW('t', 9, struct sgttyb)
diff -urN linux-2.4.21-bk3/include/asm-cris/ioctls.h linux-2.4.21-bk4/include/asm-cris/ioctls.h
--- linux-2.4.21-bk3/include/asm-cris/ioctls.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-cris/ioctls.h	2003-07-08 02:59:48.000000000 -0700
@@ -69,6 +69,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 #define TIOCSERSETRS485 0x5460  /* enable rs-485 */
 #define TIOCSERWRRS485  0x5461  /* write rs-485 */
diff -urN linux-2.4.21-bk3/include/asm-i386/io_apic.h linux-2.4.21-bk4/include/asm-i386/io_apic.h
--- linux-2.4.21-bk3/include/asm-i386/io_apic.h	2003-07-08 02:59:33.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-i386/io_apic.h	2003-07-08 02:59:48.000000000 -0700
@@ -45,7 +45,7 @@
 } __attribute__ ((packed));
 
 struct IO_APIC_reg_03 {
-	__u32	boot_DT		:  1,
+	__u32	boot_DT		: 1,
 		__reserved_1	: 31;
 } __attribute__ ((packed));
 
diff -urN linux-2.4.21-bk3/include/asm-i386/ioctls.h linux-2.4.21-bk4/include/asm-i386/ioctls.h
--- linux-2.4.21-bk3/include/asm-i386/ioctls.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-i386/ioctls.h	2003-07-08 02:59:48.000000000 -0700
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urN linux-2.4.21-bk3/include/asm-ia64/ioctls.h linux-2.4.21-bk4/include/asm-ia64/ioctls.h
--- linux-2.4.21-bk3/include/asm-ia64/ioctls.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/include/asm-ia64/ioctls.h	2003-07-08 02:59:48.000000000 -0700
@@ -72,6 +72,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urN linux-2.4.21-bk3/include/asm-m68k/ioctls.h linux-2.4.21-bk4/include/asm-m68k/ioctls.h
--- linux-2.4.21-bk3/include/asm-m68k/ioctls.h	1998-02-12 16:25:04.000000000 -0800
+++ linux-2.4.21-bk4/include/asm-m68k/ioctls.h	2003-07-08 02:59:49.000000000 -0700
@@ -65,6 +65,7 @@
 
 #define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define FIOQSIZE	0x545E
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urN linux-2.4.21-bk3/include/asm-ppc/ocp_ids.h linux-2.4.21-bk4/include/asm-ppc/ocp_ids.h
--- linux-2.4.21-bk3/include/asm-ppc/ocp_ids.h	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-ppc/ocp_ids.h	2003-07-08 02:59:49.000000000 -0700
@@ -4,7 +4,8 @@
  * BRIEF MODULE DESCRIPTION: 
  * OCP device ids based on the ideas from PCI
  *
- * Maintained by: Armin <akuster@mvista.com>
+ * The numbers below are almost completely arbitrary, and in fact
+ * strings might work better.  -- paulus
  *
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -27,8 +28,6 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  Version 1.0 08/22/02 -Armin
- *  	initial release
  */
 
 /*
diff -urN linux-2.4.21-bk3/include/asm-ppc/open_pic.h linux-2.4.21-bk4/include/asm-ppc/open_pic.h
--- linux-2.4.21-bk3/include/asm-ppc/open_pic.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-ppc/open_pic.h	2003-07-08 02:59:49.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
+ *  include/asm-ppc/open_pic.h -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
diff -urN linux-2.4.21-bk3/include/asm-ppc/pc_serial.h linux-2.4.21-bk4/include/asm-ppc/pc_serial.h
--- linux-2.4.21-bk3/include/asm-ppc/pc_serial.h	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-ppc/pc_serial.h	2003-07-08 02:59:49.000000000 -0700
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * include/asm-ppc/pc_serial.h
  *
  * This is basically a copy of include/asm-i386/serial.h.
diff -urN linux-2.4.21-bk3/include/asm-ppc/processor.h linux-2.4.21-bk4/include/asm-ppc/processor.h
--- linux-2.4.21-bk3/include/asm-ppc/processor.h	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-ppc/processor.h	2003-07-08 02:59:49.000000000 -0700
@@ -229,6 +229,9 @@
 #define	  HID0_NAP	(1<<22)
 #define	  HID0_SLEEP	(1<<21)
 #define	  HID0_DPM	(1<<20)
+#define	  HID0_BHTCLR	(1<<18)		/* Clear branch history table - 7450 */
+#define	  HID0_XAEN	(1<<17)		/* Extended addressing enable - 7450 */
+#define   HID0_NHR	(1<<16)		/* Not hard reset (software bit-7450)*/
 #define	  HID0_ICE	(1<<15)		/* Instruction Cache Enable */
 #define	  HID0_DCE	(1<<14)		/* Data Cache Enable */
 #define	  HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
@@ -247,7 +250,16 @@
 #define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
 #define	  HID0_NOPDST	(1<<1)		/* No-op dst, dstt, etc. instr. */
 #define	  HID0_NOPTI	(1<<0)		/* No-op dcbt and dcbst instr. */
+
 #define	SPRN_HID1	0x3F1	/* Hardware Implementation Register 1 */
+#define	  HID1_EMCP	(1<<31)		/* 7450 Machine Check Pin Enable */
+#define   HID1_PC0	(1<<16)		/* 7450 PLL_CFG[0] */
+#define   HID1_PC1	(1<<15)		/* 7450 PLL_CFG[1] */
+#define   HID1_PC2	(1<<14)		/* 7450 PLL_CFG[2] */
+#define   HID1_PC3	(1<<13)		/* 7450 PLL_CFG[3] */
+#define	  HID1_SYNCBE	(1<<11)		/* 7450 ABE for sync, eieio */
+#define	  HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */
+#define	SPRN_HID2	0x3F8	/* Hardware Implementation Register 2 */
 #define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
 #define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
 #define	SPRN_IAC2	0x3F5	/* Instruction Address Compare 2 */
@@ -273,6 +285,10 @@
 #define	SPRN_ICDBDR	0x3D3	/* Instruction Cache Debug Data Register */
 #define	SPRN_ICMP	0x3D5	/* Instruction TLB Compare Register */
 #define	SPRN_ICTC	0x3FB	/* Instruction Cache Throttling Control Reg */
+#define	SPRN_ICTRL 	0x3F3	/* 1011 7450 icache and interrupt ctrl */
+#define   ICTRL_EICE		0x08000000	/* enable icache parity errs */
+#define   ICTRL_EDCE		0x04000000	/* enable dcache parity errs */
+#define   ICTRL_EICP		0x00000100	/* enable icache par. check */
 #define	SPRN_IMISS	0x3D4	/* Instruction TLB Miss Register */
 #define	SPRN_IMMR	0x27E  	/* Internal Memory Map Register */
 #define	SPRN_L2CR	0x3F9	/* Level 2 Cache Control Regsiter */
@@ -328,7 +344,6 @@
 #define L3CR_PMSIZ		0x00000001	/* L3 private memory size */
 #define SPRN_MSSCR0	0x3f6	/* Memory Subsystem Control Register 0 */
 #define SPRN_MSSSR0	0x3f7	/* Memory Subsystem Status Register 1 */
-#define SPRN_ICTRL	0x3f3	/* Instruction Cache & Interrupt control reg */
 #define SPRN_LDSTCR	0x3f8	/* Load/Store control register */
 #define SPRN_LDSTDB	0x3f4	/* */
 #define	SPRN_LR		0x008	/* Link Register */
@@ -345,6 +360,8 @@
 #define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
 #define	SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
 #define	SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
+#define	SPRN_PTEHI	0x3D5	/* 981 7450 PTE HI word (S/W TLB load) */
+#define	SPRN_PTELO	0x3D6	/* 982 7450 PTE LO word (S/W TLB load)  */
 #define	SPRN_PVR	0x11F	/* Processor Version Register */
 #define	SPRN_RPA	0x3D6	/* Required Physical Address Register */
 #define	SPRN_SDA	0x3BF	/* Sampled Data Address Register */
@@ -353,6 +370,7 @@
 #define	  SGR_NORMAL		0
 #define	  SGR_GUARDED		1
 #define	SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
+#define	SPRN_SLER	0x3BB	/* Little-endian real mode */
 #define	SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 #define	SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
 #define	SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
@@ -406,6 +424,7 @@
 #define	SPRN_THRM2	0x3FD	/* Thermal Management Register 2 */
 #define	SPRN_THRM3	0x3FE	/* Thermal Management Register 3 */
 #define	  THRM3_E		(1<<0)
+#define	SPRN_TLBMISS	0x3D4	/* 980 7450 TLB Miss Register */
 #define	SPRN_TSR	0x3D8	/* Timer Status Register */
 #define	  TSR_ENW		0x80000000	/* Enable Next Watchdog */
 #define	  TSR_WIS		0x40000000	/* WDT Interrupt Status */
@@ -556,6 +575,7 @@
 #define	PVR_750P	PVR_740P
 #define	PVR_7400	0x000C0000
 #define	PVR_7410	0x800C0000
+#define	PVR_7450	0x80000000
 /*
  * For the 8xx processors, all of them report the same PVR family for
  * the PowerPC core. The various versions of these processors must be
diff -urN linux-2.4.21-bk3/include/asm-sh/ioctls.h linux-2.4.21-bk4/include/asm-sh/ioctls.h
--- linux-2.4.21-bk3/include/asm-sh/ioctls.h	1999-11-06 10:40:31.000000000 -0800
+++ linux-2.4.21-bk4/include/asm-sh/ioctls.h	2003-07-08 02:59:49.000000000 -0700
@@ -9,6 +9,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 #define TCGETS		0x5401
 #define TCSETS		0x5402
diff -urN linux-2.4.21-bk3/include/asm-sparc/ioctls.h linux-2.4.21-bk4/include/asm-sparc/ioctls.h
--- linux-2.4.21-bk3/include/asm-sparc/ioctls.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-sparc/ioctls.h	2003-07-08 02:59:49.000000000 -0700
@@ -86,6 +86,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
  * someday.  This is completely bogus, I know...
diff -urN linux-2.4.21-bk3/include/asm-sparc64/ioctls.h linux-2.4.21-bk4/include/asm-sparc64/ioctls.h
--- linux-2.4.21-bk3/include/asm-sparc64/ioctls.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/include/asm-sparc64/ioctls.h	2003-07-08 02:59:49.000000000 -0700
@@ -87,6 +87,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
  * someday.  This is completely bogus, I know...
diff -urN linux-2.4.21-bk3/include/linux/agp_backend.h linux-2.4.21-bk4/include/linux/agp_backend.h
--- linux-2.4.21-bk3/include/linux/agp_backend.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/agp_backend.h	2003-07-08 02:59:49.000000000 -0700
@@ -52,16 +52,20 @@
 	INTEL_I840,
 	INTEL_I845,
 	INTEL_I850,
+	INTEL_I855_PM,
 	INTEL_I860,
+	INTEL_I865_G,
 	VIA_GENERIC,
 	VIA_VP3,
 	VIA_MVP3,
 	VIA_MVP4,
+	VIA_APOLLO_PLE133,
 	VIA_APOLLO_PRO,
 	VIA_APOLLO_KX133,
 	VIA_APOLLO_KT133,
-	VIA_APOLLO_P4X400,
+	VIA_APOLLO_KM266,
 	VIA_APOLLO_KT400,
+	VIA_APOLLO_P4M266,
 	SIS_GENERIC,
 	AMD_GENERIC,
 	AMD_IRONGATE,
@@ -81,6 +85,9 @@
 	SVWRKS_HE,
 	SVWRKS_LE,
 	SVWRKS_GENERIC,
+	NVIDIA_NFORCE,
+	NVIDIA_NFORCE2,
+	NVIDIA_GENERIC,
 	HP_ZX1,
 };
 
diff -urN linux-2.4.21-bk3/include/linux/dcache.h linux-2.4.21-bk4/include/linux/dcache.h
--- linux-2.4.21-bk3/include/linux/dcache.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/dcache.h	2003-07-08 02:59:49.000000000 -0700
@@ -219,6 +219,7 @@
 
 /* appendix may either be NULL or be used for transname suffixes */
 extern struct dentry * d_lookup(struct dentry *, struct qstr *);
+extern struct dentry * __d_lookup(struct dentry *, struct qstr *);
 
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
diff -urN linux-2.4.21-bk3/include/linux/dqblk_v1.h linux-2.4.21-bk4/include/linux/dqblk_v1.h
--- linux-2.4.21-bk3/include/linux/dqblk_v1.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/dqblk_v1.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,18 @@
+/*
+ *	File with in-memory structures of old quota format
+ */
+
+#ifndef _LINUX_DQBLK_V1_H
+#define _LINUX_DQBLK_V1_H
+
+/* Id of quota format */
+#define QFMT_VFS_OLD 1
+
+/* Root squash turned on */
+#define V1_DQF_RSQUASH 1
+
+/* Special information about quotafile */
+struct v1_mem_dqinfo {
+};
+
+#endif	/* _LINUX_DQBLK_V1_H */
diff -urN linux-2.4.21-bk3/include/linux/dqblk_v2.h linux-2.4.21-bk4/include/linux/dqblk_v2.h
--- linux-2.4.21-bk3/include/linux/dqblk_v2.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/dqblk_v2.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,20 @@
+/*
+ *	Definitions of structures for vfsv0 quota format
+ */
+
+#ifndef _LINUX_DQBLK_V2_H
+#define _LINUX_DQBLK_V2_H
+
+#include <linux/types.h>
+
+/* id numbers of quota format */
+#define QFMT_VFS_V0 2
+
+/* Inmemory copy of version specific information */
+struct v2_mem_dqinfo {
+	unsigned int dqi_blocks;
+	unsigned int dqi_free_blk;
+	unsigned int dqi_free_entry;
+};
+
+#endif /* _LINUX_DQBLK_V2_H */
diff -urN linux-2.4.21-bk3/include/linux/dqblk_xfs.h linux-2.4.21-bk4/include/linux/dqblk_xfs.h
--- linux-2.4.21-bk3/include/linux/dqblk_xfs.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/dqblk_xfs.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef _LINUX_DQBLK_XFS_H
+#define _LINUX_DQBLK_XFS_H
+
+#include <linux/types.h>
+
+/*
+ * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
+ */
+
+#define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
+#define Q_XQUOTAON	XQM_CMD(0x1)	/* enable accounting/enforcement */
+#define Q_XQUOTAOFF	XQM_CMD(0x2)	/* disable accounting/enforcement */
+#define Q_XGETQUOTA	XQM_CMD(0x3)	/* get disk limits and usage */
+#define Q_XSETQLIM	XQM_CMD(0x4)	/* set disk limits */
+#define Q_XGETQSTAT	XQM_CMD(0x5)	/* get quota subsystem status */
+#define Q_XQUOTARM	XQM_CMD(0x6)	/* free disk space used by dquots */
+
+/*
+ * fs_disk_quota structure:
+ *
+ * This contains the current quota information regarding a user/proj/group.
+ * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of
+ * 512 bytes.
+ */
+#define FS_DQUOT_VERSION	1	/* fs_disk_quota.d_version */
+typedef struct fs_disk_quota {
+	__s8		d_version;	/* version of this structure */
+	__s8		d_flags;	/* XFS_{USER,PROJ,GROUP}_QUOTA */
+	__u16		d_fieldmask;	/* field specifier */
+	__u32		d_id;		/* user, project, or group ID */
+	__u64		d_blk_hardlimit;/* absolute limit on disk blks */
+	__u64		d_blk_softlimit;/* preferred limit on disk blks */
+	__u64		d_ino_hardlimit;/* maximum # allocated inodes */
+	__u64		d_ino_softlimit;/* preferred inode limit */
+	__u64		d_bcount;	/* # disk blocks owned by the user */
+	__u64		d_icount;	/* # inodes owned by the user */
+	__s32		d_itimer;	/* zero if within inode limits */
+					/* if not, we refuse service */
+	__s32		d_btimer;	/* similar to above; for disk blocks */
+	__u16	  	d_iwarns;       /* # warnings issued wrt num inodes */
+	__u16	  	d_bwarns;       /* # warnings issued wrt disk blocks */
+	__s32		d_padding2;	/* padding2 - for future use */
+	__u64		d_rtb_hardlimit;/* absolute limit on realtime blks */
+	__u64		d_rtb_softlimit;/* preferred limit on RT disk blks */
+	__u64		d_rtbcount;	/* # realtime blocks owned */
+	__s32		d_rtbtimer;	/* similar to above; for RT disk blks */
+	__u16	  	d_rtbwarns;     /* # warnings issued wrt RT disk blks */
+	__s16		d_padding3;	/* padding3 - for future use */	
+	char		d_padding4[8];	/* yet more padding */
+} fs_disk_quota_t;
+
+/*
+ * These fields are sent to Q_XSETQLIM to specify fields that need to change.
+ */
+#define FS_DQ_ISOFT	(1<<0)
+#define FS_DQ_IHARD	(1<<1)
+#define FS_DQ_BSOFT	(1<<2)
+#define FS_DQ_BHARD 	(1<<3)
+#define FS_DQ_RTBSOFT	(1<<4)
+#define FS_DQ_RTBHARD	(1<<5)
+#define FS_DQ_LIMIT_MASK	(FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \
+				 FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD)
+/*
+ * These timers can only be set in super user's dquot. For others, timers are
+ * automatically started and stopped. Superusers timer values set the limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}TIMELIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BTIMER	(1<<6)
+#define FS_DQ_ITIMER	(1<<7)
+#define FS_DQ_RTBTIMER 	(1<<8)
+#define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
+
+/*
+ * The following constants define the default amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure).  These may be modified by the quotactl(2)
+ * system call with the Q_XSETQLIM command.
+ */
+#define	DQ_FTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+#define	DQ_BTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+
+/*
+ * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
+ */
+#define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
+#define XFS_QUOTA_UDQ_ENFD	(1<<1)  /* user quota limits enforcement */
+#define XFS_QUOTA_GDQ_ACCT	(1<<2)  /* group quota accounting */
+#define XFS_QUOTA_GDQ_ENFD	(1<<3)  /* group quota limits enforcement */
+
+#define XFS_USER_QUOTA		(1<<0)	/* user quota type */
+#define XFS_PROJ_QUOTA		(1<<1)	/* (IRIX) project quota type */
+#define XFS_GROUP_QUOTA		(1<<2)	/* group quota type */
+
+/*
+ * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
+ * Provides a centralized way to get meta infomation about the quota subsystem.
+ * eg. space taken up for user and group quotas, number of dquots currently
+ * incore.
+ */
+#define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
+
+/*
+ * Some basic infomation about 'quota files'.
+ */
+typedef struct fs_qfilestat {
+	__u64		qfs_ino;	/* inode number */
+	__u64		qfs_nblks;	/* number of BBs 512-byte-blks */
+	__u32		qfs_nextents;	/* number of extents */
+} fs_qfilestat_t;
+
+typedef struct fs_quota_stat {
+	__s8		qs_version;	/* version number for future changes */
+	__u16		qs_flags;	/* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+	__s8		qs_pad;		/* unused */
+	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
+	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
+	__u32		qs_incoredqs;	/* number of dquots incore */
+	__s32		qs_btimelimit;  /* limit for blks timer */	
+	__s32		qs_itimelimit;  /* limit for inodes timer */	
+	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
+	__u16		qs_bwarnlimit;	/* limit for num warnings */
+	__u16		qs_iwarnlimit;	/* limit for num warnings */
+} fs_quota_stat_t;
+
+#endif	/* _LINUX_DQBLK_XFS_H */
diff -urN linux-2.4.21-bk3/include/linux/fs.h linux-2.4.21-bk4/include/linux/fs.h
--- linux-2.4.21-bk3/include/linux/fs.h	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/fs.h	2003-07-08 02:59:49.000000000 -0700
@@ -455,6 +455,7 @@
 	unsigned long		i_blksize;
 	unsigned long		i_blocks;
 	unsigned long		i_version;
+	unsigned short          i_bytes;
 	struct semaphore	i_sem;
 	struct rw_semaphore	i_alloc_sem;
 	struct semaphore	i_zombie;
@@ -516,6 +517,39 @@
 	} u;
 };
 
+static inline void inode_add_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks += bytes >> 9;
+	bytes &= 511;
+	inode->i_bytes += bytes;
+	if (inode->i_bytes >= 512) {
+		inode->i_blocks++;
+		inode->i_bytes -= 512;
+	}
+}
+
+static inline void inode_sub_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks -= bytes >> 9;
+	bytes &= 511;
+	if (inode->i_bytes < bytes) {
+		inode->i_blocks--;
+		inode->i_bytes += 512;
+	}
+	inode->i_bytes -= bytes;
+}
+
+static inline loff_t inode_get_bytes(struct inode *inode)
+{
+	return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes;
+}
+
+static inline void inode_set_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks = bytes >> 9;
+	inode->i_bytes = bytes & 511;
+}
+
 struct fown_struct {
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
 	uid_t uid, euid;	/* uid/euid of process setting the owner */
@@ -659,20 +693,8 @@
 	struct qstr last;
 	unsigned int flags;
 	int last_type;
-};
-
-#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
-#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
-
-struct quota_mount_options
-{
-	unsigned int flags;			/* Flags for diskquotas on this device */
-	struct semaphore dqio_sem;		/* lock device while I/O in progress */
-	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
-	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
-	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
-	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
-	char rsquash[MAXQUOTAS];		/* for quotas threat root as any other user */
+	struct dentry *old_dentry;
+	struct vfsmount *old_mnt;
 };
 
 /*
@@ -722,6 +744,7 @@
 	struct file_system_type	*s_type;
 	struct super_operations	*s_op;
 	struct dquot_operations	*dq_op;
+	struct quotactl_ops	*s_qcop;
 	unsigned long		s_flags;
 	unsigned long		s_magic;
 	struct dentry		*s_root;
@@ -736,7 +759,7 @@
 
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
-	struct quota_mount_options s_dquot;	/* Diskquota specific options */
+	struct quota_info	s_dquot;	/* Diskquota specific options */
 
 	union {
 		struct minix_sb_info	minix_sb;
@@ -960,16 +983,6 @@
 	__mark_inode_dirty(inode, I_DIRTY_PAGES);
 }
 
-struct dquot_operations {
-	void (*initialize) (struct inode *, short);
-	void (*drop) (struct inode *);
-	int (*alloc_block) (struct inode *, unsigned long, char);
-	int (*alloc_inode) (const struct inode *, unsigned long);
-	void (*free_block) (struct inode *, unsigned long);
-	void (*free_inode) (const struct inode *, unsigned long);
-	int (*transfer) (struct inode *, struct iattr *);
-};
-
 struct file_system_type {
 	const char *name;
 	int fs_flags;
@@ -1328,6 +1341,7 @@
  *  - require a directory
  *  - ending slashes ok even for nonexistent files
  *  - internal "there are more path compnents" flag
+ *  - locked when lookup done with dcache_lock held
  */
 #define LOOKUP_FOLLOW		(1)
 #define LOOKUP_DIRECTORY	(2)
@@ -1335,6 +1349,7 @@
 #define LOOKUP_POSITIVE		(8)
 #define LOOKUP_PARENT		(16)
 #define LOOKUP_NOALT		(32)
+
 /*
  * Type of the last component on LOOKUP_PARENT
  */
@@ -1362,7 +1377,6 @@
 extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
 
 extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
-extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
 extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
diff -urN linux-2.4.21-bk3/include/linux/fs_struct.h linux-2.4.21-bk4/include/linux/fs_struct.h
--- linux-2.4.21-bk3/include/linux/fs_struct.h	2001-07-13 15:10:44.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/fs_struct.h	2003-07-08 02:59:49.000000000 -0700
@@ -32,10 +32,12 @@
 	struct dentry *old_root;
 	struct vfsmount *old_rootmnt;
 	write_lock(&fs->lock);
+	spin_lock(&dcache_lock);
 	old_root = fs->root;
 	old_rootmnt = fs->rootmnt;
 	fs->rootmnt = mntget(mnt);
 	fs->root = dget(dentry);
+	spin_unlock(&dcache_lock);
 	write_unlock(&fs->lock);
 	if (old_root) {
 		dput(old_root);
@@ -55,10 +57,12 @@
 	struct dentry *old_pwd;
 	struct vfsmount *old_pwdmnt;
 	write_lock(&fs->lock);
+	spin_lock(&dcache_lock);
 	old_pwd = fs->pwd;
 	old_pwdmnt = fs->pwdmnt;
 	fs->pwdmnt = mntget(mnt);
 	fs->pwd = dget(dentry);
+	spin_unlock(&dcache_lock);
 	write_unlock(&fs->lock);
 	if (old_pwd) {
 		dput(old_pwd);
diff -urN linux-2.4.21-bk3/include/linux/mtd/mtd.h linux-2.4.21-bk4/include/linux/mtd/mtd.h
--- linux-2.4.21-bk3/include/linux/mtd/mtd.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/mtd/mtd.h	2003-07-08 02:59:49.000000000 -0700
@@ -287,10 +287,11 @@
 #define MTD_DEBUG_LEVEL3	(3)	/* Noisy   */
 
 #ifdef CONFIG_MTD_DEBUG
-#define DEBUG(n, args...)			\
-	if (n <=  CONFIG_MTD_DEBUG_VERBOSE) {	\
-		printk(KERN_INFO args);	\
-	}
+#define DEBUG(n, args...)				\
+ 	do {						\
+		if (n <= CONFIG_MTD_DEBUG_VERBOSE)	\
+			printk(KERN_INFO args);		\
+	} while(0)
 #else /* CONFIG_MTD_DEBUG */
 #define DEBUG(n, args...)
 #endif /* CONFIG_MTD_DEBUG */
diff -urN linux-2.4.21-bk3/include/linux/quota.h linux-2.4.21-bk4/include/linux/quota.h
--- linux-2.4.21-bk3/include/linux/quota.h	2001-11-22 10:38:31.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/quota.h	2003-07-08 02:59:49.000000000 -0700
@@ -40,30 +40,22 @@
 #define _LINUX_QUOTA_
 
 #include <linux/errno.h>
+#include <linux/types.h>
 
-/*
- * Convert diskblocks to blocks and the other way around.
- */
-#define dbtob(num) (num << BLOCK_SIZE_BITS)
-#define btodb(num) (num >> BLOCK_SIZE_BITS)
+#define __DQUOT_VERSION__	"dquot_6.5.1"
+#define __DQUOT_NUM_VERSION__	6*10000+5*100+1
 
-/*
- * Convert count of filesystem blocks to diskquota blocks, meant
- * for filesystems where i_blksize != BLOCK_SIZE
- */
-#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
+typedef __u64 qsize_t;          /* Type in which we store sizes */
 
-/*
- * Definitions for disk quotas imposed on the average user
- * (big brother finally hits Linux).
- *
- * The following constants define the amount of time given a user
- * before the soft limits are treated as hard limits (usually resulting
- * in an allocation failure). The timer is started when the user crosses
- * their soft limit, it is reset when they go below their soft limit.
- */
-#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
-#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+/* Size of blocks in which are counted size limits */
+#define QUOTABLOCK_BITS 10
+#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
+
+/* Conversion routines from and to quota blocks */
+#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
+#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
+#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
 
 #define MAXQUOTAS 2
 #define USRQUOTA  0		/* element used for user quotas */
@@ -78,9 +70,6 @@
 	"undefined", \
 };
 
-#define QUOTAFILENAME "quota"
-#define QUOTAGROUP "staff"
-
 /*
  * Command definitions for the 'quotactl' system call.
  * The commands are broken into a main command defined below
@@ -91,61 +80,122 @@
 #define SUBCMDSHIFT 8
 #define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
 
-#define Q_QUOTAON  0x0100	/* enable quotas */
-#define Q_QUOTAOFF 0x0200	/* disable quotas */
-#define Q_GETQUOTA 0x0300	/* get limits and usage */
-#define Q_SETQUOTA 0x0400	/* set limits and usage */
-#define Q_SETUSE   0x0500	/* set usage */
-#define Q_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
-#define Q_SETQLIM  0x0700	/* set limits */
-#define Q_GETSTATS 0x0800	/* get collected stats */
-#define Q_RSQUASH  0x1000	/* set root_squash option */
-
-/*
- * The following structure defines the format of the disk quota file
- * (as it appears on disk) - the file is an array of these structures
- * indexed by user or group number.
+#define Q_SYNC     0x800001	/* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON  0x800002	/* turn quotas on */
+#define Q_QUOTAOFF 0x800003	/* turn quotas off */
+#define Q_GETFMT   0x800004	/* get quota format used on given filesystem */
+#define Q_GETINFO  0x800005	/* get information about quota files */
+#define Q_SETINFO  0x800006	/* set information about quota files */
+#define Q_GETQUOTA 0x800007	/* get user quota structure */
+#define Q_SETQUOTA 0x800008	/* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
  */
-struct dqblk {
+#define QIF_BLIMITS	1
+#define QIF_SPACE	2
+#define QIF_ILIMITS	4
+#define QIF_INODES	8
+#define QIF_BTIME	16
+#define QIF_ITIME	32
+#define QIF_LIMITS	(QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE	(QIF_SPACE | QIF_INODES)
+#define QIF_TIMES	(QIF_BTIME | QIF_ITIME)
+#define QIF_ALL		(QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+	__u64 dqb_bhardlimit;
+	__u64 dqb_bsoftlimit;
+	__u64 dqb_curspace;
+	__u64 dqb_ihardlimit;
+	__u64 dqb_isoftlimit;
+	__u64 dqb_curinodes;
+	__u64 dqb_btime;
+	__u64 dqb_itime;
+	__u32 dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE	1
+#define IIF_IGRACE	2
+#define IIF_FLAGS	4
+#define IIF_ALL		(IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+	__u64 dqi_bgrace;
+	__u64 dqi_igrace;
+	__u32 dqi_flags;
+	__u32 dqi_valid;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/dqblk_xfs.h>
+#include <linux/dqblk_v1.h>
+#include <linux/dqblk_v2.h>
+
+/*
+ * Data for one user/group kept in memory
+ */
+struct mem_dqblk {
 	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
 	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
-	__u32 dqb_curblocks;	/* current block count */
+	qsize_t dqb_curspace;	/* current used space */
 	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
 	__u32 dqb_isoftlimit;	/* preferred inode limit */
 	__u32 dqb_curinodes;	/* current # allocated inodes */
-	time_t dqb_btime;		/* time limit for excessive disk use */
-	time_t dqb_itime;		/* time limit for excessive inode use */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive inode use */
 };
 
 /*
- * Shorthand notation.
+ * Data for one quotafile kept in memory
  */
-#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
-#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
-#define	dq_curblocks	dq_dqb.dqb_curblocks
-#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
-#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
-#define	dq_curinodes	dq_dqb.dqb_curinodes
-#define	dq_btime	dq_dqb.dqb_btime
-#define	dq_itime	dq_dqb.dqb_itime
+struct quota_format_type;
+
+struct mem_dqinfo {
+	struct quota_format_type *dqi_format;
+	int dqi_flags;
+	unsigned int dqi_bgrace;
+	unsigned int dqi_igrace;
+	union {
+		struct v1_mem_dqinfo v1_i;
+		struct v2_mem_dqinfo v2_i;
+	} u;
+};
+
+#define DQF_MASK 0xffff		/* Mask for format specific flags */
+#define DQF_INFO_DIRTY 0x10000  /* Is info dirty? */
+#define DQF_ANY_DQUOT_DIRTY 0x20000	/* Is any dquot dirty? */
 
-#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
+extern inline void mark_info_dirty(struct mem_dqinfo *info)
+{
+	info->dqi_flags |= DQF_INFO_DIRTY;
+}
+
+#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY)
+
+#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\
+			      (info)->dqi_flags & DQF_ANY_DQUOT_DIRTY)
+
+#define sb_dqopt(sb) (&(sb)->s_dquot)
 
 struct dqstats {
-	__u32 lookups;
-	__u32 drops;
-	__u32 reads;
-	__u32 writes;
-	__u32 cache_hits;
-	__u32 allocated_dquots;
-	__u32 free_dquots;
-	__u32 syncs;
+	int lookups;
+	int drops;
+	int reads;
+	int writes;
+	int cache_hits;
+	int allocated_dquots;
+	int free_dquots;
+	int syncs;
 };
 
-#ifdef __KERNEL__
-
-extern int nr_dquots, nr_free_dquots;
-extern int dquot_root_squash;
+extern struct dqstats dqstats;
 
 #define NR_DQHASH 43            /* Just an arbitrary number */
 
@@ -162,37 +212,113 @@
 	struct list_head dq_free;	/* Free list element */
 	wait_queue_head_t dq_wait_lock;	/* Pointer to waitqueue on dquot lock */
 	wait_queue_head_t dq_wait_free;	/* Pointer to waitqueue for quota to be unused */
-	int dq_count;			/* Reference count */
+	int dq_count;			/* Use count */
+	int dq_dup_ref;			/* Number of duplicated refences */
 
 	/* fields after this point are cleared when invalidating */
 	struct super_block *dq_sb;	/* superblock this applies to */
 	unsigned int dq_id;		/* ID this applies to (uid, gid) */
 	kdev_t dq_dev;			/* Device this applies to */
+	loff_t dq_off;			/* Offset of dquot on disk */
 	short dq_type;			/* Type of quota */
 	short dq_flags;			/* See DQ_* */
 	unsigned long dq_referenced;	/* Number of times this dquot was 
 					   referenced during its lifetime */
-	struct dqblk dq_dqb;		/* Diskquota usage */
+	struct mem_dqblk dq_dqb;	/* Diskquota usage */
 };
 
 #define NODQUOT (struct dquot *)NULL
 
-/*
- * Flags used for set_dqblk.
- */
-#define SET_QUOTA         0x02
-#define SET_USE           0x04
-#define SET_QLIMIT        0x08
-
 #define QUOTA_OK          0
 #define NO_QUOTA          1
 
+/* Operations which must be implemented by each quota format */
+struct quota_format_ops {
+	int (*check_quota_file)(struct super_block *sb, int type);	/* Detect whether file is in our format */
+	int (*read_file_info)(struct super_block *sb, int type);	/* Read main info about file - called on quotaon() */
+	int (*write_file_info)(struct super_block *sb, int type);	/* Write main info about file */
+	int (*free_file_info)(struct super_block *sb, int type);	/* Called on quotaoff() */
+	int (*read_dqblk)(struct dquot *dquot);		/* Read structure for one user */
+	int (*commit_dqblk)(struct dquot *dquot);	/* Write (or delete) structure for one user */
+};
+
+/* Operations working with dquots */
+struct dquot_operations {
+	void (*initialize) (struct inode *, int);
+	void (*drop) (struct inode *);
+	int (*alloc_space) (struct inode *, qsize_t, int);
+	int (*alloc_inode) (const struct inode *, unsigned long);
+	void (*free_space) (struct inode *, qsize_t);
+	void (*free_inode) (const struct inode *, unsigned long);
+	int (*transfer) (struct inode *, struct iattr *);
+};
+
+/* Operations handling requests from userspace */
+struct quotactl_ops {
+	int (*quota_on)(struct super_block *, int, int, char *);
+	int (*quota_off)(struct super_block *, int);
+	int (*quota_sync)(struct super_block *, int);
+	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
+	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
+	int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+	int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
+	int (*set_xstate)(struct super_block *, unsigned int, int);
+	int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+	int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+};
+
+struct quota_format_type {
+	int qf_fmt_id;	/* Quota format id */
+	struct quota_format_ops *qf_ops;	/* Operations of format */
+	struct module *qf_owner;		/* Module implementing quota format */
+	struct quota_format_type *qf_next;
+};
+
+#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
+
+struct quota_info {
+	unsigned int flags;			/* Flags for diskquotas on this device */
+	struct semaphore dqio_sem;		/* lock device while I/O in progress */
+	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
+	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
+	struct mem_dqinfo info[MAXQUOTAS];	/* Information for each quota type */
+	struct quota_format_ops *ops[MAXQUOTAS];	/* Operations for each type */
+};
+
+/* Inline would be better but we need to dereference super_block which is not defined yet */
+#define mark_dquot_dirty(dquot) do {\
+	dquot->dq_flags |= DQ_MOD;\
+	sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\
+} while (0)
+
+#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD)
+
+static inline int is_enabled(struct quota_info *dqopt, int type)
+{
+	switch (type) {
+		case USRQUOTA:
+			return dqopt->flags & DQUOT_USR_ENABLED;
+		case GRPQUOTA:
+			return dqopt->flags & DQUOT_GRP_ENABLED;
+	}
+	return 0;
+}
+
+#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA))
+
+#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type))
+
+int register_quota_format(struct quota_format_type *fmt);
+void unregister_quota_format(struct quota_format_type *fmt);
+
 #else
 
 # /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
-long quotactl __P ((int, const char *, int, caddr_t));
+long quotactl __P ((unsigned int, const char *, int, caddr_t));
 __END_DECLS
 
 #endif /* __KERNEL__ */
diff -urN linux-2.4.21-bk3/include/linux/quotacompat.h linux-2.4.21-bk4/include/linux/quotacompat.h
--- linux-2.4.21-bk3/include/linux/quotacompat.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/quotacompat.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,86 @@
+/*
+ *	Definition of symbols used for backward compatible interface
+ */
+
+#ifndef _LINUX_QUOTACOMPAT_
+#define _LINUX_QUOTACOMPAT_
+
+#include <linux/types.h>
+#include <linux/quota.h>
+
+struct v1c_mem_dqblk {
+	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
+	__u32 dqb_curblocks;	/* current block count */
+	__u32 dqb_ihardlimit;	/* maximum # allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive files */
+};
+
+struct v1c_dqstats {
+	__u32 lookups;
+	__u32 drops;
+	__u32 reads;
+	__u32 writes;
+	__u32 cache_hits;
+	__u32 allocated_dquots;
+	__u32 free_dquots;
+	__u32 syncs;
+};
+
+struct v2c_mem_dqblk {
+	unsigned int dqb_ihardlimit;
+	unsigned int dqb_isoftlimit;
+	unsigned int dqb_curinodes;
+	unsigned int dqb_bhardlimit;
+	unsigned int dqb_bsoftlimit;
+	qsize_t dqb_curspace;
+	__kernel_time_t dqb_btime;
+	__kernel_time_t dqb_itime;
+};
+
+struct v2c_mem_dqinfo {
+	unsigned int dqi_bgrace;
+	unsigned int dqi_igrace;
+	unsigned int dqi_flags;
+	unsigned int dqi_blocks;
+	unsigned int dqi_free_blk;
+	unsigned int dqi_free_entry;
+};
+
+struct v2c_dqstats {
+	__u32 lookups;
+	__u32 drops;
+	__u32 reads;
+	__u32 writes;
+	__u32 cache_hits;
+	__u32 allocated_dquots;
+	__u32 free_dquots;
+	__u32 syncs;
+	__u32 version;
+};
+
+#define Q_COMP_QUOTAON  0x0100	/* enable quotas */
+#define Q_COMP_QUOTAOFF 0x0200	/* disable quotas */
+#define Q_COMP_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
+
+#define Q_V1_GETQUOTA 0x0300	/* get limits and usage */
+#define Q_V1_SETQUOTA 0x0400	/* set limits and usage */
+#define Q_V1_SETUSE   0x0500	/* set usage */
+#define Q_V1_SETQLIM  0x0700	/* set limits */
+#define Q_V1_GETSTATS 0x0800	/* get collected stats */
+#define Q_V1_RSQUASH  0x1000	/* set root_squash option */
+
+#define Q_V2_SETQLIM  0x0700	/* set limits */
+#define Q_V2_GETINFO  0x0900	/* get info about quotas - graces, flags... */
+#define Q_V2_SETINFO  0x0A00	/* set info about quotas */
+#define Q_V2_SETGRACE 0x0B00	/* set inode and block grace */
+#define Q_V2_SETFLAGS 0x0C00	/* set flags for quota */
+#define Q_V2_GETQUOTA 0x0D00	/* get limits and usage */
+#define Q_V2_SETQUOTA 0x0E00	/* set limits and usage */
+#define Q_V2_SETUSE   0x0F00	/* set usage */
+#define Q_V2_GETSTATS 0x1100	/* get collected stats */
+
+#endif
diff -urN linux-2.4.21-bk3/include/linux/quotaio_v1.h linux-2.4.21-bk4/include/linux/quotaio_v1.h
--- linux-2.4.21-bk3/include/linux/quotaio_v1.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/quotaio_v1.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,33 @@
+#ifndef _LINUX_QUOTAIO_V1_H
+#define _LINUX_QUOTAIO_V1_H
+
+#include <linux/types.h>
+
+/*
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct v1_disk_dqblk {
+	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
+	__u32 dqb_curblocks;	/* current block count */
+	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive inode use */
+};
+
+#define v1_dqoff(UID)      ((loff_t)((UID) * sizeof (struct v1_disk_dqblk)))
+
+#endif	/* _LINUX_QUOTAIO_V1_H */
diff -urN linux-2.4.21-bk3/include/linux/quotaio_v2.h linux-2.4.21-bk4/include/linux/quotaio_v2.h
--- linux-2.4.21-bk3/include/linux/quotaio_v2.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-bk4/include/linux/quotaio_v2.h	2003-07-08 02:59:49.000000000 -0700
@@ -0,0 +1,79 @@
+/*
+ *	Definitions of structures for vfsv0 quota format
+ */
+
+#ifndef _LINUX_QUOTAIO_V2_H
+#define _LINUX_QUOTAIO_V2_H
+
+#include <linux/types.h>
+#include <linux/quota.h>
+
+/*
+ * Definitions of magics and versions of current quota files
+ */
+#define V2_INITQMAGICS {\
+	0xd9c01f11,	/* USRQUOTA */\
+	0xd9c01927	/* GRPQUOTA */\
+}
+
+#define V2_INITQVERSIONS {\
+	0,		/* USRQUOTA */\
+	0		/* GRPQUOTA */\
+}
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is a radix tree whose leaves point
+ * to blocks of these structures.
+ */
+struct v2_disk_dqblk {
+	__u32 dqb_id;		/* id this quota applies to */
+	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	__u32 dqb_bhardlimit;	/* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+	__u64 dqb_curspace;	/* current space occupied (in bytes) */
+	__u64 dqb_btime;	/* time limit for excessive disk use */
+	__u64 dqb_itime;	/* time limit for excessive inode use */
+};
+
+/*
+ * Here are header structures as written on disk and their in-memory copies
+ */
+/* First generic header */
+struct v2_disk_dqheader {
+	__u32 dqh_magic;	/* Magic number identifying file */
+	__u32 dqh_version;	/* File version */
+};
+
+/* Header with type and version specific information */
+struct v2_disk_dqinfo {
+	__u32 dqi_bgrace;	/* Time before block soft limit becomes hard limit */
+	__u32 dqi_igrace;	/* Time before inode soft limit becomes hard limit */
+	__u32 dqi_flags;	/* Flags for quotafile (DQF_*) */
+	__u32 dqi_blocks;	/* Number of blocks in file */
+	__u32 dqi_free_blk;	/* Number of first free block in the list */
+	__u32 dqi_free_entry;	/* Number of block with at least one free entry */
+};
+
+/*
+ *  Structure of header of block with quota structures. It is padded to 16 bytes so
+ *  there will be space for exactly 18 quota-entries in a block
+ */
+struct v2_disk_dqdbheader {
+	__u32 dqdh_next_free;	/* Number of next block with free entry */
+	__u32 dqdh_prev_free;	/* Number of previous block with free entry */
+	__u16 dqdh_entries;	/* Number of valid entries in block */
+	__u16 dqdh_pad1;
+	__u32 dqdh_pad2;
+};
+
+#define V2_DQINFOOFF	sizeof(struct v2_disk_dqheader)	/* Offset of info header in file */
+#define V2_DQBLKSIZE_BITS	10
+#define V2_DQBLKSIZE	(1 << V2_DQBLKSIZE_BITS)	/* Size of block with quota structures */
+#define V2_DQTREEOFF	1		/* Offset of tree in file in blocks */
+#define V2_DQTREEDEPTH	4		/* Depth of quota tree */
+#define V2_DQSTRINBLK	((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))	/* Number of entries in one blocks */
+
+#endif /* _LINUX_QUOTAIO_V2_H */
diff -urN linux-2.4.21-bk3/include/linux/quotaops.h linux-2.4.21-bk4/include/linux/quotaops.h
--- linux-2.4.21-bk3/include/linux/quotaops.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/quotaops.h	2003-07-08 02:59:49.000000000 -0700
@@ -20,15 +20,16 @@
 /*
  * declaration of quota_function calls in kernel.
  */
-extern void dquot_initialize(struct inode *inode, short type);
+extern void sync_dquots_dev(kdev_t dev, int type);
+extern void sync_dquots_sb(struct super_block *sb, int type);
+
+extern void dquot_initialize(struct inode *inode, int type);
 extern void dquot_drop(struct inode *inode);
-extern int  quota_off(struct super_block *sb, short type);
-extern int  sync_dquots(kdev_t dev, short type);
 
-extern int  dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc);
+extern int  dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
 extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
 
-extern void dquot_free_block(struct inode *inode, unsigned long number);
+extern void dquot_free_space(struct inode *inode, qsize_t number);
 extern void dquot_free_inode(const struct inode *inode, unsigned long number);
 
 extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
@@ -36,7 +37,11 @@
 /*
  * Operations supported for diskquotas.
  */
-#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED))
+extern struct dquot_operations dquot_operations;
+extern struct quotactl_ops vfs_quotactl_ops;
+
+#define sb_dquot_ops (&dquot_operations)
+#define sb_quotactl_ops (&vfs_quotactl_ops)
 
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
@@ -59,50 +64,50 @@
 	unlock_kernel();
 }
 
-static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb)) {
-		/* Number of used blocks is updated in alloc_block() */
-		if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) {
+		/* Used space is updated in alloc_space() */
+		if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) {
 			unlock_kernel();
 			return 1;
 		}
 	}
 	else
-		inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-static __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
 	int ret;
-        if (!(ret =  DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr)))
+        if (!(ret =  DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr)))
 		mark_inode_dirty(inode);
 	return ret;
 }
 
-static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb)) {
-		/* Number of used blocks is updated in alloc_block() */
-		if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) {
+		/* Used space is updated in alloc_space() */
+		if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) {
 			unlock_kernel();
 			return 1;
 		}
 	}
 	else
-		inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-static __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
 	int ret;
-	if (!(ret = DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr)))
+	if (!(ret = DQUOT_ALLOC_SPACE_NODIRTY(inode, nr)))
 		mark_inode_dirty(inode);
 	return ret;
 }
@@ -121,19 +126,19 @@
 	return 0;
 }
 
-static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb))
-		inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize));
+		inode->i_sb->dq_op->free_space(inode, nr);
 	else
-		inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_sub_bytes(inode, nr);
 	unlock_kernel();
 }
 
-static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+	DQUOT_FREE_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 }
 
@@ -159,63 +164,85 @@
 	return 0;
 }
 
-#define DQUOT_SYNC(dev)	sync_dquots(dev, -1)
-#define DQUOT_OFF(sb)	quota_off(sb, -1)
+#define DQUOT_SYNC_DEV(dev)	sync_dquots_dev(dev, -1)
+#define DQUOT_SYNC_SB(sb)	sync_dquots_sb(sb, -1)
+
+static __inline__ int DQUOT_OFF(struct super_block *sb)
+{
+	int ret = -ENOSYS;
+
+	lock_kernel();
+	if (sb->s_qcop && sb->s_qcop->quota_off)
+		ret = sb->s_qcop->quota_off(sb, -1);
+	unlock_kernel();
+	return ret;
+}
 
 #else
 
 /*
  * NO-OP when quota not configured.
  */
+#define sb_dquot_ops				(NULL)
+#define sb_quotactl_ops				(NULL)
 #define DQUOT_INIT(inode)			do { } while(0)
 #define DQUOT_DROP(inode)			do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)		(0)
 #define DQUOT_FREE_INODE(inode)			do { } while(0)
-#define DQUOT_SYNC(dev)				do { } while(0)
+#define DQUOT_SYNC_DEV(dev)			do { } while(0)
+#define DQUOT_SYNC_SB(sb)			do { } while(0)
 #define DQUOT_OFF(sb)				do { } while(0)
 #define DQUOT_TRANSFER(inode, iattr)		(0)
-extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-extern __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
+extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr);
+	DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr);
+	DQUOT_ALLOC_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 	return 0;
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_sub_bytes(inode, nr);
 	unlock_kernel();
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
+extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+	DQUOT_FREE_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 }	
 
 #endif /* CONFIG_QUOTA */
+
+#define DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr)	DQUOT_PREALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_PREALLOC_BLOCK(inode, nr)	DQUOT_PREALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_ALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_FREE_BLOCK_NODIRTY(inode, nr) DQUOT_FREE_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+
 #endif /* _LINUX_QUOTAOPS_ */
diff -urN linux-2.4.21-bk3/include/linux/sysctl.h linux-2.4.21-bk4/include/linux/sysctl.h
--- linux-2.4.21-bk3/include/linux/sysctl.h	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/include/linux/sysctl.h	2003-07-08 02:59:49.000000000 -0700
@@ -550,7 +550,7 @@
 	FS_STATINODE=2,
 	FS_MAXINODE=3,	/* int:maximum number of inodes that can be allocated */
 	FS_NRDQUOT=4,	/* int:current number of allocated dquots */
-	FS_MAXDQUOT=5,	/* int:maximum number of dquots that can be allocated */
+	/* was FS_MAXDQUOT */
 	FS_NRFILE=6,	/* int:current number of allocated filedescriptors */
 	FS_MAXFILE=7,	/* int:maximum number of filedescriptors that can be allocated */
 	FS_DENTRY=8,
@@ -561,6 +561,20 @@
 	FS_LEASES=13,	/* int: leases enabled */
 	FS_DIR_NOTIFY=14,	/* int: directory notification enabled */
 	FS_LEASE_TIME=15,	/* int: maximum time to wait for a lease break */
+	FS_DQSTATS=16,	/* dir: disc quota usage statistics */
+	FS_XFS=17,	/* struct: control xfs parameters */
+};
+
+/* /proc/sys/fs/quota/ */
+enum {
+	FS_DQ_LOOKUPS = 1,
+	FS_DQ_DROPS = 2,
+	FS_DQ_READS = 3,
+	FS_DQ_WRITES = 4,
+	FS_DQ_CACHE_HITS = 5,
+	FS_DQ_ALLOCATED = 6,
+	FS_DQ_FREE = 7,
+	FS_DQ_SYNCS = 8,
 };
 
 /* CTL_DEBUG names: */
diff -urN linux-2.4.21-bk3/kernel/fork.c linux-2.4.21-bk4/kernel/fork.c
--- linux-2.4.21-bk3/kernel/fork.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.21-bk4/kernel/fork.c	2003-07-08 02:59:49.000000000 -0700
@@ -448,6 +448,11 @@
 		goto out;
 	}
 
+	/*
+	 * Note: we may be using current for both targets (See exec.c)
+	 * This works because we cache current->files (old) as oldf. Don't
+	 * break this.
+	 */
 	tsk->files = NULL;
 	error = -ENOMEM;
 	newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
@@ -537,6 +542,33 @@
 	goto out;
 }
 
+/*
+ *	Helper to unshare the files of the current task. 
+ *	We don't want to expose copy_files internals to 
+ *	the exec layer of the kernel.
+ */
+
+int unshare_files(void)
+{
+	struct files_struct *files  = current->files;
+	int rc;
+	
+	if(!files)
+		BUG();
+		
+	/* This can race but the race causes us to copy when we don't
+	   need to and drop the copy */
+	if(atomic_read(&files->count) == 1)
+	{
+		atomic_inc(&files->count);
+		return 0;
+	}
+	rc = copy_files(0, current);
+	if(rc)
+		current->files = files;
+	return rc;
+}		
+
 static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct signal_struct *sig;
diff -urN linux-2.4.21-bk3/kernel/ksyms.c linux-2.4.21-bk4/kernel/ksyms.c
--- linux-2.4.21-bk3/kernel/ksyms.c	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/kernel/ksyms.c	2003-07-08 02:59:49.000000000 -0700
@@ -149,8 +149,8 @@
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(lookup_mnt);
-EXPORT_SYMBOL(path_init);
 EXPORT_SYMBOL(path_walk);
+EXPORT_SYMBOL(path_lookup);
 EXPORT_SYMBOL(path_release);
 EXPORT_SYMBOL(__user_walk);
 EXPORT_SYMBOL(lookup_one_len);
diff -urN linux-2.4.21-bk3/kernel/sys.c linux-2.4.21-bk4/kernel/sys.c
--- linux-2.4.21-bk3/kernel/sys.c	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/kernel/sys.c	2003-07-08 02:59:49.000000000 -0700
@@ -1143,6 +1143,8 @@
 		return -EINVAL;
 	if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 		return -EFAULT;
+       if (new_rlim.rlim_cur > new_rlim.rlim_max)
+               return -EINVAL;
 	old_rlim = current->rlim + resource;
 	if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 	     (new_rlim.rlim_max > old_rlim->rlim_max)) &&
diff -urN linux-2.4.21-bk3/kernel/sysctl.c linux-2.4.21-bk4/kernel/sysctl.c
--- linux-2.4.21-bk3/kernel/sysctl.c	2003-07-08 02:59:34.000000000 -0700
+++ linux-2.4.21-bk4/kernel/sysctl.c	2003-07-08 02:59:49.000000000 -0700
@@ -306,8 +306,6 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
-	 0444, NULL, &proc_dointvec},
 	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
diff -urN linux-2.4.21-bk3/net/unix/af_unix.c linux-2.4.21-bk4/net/unix/af_unix.c
--- linux-2.4.21-bk3/net/unix/af_unix.c	2002-11-28 15:53:16.000000000 -0800
+++ linux-2.4.21-bk4/net/unix/af_unix.c	2003-07-08 02:59:49.000000000 -0700
@@ -590,9 +590,8 @@
 	int err = 0;
 	
 	if (sunname->sun_path[0]) {
-		if (path_init(sunname->sun_path, 
-			      LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd))
-			err = path_walk(sunname->sun_path, &nd);
+		err = path_lookup(sunname->sun_path, 
+			      LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd);
 		if (err)
 			goto fail;
 		err = permission(nd.dentry->d_inode,MAY_WRITE);
@@ -685,8 +684,7 @@
 		 * Get the parent directory, calculate the hash for last
 		 * component.
 		 */
-		if (path_init(sunaddr->sun_path, LOOKUP_PARENT, &nd))
-			err = path_walk(sunaddr->sun_path, &nd);
+		err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
 		if (err)
 			goto out_mknod_parent;
 		/*
