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

diff -urN linux-2.4.21-bk23/Documentation/networking/ifenslave.c linux-2.4.21-bk24/Documentation/networking/ifenslave.c
--- linux-2.4.21-bk23/Documentation/networking/ifenslave.c	2003-08-01 02:53:16.000000000 -0700
+++ linux-2.4.21-bk24/Documentation/networking/ifenslave.c	2003-08-01 02:53:23.000000000 -0700
@@ -140,8 +140,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_bonding.h>
 #include <linux/sockios.h>
diff -urN linux-2.4.21-bk23/Makefile linux-2.4.21-bk24/Makefile
--- linux-2.4.21-bk23/Makefile	2003-08-01 02:53:17.000000000 -0700
+++ linux-2.4.21-bk24/Makefile	2003-08-01 02:53:23.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -bk23
+EXTRAVERSION = -bk24
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.21-bk23/arch/i386/kernel/i387.c linux-2.4.21-bk24/arch/i386/kernel/i387.c
--- linux-2.4.21-bk23/arch/i386/kernel/i387.c	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.21-bk24/arch/i386/kernel/i387.c	2003-08-01 02:53:23.000000000 -0700
@@ -373,14 +373,14 @@
 
 static inline int restore_i387_fxsave( struct _fpstate *buf )
 {
+	int err;
 	struct task_struct *tsk = current;
 	clear_fpu( tsk );
-	if ( __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
-			       sizeof(struct i387_fxsave_struct) ) )
-		return 1;
+	err = __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
+				sizeof(struct i387_fxsave_struct) );
 	/* mxcsr bit 6 and 31-16 must be zero for security reasons */
 	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
-	return convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
+	return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
 }
 
 int restore_i387( struct _fpstate *buf )
diff -urN linux-2.4.21-bk23/arch/i386/kernel/io_apic.c linux-2.4.21-bk24/arch/i386/kernel/io_apic.c
--- linux-2.4.21-bk23/arch/i386/kernel/io_apic.c	2003-08-01 02:53:17.000000000 -0700
+++ linux-2.4.21-bk24/arch/i386/kernel/io_apic.c	2003-08-01 02:53:23.000000000 -0700
@@ -1343,6 +1343,25 @@
 
 static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
 
+#ifndef CONFIG_SMP
+
+void send_IPI_self(int vector)
+{
+	unsigned int cfg;
+
+	/*
+	 * Wait for idle.
+	 */
+	apic_wait_icr_idle();
+	cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
+	/*
+	 * Send the IPI. The write to APIC_ICR fires this off.
+	 */
+	apic_write_around(APIC_ICR, cfg);
+}
+
+#endif /* CONFIG_SMP */
+
 static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
 {
 	unsigned long flags;
diff -urN linux-2.4.21-bk23/drivers/block/cciss.c linux-2.4.21-bk24/drivers/block/cciss.c
--- linux-2.4.21-bk23/drivers/block/cciss.c	2003-08-01 02:53:19.000000000 -0700
+++ linux-2.4.21-bk24/drivers/block/cciss.c	2003-08-01 02:53:24.000000000 -0700
@@ -48,7 +48,7 @@
 #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,47)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.47");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
@@ -2341,7 +2341,7 @@
 
 
 	/* Is this interrupt for us? */
-	if (h->access.intr_pending(h) == 0)
+	if ((h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))
 		return;
 
 	/*
diff -urN linux-2.4.21-bk23/drivers/block/cciss.h linux-2.4.21-bk24/drivers/block/cciss.h
--- linux-2.4.21-bk23/drivers/block/cciss.h	2003-08-01 02:53:19.000000000 -0700
+++ linux-2.4.21-bk24/drivers/block/cciss.h	2003-08-01 02:53:24.000000000 -0700
@@ -51,7 +51,7 @@
 	unsigned long io_mem_length;
 	CfgTable_struct *cfgtable;
 	int	intr;
-
+	int	interrupts_enabled;
 	int 	max_commands;
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
@@ -139,9 +139,11 @@
 {
 	if (val) 
 	{ /* Turn interrupts on */
+		h->interrupts_enabled = 1;
 		writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
 	} else /* Turn them off */
 	{
+		h->interrupts_enabled = 0;
         	writel( SA5_INTR_OFF, 
 			h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
 	}
@@ -155,9 +157,11 @@
 {
         if (val)
         { /* Turn interrupts on */
+		h->interrupts_enabled = 1;
                 writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         } else /* Turn them off */
         {
+		h->interrupts_enabled = 0;
                 writel( SA5B_INTR_OFF,
                         h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         }
diff -urN linux-2.4.21-bk23/drivers/char/agp/agpgart_be.c linux-2.4.21-bk24/drivers/char/agp/agpgart_be.c
--- linux-2.4.21-bk23/drivers/char/agp/agpgart_be.c	2003-08-01 02:53:20.000000000 -0700
+++ linux-2.4.21-bk24/drivers/char/agp/agpgart_be.c	2003-08-01 02:53:25.000000000 -0700
@@ -5580,7 +5580,11 @@
 {
 	long memory, index, result;
 
-	memory = (num_physpages << PAGE_SHIFT) >> 20;
+#if PAGE_SHIFT < 20
+	memory = num_physpages >> (20 - PAGE_SHIFT);
+#else
+	memory = num_physpages << (PAGE_SHIFT - 20);
+#endif
 	index = 1;
 
 	while ((memory > maxes_table[index].mem) &&
diff -urN linux-2.4.21-bk23/drivers/net/bonding/bond_main.c linux-2.4.21-bk24/drivers/net/bonding/bond_main.c
--- linux-2.4.21-bk23/drivers/net/bonding/bond_main.c	2003-08-01 02:53:20.000000000 -0700
+++ linux-2.4.21-bk24/drivers/net/bonding/bond_main.c	2003-08-01 02:53:25.000000000 -0700
@@ -524,7 +524,7 @@
 MODULE_PARM(miimon, "i");
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 MODULE_PARM(use_carrier, "i");
-MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 09 for off, 1 for on (default)");
+MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)");
 MODULE_PARM(mode, "s");
 MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(arp_interval, "i");
@@ -1594,11 +1594,14 @@
 #endif
 			bond_set_slave_inactive_flags(new_slave);
 		}
-		read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
-		ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list);
-		ifa = *ifap;
-		my_ip = ifa->ifa_address;
-		read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+		if (((struct in_device *)slave_dev->ip_ptr) != NULL) {
+			read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+			ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list);
+			ifa = *ifap;
+			if (ifa != NULL)
+				my_ip = ifa->ifa_address;
+			read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+		}
 
 		/* if there is a primary slave, remember it */
 		if (primary != NULL) {
diff -urN linux-2.4.21-bk23/drivers/scsi/3w-xxxx.c linux-2.4.21-bk24/drivers/scsi/3w-xxxx.c
--- linux-2.4.21-bk23/drivers/scsi/3w-xxxx.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.21-bk24/drivers/scsi/3w-xxxx.c	2003-08-01 02:53:25.000000000 -0700
@@ -165,6 +165,14 @@
                  Add support for "twe" character device for ioctls.
                  Clean up request_id queueing code.
                  Fix tw_scsi_queue() spinlocks.
+   1.02.00.033 - Fix tw_aen_complete() to not queue 'queue empty' AEN's.
+                 Initialize queues correctly when loading with no valid units.
+   1.02.00.034 - Fix tw_decode_bits() to handle multiple errors.
+                 Add support for user configurable cmd_per_lun.
+                 Add support for sht->select_queue_depths.
+   1.02.00.035 - Improve tw_allocate_memory() memory allocation.
+                 Fix tw_chrdev_ioctl() to sleep correctly.
+   1.02.00.036 - Increase character ioctl timeout to 60 seconds.
 */
 
 #include <linux/module.h>
@@ -232,7 +240,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.032";
+char *tw_driver_version="1.02.00.036";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 static int twe_major = -1;
@@ -271,25 +279,24 @@
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
 		}
 	}
-	if (aen != 0x0) 
+	if (aen != TW_AEN_QUEUE_EMPTY) {
 		tw_dev->aen_count++;
 
-	/* Now queue the code */
-	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
-	if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
-		tw_dev->aen_tail = TW_Q_START;
-	} else {
-		tw_dev->aen_tail = tw_dev->aen_tail + 1;
-	}
-	if (tw_dev->aen_head == tw_dev->aen_tail) {
-		if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-			tw_dev->aen_head = TW_Q_START;
+		/* Now queue the code */
+		tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+		if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+			tw_dev->aen_tail = TW_Q_START;
 		} else {
-			tw_dev->aen_head = tw_dev->aen_head + 1;
+			tw_dev->aen_tail = tw_dev->aen_tail + 1;
+		}
+		if (tw_dev->aen_head == tw_dev->aen_tail) {
+			if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+				tw_dev->aen_head = TW_Q_START;
+			} else {
+				tw_dev->aen_head = tw_dev->aen_head + 1;
+			}
 		}
-	}
 
-	if (aen != TW_AEN_QUEUE_EMPTY) {
 		error = tw_aen_read_queue(tw_dev, request_id);
 		if (error) {
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
@@ -556,34 +563,33 @@
 	else
 		imax = TW_Q_LENGTH;
 
-	for (i=0;i<imax;i++) {
-		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
-		if (cpu_addr == NULL) {
-			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
-			return 1;
-		}
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*imax, &dma_handle);
+	if (cpu_addr == NULL) {
+		printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+		return 1;
+	}
 
-		if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
-			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
-			pci_free_consistent(tw_dev->tw_pci_dev, size, cpu_addr, dma_handle);
-			return 1;
-		}
+	if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*imax, cpu_addr, dma_handle);
+		return 1;
+	}
+
+	memset(cpu_addr, 0, size*imax);
 
+	for (i=0;i<imax;i++) {
 		switch(which) {
 		case 0:
-			tw_dev->command_packet_virtual_address[i] = cpu_addr;
-			tw_dev->command_packet_physical_address[i] = dma_handle;
-			memset(tw_dev->command_packet_virtual_address[i], 0, size);
+			tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		case 1:
-			tw_dev->alignment_virtual_address[i] = cpu_addr;
-			tw_dev->alignment_physical_address[i] = dma_handle;
-			memset(tw_dev->alignment_virtual_address[i], 0, size);
+			tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
+			tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		case 2:
-			tw_dev->bounce_buffer[i] = cpu_addr;
-			tw_dev->bounce_buffer_phys[i] = dma_handle;
-			memset(tw_dev->bounce_buffer[i], 0, size);
+			tw_dev->bounce_buffer_phys[i] = dma_handle+(i*size);
+			tw_dev->bounce_buffer[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		default:
 			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
@@ -631,11 +637,11 @@
 	int error, request_id;
 	dma_addr_t dma_handle;
 	unsigned short tw_aen_code;
-	unsigned long before;
 	unsigned long flags;
 	unsigned int data_buffer_length = 0;
 	unsigned long data_buffer_length_adjusted = 0;
 	unsigned long *cpu_addr;
+	long timeout;
 	TW_New_Ioctl *tw_ioctl;
 	TW_Passthru *passthru;
 	TW_Device_Extension *tw_dev = tw_device_extension_list[MINOR(inode->i_rdev)];
@@ -735,30 +741,30 @@
 			tw_post_command_packet(tw_dev, request_id);
 			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
 
+			timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
 			/* Now wait for the command to complete */
-			before = jiffies;
+			tw_wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
 
-			while (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
-				/* FIXME: we need to sleep here */
-				udelay(10);
-				if (time_after(jiffies, before + HZ *TW_IOCTL_CHRDEV_TIMEOUT)) {
-					/* Now we need to reset the board */
+			/* Check if we timed out, got a signal, or didn't get 
+                           an interrupt */
+			if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+				/* Now we need to reset the board */
+				if (timeout == -ERESTARTSYS) {
+					retval = timeout;
+				} else {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
-					spin_lock_irqsave(&tw_dev->tw_lock, flags);
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					tw_state_request_finish(tw_dev, request_id);
-					pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
-					tw_dev->posted_request_count--;
-					if (tw_reset_device_extension(tw_dev)) {
-						printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
-					}
-					spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-					if (signal_pending(current))
-						retval = -EINTR;
-					else
-						retval = -EIO;
-					goto out2;
+					retval = -EIO;
+				}
+				spin_lock_irqsave(&tw_dev->tw_lock, flags);
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				tw_state_request_finish(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				if (tw_reset_device_extension(tw_dev)) {
+					printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
 				}
+				spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+				goto out2;
 			}
 
 			/* Now copy in the command packet response */
@@ -886,30 +892,33 @@
 	else
 		host[0] = '\0';
 
-	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
-	case TW_STATUS_PCI_PARITY_ERROR:
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
-		break;
-	case TW_STATUS_MICROCONTROLLER_ERROR:
-		if (tw_dev->reset_print == 0) {
-			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
-			tw_dev->reset_print = 1;
-		}
-		return 1;
-	case TW_STATUS_PCI_ABORT:
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
 		printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
 		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
-		break;
-	case TW_STATUS_QUEUE_ERROR:
+	}
+	
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
-		break;
-	case TW_STATUS_SBUF_WRITE_ERROR:
+	}
+	
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
-		break;
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+			tw_dev->reset_print = 1;
+		}
+		return 1;
 	}
 
 	return 0;
@@ -1143,19 +1152,24 @@
 			tw_dev->online = 1;
 
 			/* Calculate max cmds per lun, and setup queues */
-			if (tw_dev->num_units > 0) {
-				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_START;
-					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
-				} else {
-					/* Use SHT cmd_per_lun here */
+			if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+				tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_START;
+				tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
+			} else {
+				/* Check for user configured cmd_per_lun */
+#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
+				tw_host->cmd_per_lun = CONFIG_3W_XXXX_CMD_PER_LUN;
+				if (tw_host->cmd_per_lun > TW_MAX_CMDS_PER_LUN)
 					tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_START;
-					tw_dev->free_wrap = TW_Q_LENGTH - 1;
-				}
+#else
+				/* Use SHT cmd_per_lun default */
+				tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
+#endif
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_START;
+				tw_dev->free_wrap = TW_Q_LENGTH - 1;
 			}
 
 		/* Register the card with the kernel SCSI layer */
@@ -1184,6 +1198,8 @@
 				host->max_sectors = TW_MAX_SECTORS;
 #endif
 
+			host->select_queue_depths = tw_select_queue_depths;
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
 			scsi_set_pci_device(host, tw_pci_dev);
 #endif
@@ -1198,6 +1214,10 @@
 			if (host->hostdata) {
 				tw_dev2 = (TW_Device_Extension *)host->hostdata;
 				memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+				/* Need to init the sem/wqueue after the copy */
+				init_MUTEX(&tw_dev2->ioctl_sem);
+				init_waitqueue_head(&tw_dev2->ioctl_wqueue);
+
 				tw_device_extension_list[tw_device_extension_count] = tw_dev2;
 				numcards++;
 				tw_device_extension_count = numcards;
@@ -1254,22 +1274,17 @@
 /* This function will free up device extension resources */
 void tw_free_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i;
-
 	dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
+
 	/* Free command packet and generic buffer memory */
-	for (i=0;i<TW_Q_LENGTH;i++) {
-		if (tw_dev->command_packet_virtual_address[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
+	if (tw_dev->command_packet_physical_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
 
-		if (tw_dev->alignment_virtual_address[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
+	if (tw_dev->alignment_physical_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
 
-	}
-	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-		if (tw_dev->bounce_buffer[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, tw_dev->bounce_buffer[i], tw_dev->bounce_buffer_phys[i]);
-	}
+	if (tw_dev->bounce_buffer[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS*TW_MAX_BOUNCEBUF, tw_dev->bounce_buffer[0], tw_dev->bounce_buffer_phys[0]);
 } /* End tw_free_device_extension() */
 
 /* Clean shutdown routine */
@@ -1379,8 +1394,6 @@
 	tw_dev->pending_tail = TW_Q_START;
 	spin_lock_init(&tw_dev->tw_lock);
 	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-	init_waitqueue_head(&tw_dev->ioctl_wqueue);
-	init_MUTEX(&tw_dev->ioctl_sem);
 
 	return 0;
 } /* End tw_initialize_device_extension() */
@@ -1720,6 +1733,7 @@
 						}
 					} else {
 						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+						wake_up(&tw_dev->ioctl_wqueue);
 					}
 				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
@@ -3395,6 +3409,31 @@
 	return 0;
 } /* End tw_scsiop_test_unit_ready_complete() */
 
+/* This function will select queue depths for a target */
+void tw_select_queue_depths(struct Scsi_Host *host, Scsi_Device *dev)
+{
+	Scsi_Device *ptr;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_select_queue_depths()\n");
+
+	for (ptr = dev; ptr != NULL; ptr = ptr->next) {
+		if (ptr->host == host) {
+			if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+				ptr->queue_depth = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
+			} else {
+#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
+				ptr->queue_depth = CONFIG_3W_XXXX_CMD_PER_LUN;
+				if (ptr->queue_depth > TW_MAX_CMDS_PER_LUN)
+					ptr->queue_depth = TW_MAX_CMDS_PER_LUN;
+#else
+				ptr->queue_depth = TW_MAX_CMDS_PER_LUN;
+#endif
+			}
+		}
+	}
+} /* End tw_select_queue_depths() */
+
 /* Set a value in the features table */
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
                   unsigned char *val)
diff -urN linux-2.4.21-bk23/drivers/scsi/3w-xxxx.h linux-2.4.21-bk24/drivers/scsi/3w-xxxx.h
--- linux-2.4.21-bk23/drivers/scsi/3w-xxxx.h	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.21-bk24/drivers/scsi/3w-xxxx.h	2003-08-01 02:53:25.000000000 -0700
@@ -115,10 +115,10 @@
   {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0x37, 0x02, 0x04, 0x00}, // Unit offline                 Not ready
+  {0x09, 0x02, 0x04, 0x00}, // Unrecovered disk error       Not ready
 
   /* Codes for older firmware */
                             // 3ware Error                  SCSI Error
-  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
   {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
 };
 
@@ -238,7 +238,7 @@
 #define TW_ISR_DONT_COMPLETE                  2
 #define TW_ISR_DONT_RESULT                    3
 #define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
-#define TW_IOCTL_CHRDEV_TIMEOUT               25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
 #define TW_IOCTL_CHRDEV_FREE                  -1
 
 /* Macros */
@@ -249,6 +249,30 @@
 	(x & TW_STATUS_MICROCONTROLLER_ERROR)) && \
 	(x & TW_STATUS_MICROCONTROLLER_READY))
 
+/* This was taken from 2.5 kernel */
+#define tw_wait_event_interruptible_timeout(wq, condition, ret)         \
+do {                                                                    \
+        wait_queue_t __wait;                                            \
+        init_waitqueue_entry(&__wait, current);                         \
+                                                                        \
+        add_wait_queue(&wq, &__wait);                                   \
+        for (;;) {                                                      \
+                set_current_state(TASK_INTERRUPTIBLE);                  \
+                if (condition)                                          \
+                        break;                                          \
+                if (!signal_pending(current)) {                         \
+                        ret = schedule_timeout(ret);                    \
+                        if (!ret)                                       \
+                                break;                                  \
+                        continue;                                       \
+                }                                                       \
+                ret = -ERESTARTSYS;                                     \
+                break;                                                  \
+        }                                                               \
+        current->state = TASK_RUNNING;                                  \
+        remove_wait_queue(&wq, &__wait);                                \
+} while (0)
+
 #ifdef TW_DEBUG
 #define dprintk(msg...) printk(msg)
 #else
@@ -498,6 +522,7 @@
 int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id);
+void tw_select_queue_depths(struct Scsi_Host *host, Scsi_Device *dev);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
diff -urN linux-2.4.21-bk23/fs/jfs/super.c linux-2.4.21-bk24/fs/jfs/super.c
--- linux-2.4.21-bk23/fs/jfs/super.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk24/fs/jfs/super.c	2003-08-01 02:53:26.000000000 -0700
@@ -337,6 +337,7 @@
 	if (!(sb->s_flags & MS_RDONLY)) {
 		txQuiesce(sb);
 		lmLogShutdown(log);
+		updateSuper(sb, FM_CLEAN);
 	}
 }
 
@@ -347,6 +348,7 @@
 	int rc = 0;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
+		updateSuper(sb, FM_MOUNT);
 		if ((rc = lmLogInit(log)))
 			jfs_err("jfs_unlock failed with return code %d", rc);
 		else
diff -urN linux-2.4.21-bk23/fs/nfs/nfsroot.c linux-2.4.21-bk24/fs/nfs/nfsroot.c
--- linux-2.4.21-bk23/fs/nfs/nfsroot.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk24/fs/nfs/nfsroot.c	2003-08-01 02:53:26.000000000 -0700
@@ -305,7 +305,7 @@
  */
 int __init nfs_root_setup(char *line)
 {
-	ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
+	ROOT_DEV = MKDEV(NFS_MAJOR, NFS_MINOR);
 	if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
 		strncpy(nfs_root_name, line, sizeof(nfs_root_name));
 		nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
diff -urN linux-2.4.21-bk23/fs/proc/base.c linux-2.4.21-bk24/fs/proc/base.c
--- linux-2.4.21-bk23/fs/proc/base.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk24/fs/proc/base.c	2003-08-01 02:53:26.000000000 -0700
@@ -124,20 +124,56 @@
 	return result;
 }
 
+#define MAY_PTRACE(task) \
+	(task == current || \
+	(task->p_pptr == current && \
+	(task->ptrace & PT_PTRACED) && task->state == TASK_STOPPED))
+
+static int may_ptrace_attach(struct task_struct *task)
+{
+	int retval = 0;
+
+	task_lock(task);
+
+	if (((current->uid != task->euid) ||
+	    (current->uid != task->suid) ||
+	    (current->uid != task->uid) ||
+	    (current->gid != task->egid) ||
+	    (current->gid != task->sgid) ||
+	    (!cap_issubset(task->cap_permitted, current->cap_permitted)) ||
+	    (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+		goto out;
+	rmb();
+	if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE))
+		goto out;
+
+	retval = 1;
+
+out:
+	task_unlock(task);
+	return retval;
+}
+
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
 	struct mm_struct *mm;
 	int res = 0;
+
+	if (!may_ptrace_attach(task))
+		return -ESRCH;
+
 	task_lock(task);
 	mm = task->mm;
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	task_unlock(task);
 	if (mm) {
-		int len = mm->env_end - mm->env_start;
+		unsigned int len = mm->env_end - mm->env_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->env_start, buffer, len, 0);
+		if (!may_ptrace_attach(task))
+			res = -ESRCH;
 		mmput(mm);
 	}
 	return res;
@@ -328,10 +364,6 @@
 	read:		proc_info_read,
 };
 
-#define MAY_PTRACE(p) \
-(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
-
-
 static int mem_open(struct inode* inode, struct file* file)
 {
 	file->private_data = (void*)((long)current->self_exec_id);
@@ -347,8 +379,7 @@
 	int copied = 0;
 	struct mm_struct *mm;
 
-
-	if (!MAY_PTRACE(task))
+	if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
 		return -ESRCH;
 
 	page = (char *)__get_free_page(GFP_USER);
@@ -370,14 +401,13 @@
 		copied = -EIO;
 		goto out_free;
 	}
-		
 
 	while (count > 0) {
 		int this_len, retval;
 
 		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 		retval = access_process_vm(task, src, page, this_len, 0);
-		if (!retval) {
+		if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) {
 			if (!copied)
 				copied = -EIO;
 			break;
@@ -411,7 +441,7 @@
 	struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
 	unsigned long dst = *ppos;
 
-	if (!MAY_PTRACE(task))
+	if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
 		return -ESRCH;
 
 	page = (char *)__get_free_page(GFP_USER);
diff -urN linux-2.4.21-bk23/fs/proc/proc_misc.c linux-2.4.21-bk24/fs/proc/proc_misc.c
--- linux-2.4.21-bk23/fs/proc/proc_misc.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.21-bk24/fs/proc/proc_misc.c	2003-08-01 02:53:26.000000000 -0700
@@ -423,9 +423,9 @@
 				 int count, int *eof, void *data)
 {
 	extern char saved_command_line[];
-	int len;
+	int len = 0;
 
-	len = snprintf(page, count, "%s\n", saved_command_line);
+	proc_sprintf(page, &off, &len, "%s\n", saved_command_line);
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
@@ -495,7 +495,8 @@
 		buf++; p++; count--; read++;
 	}
 	pnt = (char *)prof_buffer + p - sizeof(unsigned int);
-	copy_to_user(buf,(void *)pnt,count);
+	if (copy_to_user(buf,(void *)pnt,count))
+		return -EFAULT;
 	read += count;
 	*ppos += read;
 	return read;
diff -urN linux-2.4.21-bk23/fs/reiserfs/super.c linux-2.4.21-bk24/fs/reiserfs/super.c
--- linux-2.4.21-bk23/fs/reiserfs/super.c	2003-08-01 02:53:21.000000000 -0700
+++ linux-2.4.21-bk24/fs/reiserfs/super.c	2003-08-01 02:53:26.000000000 -0700
@@ -284,7 +284,7 @@
     }
 
     /* body of "save" link */
-    link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id);
+    link = INODE_PKEY (inode)->k_dir_id;
 
     /* put "save" link inot tree */
     retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
diff -urN linux-2.4.21-bk23/include/asm-i386/hw_irq.h linux-2.4.21-bk24/include/asm-i386/hw_irq.h
--- linux-2.4.21-bk23/include/asm-i386/hw_irq.h	2001-11-22 11:46:18.000000000 -0800
+++ linux-2.4.21-bk24/include/asm-i386/hw_irq.h	2003-08-01 02:53:26.000000000 -0700
@@ -13,8 +13,10 @@
  */
 
 #include <linux/config.h>
+#include <linux/smp_lock.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
+#include <asm/current.h>
 
 /*
  * IDT vectors usable for external interrupt sources start
@@ -213,7 +215,7 @@
 	atomic_inc((atomic_t *)&prof_buffer[eip]);
 }
 
-#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
+#if defined(CONFIG_X86_IO_APIC)
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
 	if (IO_APIC_IRQ(i))
 		send_IPI_self(IO_APIC_VECTOR(i));
diff -urN linux-2.4.21-bk23/include/linux/nfs.h linux-2.4.21-bk24/include/linux/nfs.h
--- linux-2.4.21-bk23/include/linux/nfs.h	2000-04-01 08:04:27.000000000 -0800
+++ linux-2.4.21-bk24/include/linux/nfs.h	2003-08-01 02:53:26.000000000 -0700
@@ -30,6 +30,9 @@
 #define NFS_MNT_PROGRAM	100005
 #define NFS_MNT_PORT	627
 
+#define NFS_MAJOR   	UNNAMED_MAJOR
+#define NFS_MINOR   	0xff
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
diff -urN linux-2.4.21-bk23/include/linux/sunrpc/xprt.h linux-2.4.21-bk24/include/linux/sunrpc/xprt.h
--- linux-2.4.21-bk23/include/linux/sunrpc/xprt.h	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/include/linux/sunrpc/xprt.h	2003-08-01 02:53:27.000000000 -0700
@@ -98,6 +98,10 @@
 
 	struct list_head	rq_list;
 
+	struct xdr_buf		rq_private_buf;		/* The receive buffer
+							 * used in the softirq.
+							 */
+
 	/*
 	 * For authentication (e.g. auth_des)
 	 */
diff -urN linux-2.4.21-bk23/init/do_mounts.c linux-2.4.21-bk24/init/do_mounts.c
--- linux-2.4.21-bk23/init/do_mounts.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/init/do_mounts.c	2003-08-01 02:53:27.000000000 -0700
@@ -88,7 +88,7 @@
 	const char *name;
 	const int num;
 } root_dev_names[] __initdata = {
-	{ "nfs",     0x00ff },
+	{ "nfs",     MKDEV(NFS_MAJOR, NFS_MINOR) },
 	{ "hda",     0x0300 },
 	{ "hdb",     0x0340 },
 	{ "loop",    0x0700 },
@@ -759,7 +759,8 @@
 static void __init mount_root(void)
 {
 #ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
+       if (MAJOR(ROOT_DEV) == NFS_MAJOR
+           && MINOR(ROOT_DEV) == NFS_MINOR) {
 		if (mount_nfs_root()) {
 			sys_chdir("/root");
 			ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
diff -urN linux-2.4.21-bk23/kernel/sysctl.c linux-2.4.21-bk24/kernel/sysctl.c
--- linux-2.4.21-bk23/kernel/sysctl.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/kernel/sysctl.c	2003-08-01 02:53:27.000000000 -0700
@@ -474,7 +474,8 @@
 	 * zero, proceed with automatic r/w */
 	if (table->data && table->maxlen) {
 		if (oldval && oldlenp) {
-			get_user(len, oldlenp);
+			if (get_user(len, oldlenp))
+				return -EFAULT;
 			if (len) {
 				if (len > table->maxlen)
 					len = table->maxlen;
@@ -765,7 +766,7 @@
 		len = 0;
 		p = buffer;
 		while (len < *lenp) {
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (c == 0 || c == '\n')
 				break;
@@ -848,7 +849,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c,(char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -914,7 +915,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1001,7 +1002,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c, (char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -1060,7 +1061,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1102,7 +1103,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c, (char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -1165,7 +1166,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1319,7 +1320,7 @@
 		return -ENOTDIR;
 	
 	if (oldval && oldlenp) {
-		if(get_user(len, oldlenp))
+		if (get_user(len, oldlenp))
 			return -EFAULT;
 		if (len) {
 			l = strlen(table->data);
@@ -1376,7 +1377,8 @@
 
 		for (i = 0; i < length; i++) {
 			int value;
-			get_user(value, vec + i);
+			if (get_user(value, vec + i))
+				return -EFAULT;
 			if (min && value < min[i])
 				return -EINVAL;
 			if (max && value > max[i])
diff -urN linux-2.4.21-bk23/net/ipv4/ipconfig.c linux-2.4.21-bk24/net/ipv4/ipconfig.c
--- linux-2.4.21-bk23/net/ipv4/ipconfig.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/net/ipv4/ipconfig.c	2003-08-01 02:53:27.000000000 -0700
@@ -1234,7 +1234,7 @@
 			 * 				-- Chip
 			 */
 #ifdef CONFIG_ROOT_NFS
-			if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) {
+			if (ROOT_DEV == MKDEV(NFS_MAJOR, NFS_MINOR)) {
 				printk(KERN_ERR 
 					"IP-Config: Retrying forever (NFS root)...\n");
 				goto try_try_again;
diff -urN linux-2.4.21-bk23/net/sunrpc/clnt.c linux-2.4.21-bk24/net/sunrpc/clnt.c
--- linux-2.4.21-bk23/net/sunrpc/clnt.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/net/sunrpc/clnt.c	2003-08-01 02:53:27.000000000 -0700
@@ -646,7 +646,8 @@
 	struct rpc_rqst	*req = task->tk_rqstp;
 	int		status;
 
-	if (req->rq_received != 0)
+	smp_rmb();
+	if (req->rq_received > 0 && !req->rq_bytes_sent)
 		task->tk_status = req->rq_received;
 
 	dprintk("RPC: %4d call_status (status %d)\n", 
@@ -754,17 +755,23 @@
 		if (!clnt->cl_softrtry) {
 			task->tk_action = call_transmit;
 			clnt->cl_stats->rpcretrans++;
-		} else {
-			printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
-				clnt->cl_protname, task->tk_status);
-			rpc_exit(task, -EIO);
+			goto out_retry;
 		}
+		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
+			clnt->cl_protname, task->tk_status);
+		rpc_exit(task, -EIO);
 		return;
 	}
 
+	/* Check that the softirq receive buffer is valid */
+	if (unlikely(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
+				sizeof(req->rq_rcv_buf)) != 0))
+		printk(KERN_WARNING "%s: receive buffer is inconsistent. Please contact maintainer.\n",
+				__FUNCTION__);
+
 	/* Verify the RPC header */
 	if (!(p = call_verify(task)))
-		return;
+		goto out_retry;
 
 	/*
 	 * The following is an NFS-specific hack to cater for setuid
@@ -777,7 +784,7 @@
 			task->tk_flags ^= RPC_CALL_REALUID;
 			task->tk_action = call_encode;
 			task->tk_suid_retry--;
-			return;
+			goto out_retry;
 		}
 	}
 
@@ -787,6 +794,10 @@
 		task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
 	dprintk("RPC: %4d call_decode result %d\n", task->tk_pid,
 					task->tk_status);
+	return;
+out_retry:
+	req->rq_received = 0;
+	task->tk_status = 0;
 }
 
 /*
diff -urN linux-2.4.21-bk23/net/sunrpc/xdr.c linux-2.4.21-bk24/net/sunrpc/xdr.c
--- linux-2.4.21-bk23/net/sunrpc/xdr.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/net/sunrpc/xdr.c	2003-08-01 02:53:27.000000000 -0700
@@ -180,7 +180,8 @@
 {
 	struct iovec	*iov = iov_base;
 	struct page	**ppage = xdr->pages;
-	unsigned int	len, pglen = xdr->page_len, first_kmap;
+	struct page	**first_kmap = NULL;
+	unsigned int	len, pglen = xdr->page_len;
 
 	len = xdr->head[0].iov_len;
 	if (base < len) {
@@ -203,16 +204,15 @@
 		ppage += base >> PAGE_CACHE_SHIFT;
 		base &= ~PAGE_CACHE_MASK;
 	}
-	first_kmap = 1;
 	do {
 		len = PAGE_CACHE_SIZE;
-		if (first_kmap) {
-			first_kmap = 0;
+		if (!first_kmap) {
+			first_kmap = ppage;
 			iov->iov_base = kmap(*ppage);
 		} else {
 			iov->iov_base = kmap_nonblock(*ppage);
 			if (!iov->iov_base)
-				goto out;
+				goto out_err;
 		}
 		if (base) {
 			iov->iov_base += base;
@@ -233,6 +233,10 @@
 	}
  out:
 	return (iov - iov_base);
+out_err:
+	for (; first_kmap != ppage; first_kmap++)
+		kunmap(*first_kmap);
+	return 0;
 }
 
 void xdr_kunmap(struct xdr_buf *xdr, unsigned int base, int niov)
diff -urN linux-2.4.21-bk23/net/sunrpc/xprt.c linux-2.4.21-bk24/net/sunrpc/xprt.c
--- linux-2.4.21-bk23/net/sunrpc/xprt.c	2003-08-01 02:53:22.000000000 -0700
+++ linux-2.4.21-bk24/net/sunrpc/xprt.c	2003-08-01 02:53:27.000000000 -0700
@@ -237,6 +237,10 @@
 		unsigned int slen_part, n;
 
 		niov = xdr_kmap(niv, xdr, skip);
+		if (!niov) {
+			result = -EAGAIN;
+			break;
+		}
 
 		msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
 		msg.msg_iov	= niv;
@@ -726,11 +730,11 @@
 	xprt_pktdump("packet data:",
 		     (u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize);
 
-	if ((copied = rovr->rq_rlen) > repsize)
+	if ((copied = rovr->rq_private_buf.len) > repsize)
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
-	if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb))
+	if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb))
 		goto out_unlock;
 
 	/* Something worked... */
@@ -852,7 +856,7 @@
 		return;
 	}
 
-	rcvbuf = &req->rq_rcv_buf;
+	rcvbuf = &req->rq_private_buf;
 	len = desc->count;
 	if (len > xprt->tcp_reclen - xprt->tcp_offset) {
 		skb_reader_t my_desc;
@@ -870,7 +874,7 @@
 	xprt->tcp_copied += len;
 	xprt->tcp_offset += len;
 
-	if (xprt->tcp_copied == req->rq_rlen)
+	if (xprt->tcp_copied == req->rq_private_buf.len)
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 	else if (xprt->tcp_offset == xprt->tcp_reclen) {
 		if (xprt->tcp_flags & XPRT_LAST_FRAG)
@@ -1102,6 +1106,9 @@
 	}
 
 	spin_lock_bh(&xprt->sock_lock);
+	if (req->rq_received != 0 && !req->rq_bytes_sent)
+		goto out_notrans;
+
 	if (!__xprt_lock_write(xprt, task))
 		goto out_notrans;
 
@@ -1111,8 +1118,10 @@
 	}
 
 	if (list_empty(&req->rq_list)) {
+		/* Update the softirq receive buffer */
+		memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
+				sizeof(req->rq_private_buf));
 		list_add_tail(&req->rq_list, &xprt->recv);
-		req->rq_received = 0;
 	}
 	spin_unlock_bh(&xprt->sock_lock);
 
@@ -1145,8 +1154,12 @@
 		if (xprt->stream) {
 			req->rq_bytes_sent += status;
 
-			if (req->rq_bytes_sent >= req->rq_slen)
+			/* If we've sent the entire packet, immediately
+			 * reset the count of bytes sent. */
+			if (req->rq_bytes_sent >= req->rq_slen) {
+				req->rq_bytes_sent = 0;
 				goto out_receive;
+			}
 		} else {
 			if (status >= req->rq_slen)
 				goto out_receive;
@@ -1168,9 +1181,6 @@
 	 * Note, though, that we can't do this if we've already started
 	 * resending down a TCP stream.
 	 */
-	if (req->rq_received && !req->rq_bytes_sent)
-		goto out_release;
-
 	task->tk_status = status;
 
 	switch (status) {
@@ -1200,7 +1210,6 @@
 		if (xprt->stream)
 			xprt_disconnect(xprt);
 	}
- out_release:
 	xprt_release_write(xprt, task);
 	return;
  out_receive:
