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

diff -urN linux-2.4.20-pre11/CREDITS linux-2.4.20-rc1/CREDITS
--- linux-2.4.20-pre11/CREDITS	Tue Oct 29 08:34:05 2002
+++ linux-2.4.20-rc1/CREDITS	Tue Oct 29 08:34:30 2002
@@ -1263,7 +1263,7 @@
 S: Germany
 
 N: David Hinds
-E: dhinds@zen.stanford.edu
+E: dahinds@users.sourceforge.net
 W: http://tao.stanford.edu/~dhinds
 D: PCMCIA and CardBus stuff, PCMCIA-HOWTO, PCMCIA client drivers
 S: 2019 W. Middlefield Rd #1
diff -urN linux-2.4.20-pre11/Documentation/networking/e100.txt linux-2.4.20-rc1/Documentation/networking/e100.txt
--- linux-2.4.20-pre11/Documentation/networking/e100.txt	Tue Oct 29 08:34:08 2002
+++ linux-2.4.20-rc1/Documentation/networking/e100.txt	Tue Oct 29 08:34:31 2002
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-April 9, 2002
+September 16, 2002
 
 
 Contents
@@ -19,26 +19,9 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
-Adapters, version 2.0.x.  This driver includes support for Itanium(TM)-based 
+Adapters, version 2.1.x.  This driver includes support for Itanium(TM)-based 
 systems.
 
-New for this release:
-
-   - Additional ethtool functionality, including link status test and EEPROM 
-     read/write. A third-party application can use the ethtool interface to 
-     get and set driver parameters.
-
-   - Support for Zero copy on 82550-based adapters. This feature provides 
-     faster data throughput and significant CPU usage improvement in systems 
-     that use the relevant system call (sendfile(2)).
-
-   - Support for large MTU-enabling interface (1504 bytes) with kernel's 
-     VLAN module
-
-   - Support for polling on RX
-
-   - Support for Wake On LAN* on 82550 and 82559-based adapters
-
 
 Supported Adapters
 ==================
@@ -96,8 +79,7 @@
 
 To verify that your adapter is supported, find the board ID number on the 
 adapter. Look for a label that has a barcode and a number in the format 
-123456-001 (six digits hyphen three digits). Match this to the list of 
-numbers above.
+A12345-001. Match this to the list of numbers above.
 
 For more information on how to identify your adapter, go to the Adapter & 
 Driver ID Guide at:
@@ -106,15 +88,20 @@
 
 For the latest Intel PRO/100 network driver for Linux, see:
 
-  http://appsr.intel.com/scripts-df/support_intel.asp
+  http://downloadfinder.intel.com/scripts-df/support_intel.asp
 
 
 Command Line Parameters
 =======================
 
-The following parameters are used by entering them on the command line with 
-the modprobe or insmod command. For example, with two Intel PRO/100 PCI 
-adapters, entering:
+The following optional parameters are used by entering them on the command 
+line with the modprobe or insmod command using this syntax:
+
+     modprobe e100 [<option>=<VAL1>,<VAL2>,...]
+
+     insmod e100 [<option>=<VAL1>,<VAL2>,...] 
+
+For example, with two Intel PRO/100 PCI adapters, entering:
 	
      modprobe e100 TxDescriptors=32,128
 
@@ -122,16 +109,20 @@
 resources for the second adapter. This configuration favors the second 
 adapter. The driver supports up to 16 network adapters concurrently.
 
+The default value for each parameter is generally the recommended setting,
+unless otherwise noted.
+
 NOTE: Giving any command line option the value "-1" causes the driver to use 
       the appropriate default value for that option, as if no value was 
       specified.
 
 
 BundleMax
-Valid Range: 0x1-0xFFFF
+Valid Range: 1-65535
 Default Value: 6
-   This parameter holds the maximum number of packets in a bundle. Suggested 
-   values range from 2 to 10. See "CPU Cycle Saver."
+   This parameter holds the maximum number of small packets (less than 128
+   bytes) in a bundle. Suggested values range from 2 to 10. See "CPU Cycle 
+   Saver."
 
 BundleSmallFr
 Valid Range: 0-1 (0=off, 1=on)
@@ -142,48 +133,33 @@
 e100_speed_duplex
 Valid Range: 0-4 (1=10half;2=10full;3=100half;4=100full)
 Default Value: 0
-   The default value of 0 is set to auto-negotiate if the link partner is set
-   to auto-negotiate. If the link partner is forced, e100_speed_duplex 
-   defaults to half-duplex. 
+   The default value of 0 sets the adapter to auto-negotiate. Other values
+   set the adapter to forced speed and duplex. 
    Example usage: insmod e100.o e100_speed_duplex=4,4 (for two adapters)
 
 flow_control
 Valid Range: 0-1 (0=off, 1=on)
 Default Value: 0
    This parameter controls the automatic generation(Tx) and response(Rx) to 
-   Ethernet PAUSE frames. flow_control should NOT be set to 1 when the e100 
+   Ethernet PAUSE frames. flow_control should NOT be set to 1 when the 
    adapter is connected to an interface that does not support Ethernet PAUSE 
    frames and when the e100_speed_duplex parameter is NOT set to zero. 
 
 IntDelay
-Valid Range: 0-0xFFFF (0=off)
+Valid Range: 0-65535 (0=off)
 Default Value: 1536
    This parameter holds the number of time units (in adapter terminology)
    until the adapter generates an interrupt. The recommended value for 
-   IntDelay is 0x600 (upon initialization). Suggested values range from 
-   0x200h to 0x800. See "CPU Cycle Saver."
+   IntDelay is 1536 (upon initialization). Suggested values range from 
+   512 to 2048. See "CPU Cycle Saver."
 
 IFS
 Valid Range: 0-1 (0=off, 1=on)
 Default Value: 1
   Inter Frame Spacing (IFS) aims to reduce the number of Ethernet frame
   collisions by altering the time between frame transmissions. When IFS is 
-  enabled the driver tries to find an optimal IFS value. However, some 
-  switches function better when IFS is disabled.
-
-PollingMaxWork
-Valid Range: 1-1024 (max number of RxDescriptors)
-Default Value: Specified number of RxDescriptors
-  This value specifies the maximum number of receive packets that are 
-  processed on a single polling call. This parameter is invalid if 
-  RxCongestionControl is set to 0.
-
-RxCongestionControl
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 1
-  1 enables polling mode. When the link is congested, the driver can decide 
-  to handle received packets by polling them, instead of waiting until 
-  interrupts occur.
+  enabled the driver tries to find an optimal IFS value. It is used only at 
+  half duplex.
 
 RxDescriptors
 Valid Range: 8-1024
@@ -200,13 +176,15 @@
    Increasing this value allows the protocol stack to queue more transmits at
    the driver level. The maximum value for Itanium-based systems is 64.
 
-ucode (not available for 82557-based adapters)
+ucode
 Valid Range: 0-1 (0=off, 1=on)
 Default Value: 0 for 82558-based adapters
-               1 for 82559(and higher)-based adapters
+               1 for 82559, 82550, and 82551-based adapters
    On uploads the micro code to the adapter, which enables CPU Cycle Saver. 
    See the section "CPU Cycle Saver" below.
-   Example usage: insmod e100.o ucode=0  (does not reduce CPU usage)
+   Example usage: insmod e100.o ucode=1
+
+   Not available on 82557-based adapters.
 
 XsumRX
 Valid Range: 0-1 (0=off, 1=on)
@@ -214,6 +192,8 @@
    On allows Rx checksum offloading for TCP/UDP packets. Requires that the 
    hardware support this feature.
 
+   Not available on 82557 and 82558-based adapters.
+
 
 CPU Cycle Saver
 ================
@@ -234,10 +214,11 @@
 CPU Cycle Saver consists of these arguments: IntDelay, BundleMax and 
 BundleSmallFr. When IntDelay is increased, the adapter waits longer for 
 frames to arrive before generating the interrupt. By increasing BundleMax, 
-the network adapter waits for the number of frames specified to arrive before 
-generating the interrupt. When BundleSmallFr is disabled, the adapter does 
-not bundle packets that are smaller than 128 bytes. Such small packets are 
-often, but not always, control packets that are better served immediately.
+the network adapter waits for the number of small frames (less than 128 bytes)
+specified to arrive before generating the interrupt. When BundleSmallFr is 
+disabled, the adapter does not bundle small packets. Such small packets are 
+often, but not always, control packets that are better served immediately;
+therefore, BundleSmallFr is disabled by default.
 
 For most users, it is recommended that CPU Cycle Saver be used with the 
 default values specified in the Command Line Parameters section. However, in 
@@ -249,7 +230,7 @@
 Support
 =======
 
-For general information and support, go to the Intel support website at:
+For general information, go to the Intel support website at:
 
     http://support.intel.com
 
diff -urN linux-2.4.20-pre11/Documentation/networking/e1000.txt linux-2.4.20-rc1/Documentation/networking/e1000.txt
--- linux-2.4.20-pre11/Documentation/networking/e1000.txt	Tue Oct 29 08:34:08 2002
+++ linux-2.4.20-rc1/Documentation/networking/e1000.txt	Tue Oct 29 08:34:31 2002
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
 ===============================================================
 
-August 6, 2002
+October 12, 2002
 
 
 Contents
@@ -20,7 +20,7 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/1000 Family
-of Adapters, version 4.3.x.  This driver includes support for 
+of Adapters, version 4.4.x.  This driver includes support for 
 Itanium(TM)-based systems.
 
 This release version includes the following:
@@ -32,7 +32,7 @@
      default in supporting kernels. It is not supported on the Intel(R)
      PRO/1000 Gigabit Server Adapter.
 
-New features include:
+Features include:
 
    - Support for the 82545 and 82546-based adapters listed below
 
@@ -144,8 +144,7 @@
 
 RxIntDelay
 Valid Range: 0-65535 (0=off)
-Default Value: 0 (82542, 82543, and 82544-based adapters)
-               128 (82540, 82545, and 82546-based adapters)
+Default Value: 0
     This value delays the generation of receive interrupts in units of 1.024 
     microseconds.  Receive interrupt reduction can improve CPU efficiency if 
     properly tuned for specific network traffic. Increasing this value adds 
@@ -154,13 +153,12 @@
     may be set too high, causing the driver to run out of available receive 
     descriptors.
 
-    CAUTION: When setting RxIntDelay to a value other than 0, adapters based 
-             on the Intel 82543 and 82544 LAN controllers may hang (stop 
-             transmitting) under certain network conditions. If this occurs a
-             message is logged in the system event log. In addition, the 
-             controller is automatically reset, restoring the network 
-             connection. To eliminate the potential for the hang ensure that 
-             RxIntDelay is set to 0.
+    CAUTION: When setting RxIntDelay to a value other than 0, adapters may 
+             hang (stop transmitting) under certain network conditions. If
+             this occurs a NETDEV WATCHDOG message is logged in the system
+             event log. In addition, the controller is automatically reset,
+             restoring the network connection. To eliminate the potential for
+             the hang ensure that RxIntDelay is set to 0.
 
 RxAbsIntDelay (82540, 82545, and 82546-based adapters only)
 Valid Range: 0-65535 (0=off)
diff -urN linux-2.4.20-pre11/MAINTAINERS linux-2.4.20-rc1/MAINTAINERS
--- linux-2.4.20-pre11/MAINTAINERS	Tue Oct 29 08:34:09 2002
+++ linux-2.4.20-rc1/MAINTAINERS	Tue Oct 29 08:34:31 2002
@@ -1252,7 +1252,7 @@
 
 PCMCIA SUBSYSTEM
 P:	David Hinds
-M:	dhinds@zen.stanford.edu
+M:	dahinds@users.sourceforge.net
 L:	linux-kernel@vger.kernel.org
 W:	http://pcmcia-cs.sourceforge.net
 S:	Maintained
diff -urN linux-2.4.20-pre11/Makefile linux-2.4.20-rc1/Makefile
--- linux-2.4.20-pre11/Makefile	Tue Oct 29 08:34:09 2002
+++ linux-2.4.20-rc1/Makefile	Tue Oct 29 08:34:31 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -pre11
+EXTRAVERSION = -rc1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.20-pre11/arch/alpha/lib/ev6-stxncpy.S linux-2.4.20-rc1/arch/alpha/lib/ev6-stxncpy.S
--- linux-2.4.20-pre11/arch/alpha/lib/ev6-stxncpy.S	Tue Oct 29 08:34:09 2002
+++ linux-2.4.20-rc1/arch/alpha/lib/ev6-stxncpy.S	Tue Oct 29 08:34:32 2002
@@ -38,7 +38,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <asm/regdef.h>
+#include <alpha/regdef.h>
 
 	.set noat
 	.set noreorder
diff -urN linux-2.4.20-pre11/arch/alpha/lib/stxncpy.S linux-2.4.20-rc1/arch/alpha/lib/stxncpy.S
--- linux-2.4.20-pre11/arch/alpha/lib/stxncpy.S	Tue Oct 29 08:34:09 2002
+++ linux-2.4.20-rc1/arch/alpha/lib/stxncpy.S	Tue Oct 29 08:34:32 2002
@@ -28,7 +28,7 @@
  * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
  */
 
-#include <asm/regdef.h>
+#include <alpha/regdef.h>
 
 	.set noat
 	.set noreorder
diff -urN linux-2.4.20-pre11/arch/i386/kernel/dmi_scan.c linux-2.4.20-rc1/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20-pre11/arch/i386/kernel/dmi_scan.c	Tue Oct 29 08:34:11 2002
+++ linux-2.4.20-rc1/arch/i386/kernel/dmi_scan.c	Tue Oct 29 08:34:32 2002
@@ -31,7 +31,7 @@
 	if(!s)
 		return "";
 	s--;
-	while(s>0)
+	while(s>0 && *bp)
 	{
 		bp+=strlen(bp);
 		bp++;
@@ -50,7 +50,7 @@
 	u8 *buf;
 	struct dmi_header *dm;
 	u8 *data;
-	int i=1;
+	int i=0;
 		
 	buf = bt_ioremap(base, len);
 	if(buf==NULL)
@@ -59,28 +59,23 @@
 	data = buf;
 
 	/*
- 	 *	Stop when we see al the items the table claimed to have
+ 	 *	Stop when we see all the items the table claimed to have
  	 *	OR we run off the end of the table (also happens)
  	 */
  
-	while(i<num && (data - buf) < len)
+	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
 	{
 		dm=(struct dmi_header *)data;
-	
 		/*
-		 *	Avoid misparsing crud if the length of the last
-	 	 *	record is crap 
+		 *  We want to know the total length (formated area and strings)
+		 *  before decoding to make sure we won't run off the table in
+		 *  dmi_decode or dmi_string
 		 */
-		if((data-buf+dm->length) >= len)
-			break;
-		decode(dm);		
 		data+=dm->length;
-		/*
-		 *	Don't go off the end of the data if there is
-	 	 *	stuff looking like string fill past the end
-	 	 */
-		while((data-buf) < len && (*data || data[1]))
+		while(data-buf<len-1 && (data[0] || data[1]))
 			data++;
+		if(data-buf<len-1)
+			decode(dm);
 		data+=2;
 		i++;
 	}
@@ -89,11 +84,20 @@
 }
 
 
+inline static int __init dmi_checksum(u8 *buf)
+{
+	u8 sum=0;
+	int a;
+	
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-	unsigned char buf[20];
-	long fp=0xE0000L;
-	fp -= 16;
+	u8 buf[15];
+	u32 fp=0xF0000;
 
 #ifdef CONFIG_SIMNOW
 	/*
@@ -105,24 +109,30 @@
  	
 	while( fp < 0xFFFFF)
 	{
-		fp+=16;
-		isa_memcpy_fromio(buf, fp, 20);
-		if(memcmp(buf, "_DMI_", 5)==0)
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
 		{
 			u16 num=buf[13]<<8|buf[12];
 			u16 len=buf[7]<<8|buf[6];
 			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
 
-			dmi_printk((KERN_INFO "DMI %d.%d present.\n",
-				buf[14]>>4, buf[14]&0x0F));
+			/*
+			 * DMI version 0.0 means that the real version is taken from
+			 * the SMBIOS version, which we don't know at this point.
+			 */
+			if(buf[14]!=0)
+				dmi_printk((KERN_INFO "DMI %d.%d present.\n",
+					buf[14]>>4, buf[14]&0x0F));
+			else
+				dmi_printk((KERN_INFO "DMI present.\n"));
 			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-				buf[13]<<8|buf[12],
-				buf[7]<<8|buf[6]));
+				num, len));
 			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
-				buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
+				base));
 			if(dmi_table(base,len, num, decode)==0)
 				return 0;
 		}
+		fp+=16;
 	}
 	return -1;
 }
@@ -475,6 +485,22 @@
 	return 0;
 }
 
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int broken_hp_bios_irq9;
+	if (broken_hp_bios_irq9 == 0)
+	{
+		broken_hp_bios_irq9 = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
 
 /*
  *	Simple "print if true" callback
@@ -755,7 +781,14 @@
 			NO_MATCH, NO_MATCH
 			} },
 	 
-			
+	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+			} },
+ 
+
 	/*
 	 *	Generic per vendor APM settings
 	 */
@@ -810,59 +843,43 @@
 static void __init dmi_decode(struct dmi_header *dm)
 {
 	u8 *data = (u8 *)dm;
-	char *p;
 	
 	switch(dm->type)
 	{
 		case  0:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("BIOS Vendor: %s\n", p));
-				dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-				dmi_printk(("BIOS Version: %s\n", 
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-				dmi_printk(("BIOS Release: %s\n",
-					dmi_string(dm, data[8])));
-				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
-			}
+			dmi_printk(("BIOS Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+			dmi_printk(("BIOS Version: %s\n", 
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+			dmi_printk(("BIOS Release: %s\n",
+				dmi_string(dm, data[8])));
+			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			break;
-			
 		case 1:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("System Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-				dmi_printk(("Product Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-				dmi_printk(("Version %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-				dmi_printk(("Serial Number %s.\n",
-					dmi_string(dm, data[7])));
-			}
+			dmi_printk(("System Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+			dmi_printk(("Product Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+			dmi_printk(("Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+			dmi_printk(("Serial Number: %s\n",
+				dmi_string(dm, data[7])));
 			break;
 		case 2:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("Board Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-				dmi_printk(("Board Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-				dmi_printk(("Board Version: %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
-			}
-			break;
-		case 3:
-			p=dmi_string(dm,data[8]);
-			if(*p && *p!=' ')
-				dmi_printk(("Asset Tag: %s.\n", p));
+			dmi_printk(("Board Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+			dmi_printk(("Board Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+			dmi_printk(("Board Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
 			break;
 	}
 }
diff -urN linux-2.4.20-pre11/arch/i386/kernel/io_apic.c linux-2.4.20-rc1/arch/i386/kernel/io_apic.c
--- linux-2.4.20-pre11/arch/i386/kernel/io_apic.c	Tue Oct 29 08:34:11 2002
+++ linux-2.4.20-rc1/arch/i386/kernel/io_apic.c	Tue Oct 29 08:34:32 2002
@@ -40,6 +40,10 @@
 
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
+unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
+unsigned char int_delivery_mode = dest_LowestPrio;
+
+
 /*
  * # of IRQ routing registers
  */
diff -urN linux-2.4.20-pre11/arch/i386/kernel/mpparse.c linux-2.4.20-rc1/arch/i386/kernel/mpparse.c
--- linux-2.4.20-pre11/arch/i386/kernel/mpparse.c	Tue Oct 29 08:34:11 2002
+++ linux-2.4.20-rc1/arch/i386/kernel/mpparse.c	Tue Oct 29 08:34:33 2002
@@ -66,8 +66,6 @@
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
-unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
-unsigned char int_delivery_mode = dest_LowestPrio;
 unsigned char esr_disable = 0;
 
 /*
diff -urN linux-2.4.20-pre11/arch/i386/kernel/pci-irq.c linux-2.4.20-rc1/arch/i386/kernel/pci-irq.c
--- linux-2.4.20-pre11/arch/i386/kernel/pci-irq.c	Fri Aug  2 17:39:42 2002
+++ linux-2.4.20-rc1/arch/i386/kernel/pci-irq.c	Tue Oct 29 08:34:33 2002
@@ -22,6 +22,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+int broken_hp_bios_irq9;
+
 static struct irq_routing_table *pirq_table;
 
 /*
@@ -596,6 +598,15 @@
 	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
 	mask &= pcibios_irq_mask;
 
+	/* Work around broken HP Pavilion Notebooks which assign USB to
+	   IRQ 9 even though it is actually wired to IRQ 11 */
+
+	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+		r->set(pirq_router_dev, dev, pirq, 11);
+	}
+
 	/*
 	 * Find the best IRQ to assign: use the one
 	 * reported by the device if possible.
diff -urN linux-2.4.20-pre11/arch/ppc/boot/simple/misc-spruce.c linux-2.4.20-rc1/arch/ppc/boot/simple/misc-spruce.c
--- linux-2.4.20-pre11/arch/ppc/boot/simple/misc-spruce.c	Tue Oct 29 08:34:19 2002
+++ linux-2.4.20-rc1/arch/ppc/boot/simple/misc-spruce.c	Tue Oct 29 08:34:41 2002
@@ -172,15 +172,15 @@
 	int loop;
 	int csr0;
 	int csr_id;
-	int *mem_addr = (int *)0xff500008;
-	int *mem_data = (int *)0xff50000c;
+	volatile int *mem_addr = (int *)0xff500008;
+	volatile int *mem_data = (int *)0xff50000c;
 	int mem_size = 0;
 	unsigned long mem_mben;
 	unsigned long mem_type;
 	unsigned long mem_start;
 	unsigned long mem_end;
-	int *pif_addr = (int *)0xff500000;
-	int *pif_data = (int *)0xff500004;
+	volatile int *pif_addr = (int *)0xff500000;
+	volatile int *pif_data = (int *)0xff500004;
 	int pci_devfn;
 	int found_multi = 0;
 	unsigned short vendor;
diff -urN linux-2.4.20-pre11/arch/ppc/kernel/Makefile linux-2.4.20-rc1/arch/ppc/kernel/Makefile
--- linux-2.4.20-pre11/arch/ppc/kernel/Makefile	Tue Oct 29 08:34:20 2002
+++ linux-2.4.20-rc1/arch/ppc/kernel/Makefile	Tue Oct 29 08:34:42 2002
@@ -23,7 +23,8 @@
 CFLAGS_btext.o		+= -mrelocatable-lib
 
 # Start off with 'head.o', change as needed.
-HEAD-y				:= head.o idle_6xx.o
+HEAD-y				:= head.o
+HEAD-$(CONFIG_6xx)		+= idle_6xx.o
 HEAD-$(CONFIG_4xx)		:= head_4xx.o
 HEAD-$(CONFIG_8xx)		:= head_8xx.o
 
diff -urN linux-2.4.20-pre11/arch/ppc/kernel/idle.c linux-2.4.20-rc1/arch/ppc/kernel/idle.c
--- linux-2.4.20-pre11/arch/ppc/kernel/idle.c	Tue Oct 29 08:34:20 2002
+++ linux-2.4.20-rc1/arch/ppc/kernel/idle.c	Tue Oct 29 08:34:42 2002
@@ -33,12 +33,12 @@
 #include <asm/cache.h>
 #include <asm/cputable.h>
 
-unsigned long zero_paged_on = 0;
-unsigned long powersave_nap = 0;
+unsigned long zero_paged_on;
+unsigned long powersave_nap;
+unsigned long powersave_lowspeed;
 
 #ifdef CONFIG_6xx
 extern void power_save_6xx(void);
-unsigned long powersave_lowspeed = 0;
 #endif
 
 int idled(void)
diff -urN linux-2.4.20-pre11/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20-rc1/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.20-pre11/arch/ppc/kernel/ppc_ksyms.c	Tue Oct 29 08:34:20 2002
+++ linux-2.4.20-rc1/arch/ppc/kernel/ppc_ksyms.c	Tue Oct 29 08:34:42 2002
@@ -167,7 +167,8 @@
 EXPORT_SYMBOL(iopa);
 EXPORT_SYMBOL(mm_ptov);
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
+	defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
 EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
 #endif
@@ -265,6 +266,10 @@
 EXPORT_SYMBOL(pci_phys_to_bus);
 EXPORT_SYMBOL(pci_bus_to_phys);
 EXPORT_SYMBOL(pmac_newworld);
+EXPORT_SYMBOL(nvram_read_byte);
+EXPORT_SYMBOL(nvram_write_byte);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
 #endif /* defined(CONFIG_ALL_PPC) */
 #if defined(CONFIG_BOOTX_TEXT)
 EXPORT_SYMBOL(btext_update_display);
@@ -275,12 +280,6 @@
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
 #endif
-#ifdef CONFIG_NVRAM
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
-#endif /* CONFIG_NVRAM */
 EXPORT_SYMBOL(to_tm);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
diff -urN linux-2.4.20-pre11/arch/ppc/kernel/setup.c linux-2.4.20-rc1/arch/ppc/kernel/setup.c
--- linux-2.4.20-pre11/arch/ppc/kernel/setup.c	Tue Oct 29 08:34:20 2002
+++ linux-2.4.20-rc1/arch/ppc/kernel/setup.c	Tue Oct 29 08:34:42 2002
@@ -456,7 +456,8 @@
 		ulong *data = rec->data;
 		switch (rec->tag) {
 		case BI_CMD_LINE:
-			memcpy(cmd_line, (void *)data, rec->size);
+			memcpy(cmd_line, (void *)data, rec->size - 
+					sizeof(struct bi_record));
 			break;
 		case BI_SYSMAP:
 			sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] :
@@ -603,7 +604,8 @@
 	ppc_md.ppc_machine = _machine;
 }
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
+	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 /* Convert the shorts/longs in hd_driveid from little to big endian;
  * chars are endian independant, of course, but strings need to be flipped.
  * (Despite what it says in drivers/block/ide.h, they come up as little
diff -urN linux-2.4.20-pre11/arch/ppc/platforms/Makefile linux-2.4.20-rc1/arch/ppc/platforms/Makefile
--- linux-2.4.20-pre11/arch/ppc/platforms/Makefile	Tue Oct 29 08:34:21 2002
+++ linux-2.4.20-rc1/arch/ppc/platforms/Makefile	Tue Oct 29 08:34:42 2002
@@ -40,14 +40,8 @@
 obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
 					pmac_feature.o pmac_pci.o chrp_setup.o\
 					chrp_time.o chrp_pci.o prep_pci.o \
-					prep_time.o prep_setup.o pmac_sleep.o
-# CONFIG_NVRAM can't be 'm' on CONFIG_ALL_PPC, only 'y' or 'n'.
-ifeq ($(CONFIG_NVRAM),y)
-obj-$(CONFIG_ALL_PPC)		+= pmac_nvram.o
-endif
-ifeq ($(CONFIG_NVRAM),m)
-obj-$(CONFIG_ALL_PPC)		+= pmac_nvram.o
-endif
+					prep_time.o prep_setup.o pmac_sleep.o \
+					pmac_nvram.o
 obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
 obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
diff -urN linux-2.4.20-pre11/arch/ppc64/kernel/ioctl32.c linux-2.4.20-rc1/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.20-pre11/arch/ppc64/kernel/ioctl32.c	Tue Oct 29 08:34:21 2002
+++ linux-2.4.20-rc1/arch/ppc64/kernel/ioctl32.c	Tue Oct 29 08:34:43 2002
@@ -756,6 +756,11 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -804,6 +809,9 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
+	if (mysock)
+		sockfd_put(mysock);
+
 	return ret;
 }
 
diff -urN linux-2.4.20-pre11/arch/sparc/kernel/sparc_ksyms.c linux-2.4.20-rc1/arch/sparc/kernel/sparc_ksyms.c
--- linux-2.4.20-pre11/arch/sparc/kernel/sparc_ksyms.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-rc1/arch/sparc/kernel/sparc_ksyms.c	Tue Oct 29 08:34:45 2002
@@ -46,6 +46,9 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
+#ifdef CONFIG_HIGHMEM
+#include <linux/highmem.h>
+#endif
 #include <asm/a.out.h>
 #include <asm/io-unit.h>
 
@@ -204,6 +207,12 @@
 EXPORT_SYMBOL(pci_dma_sync_single);
 #endif
 
+/* in arch/sparc/mm/highmem.c */
+#ifdef CONFIG_HIGHMEM
+EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(kunmap_atomic);
+#endif
+
 /* Solaris/SunOS binary compatibility */
 EXPORT_SYMBOL(svr4_setcontext);
 EXPORT_SYMBOL(svr4_getcontext);
diff -urN linux-2.4.20-pre11/arch/sparc/mm/Makefile linux-2.4.20-rc1/arch/sparc/mm/Makefile
--- linux-2.4.20-pre11/arch/sparc/mm/Makefile	Fri Dec 29 14:07:21 2000
+++ linux-2.4.20-rc1/arch/sparc/mm/Makefile	Tue Oct 29 08:34:45 2002
@@ -10,19 +10,24 @@
 .S.o:
 	$(CC) $(AFLAGS) -ansi -c -o $*.o $<
 
-O_TARGET := mm.o
-obj-y    := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
+O_TARGET	:= mm.o
+obj-y		:= fault.o init.o loadmmu.o generic.o extable.o btfixup.o
 
 ifeq ($(CONFIG_SUN4),y)
-obj-y	 += nosrmmu.o
+obj-y		+= nosrmmu.o
 else
-obj-y	 += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
+obj-y		+= srmmu.o iommu.o io-unit.o hypersparc.o viking.o \
+			tsunami.o swift.o
+endif
+
+ifdef CONFIG_HIGHMEM
+obj-y		+= highmem.o
 endif
 
 ifdef CONFIG_SMP
-obj-y   += nosun4c.o
+obj-y		+= nosun4c.o
 else
-obj-y   += sun4c.o
+obj-y		+= sun4c.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.20-pre11/arch/sparc/mm/highmem.c linux-2.4.20-rc1/arch/sparc/mm/highmem.c
--- linux-2.4.20-pre11/arch/sparc/mm/highmem.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.20-rc1/arch/sparc/mm/highmem.c	Tue Oct 29 08:34:45 2002
@@ -0,0 +1,84 @@
+/*
+ *  highmem.c: virtual kernel memory mappings for high memory
+ *
+ *  Provides kernel-static versions of atomic kmap functions originally
+ *  found as inlines in include/asm-sparc/highmem.h.  These became
+ *  needed as kmap_atomic() and kunmap_atomic() started getting
+ *  called from within modules.
+ *  -- Tomas Szepe <szepe@pinerecords.com>, September 2002
+ */
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/pgalloc.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged -- kmap()/kunmap()
+ * gives a more generic (and caching) interface.  But kmap_atomic() can
+ * be used in IRQ contexts, so in some (very limited) cases we need it.
+ */
+void *kmap_atomic(struct page *page, enum km_type type)
+{
+	unsigned long idx;
+	unsigned long vaddr;
+
+	if (page < highmem_start_page)
+		return page_address(page);
+
+	idx = type + KM_TYPE_NR * smp_processor_id();
+	vaddr = fix_kmap_begin + idx * PAGE_SIZE;
+
+/* XXX Fix - Anton */
+#if 0
+	__flush_cache_one(vaddr);
+#else
+	flush_cache_all();
+#endif
+
+#if HIGHMEM_DEBUG
+	if (!pte_none(*(kmap_pte + idx)))
+		BUG();
+#endif
+	set_pte(kmap_pte + idx, mk_pte(page, kmap_prot));
+/* XXX Fix - Anton */
+#if 0
+	__flush_tlb_one(vaddr);
+#else
+	flush_tlb_all();
+#endif
+
+	return (void *) vaddr;
+}
+
+void kunmap_atomic(void *kvaddr, enum km_type type)
+{
+	unsigned long vaddr = (unsigned long) kvaddr;
+	unsigned long idx = type + KM_TYPE_NR * smp_processor_id();
+
+	if (vaddr < fix_kmap_begin) /* FIXME */
+		return;
+
+	if (vaddr != fix_kmap_begin + idx * PAGE_SIZE)
+		BUG();
+
+/* XXX Fix - Anton */
+#if 0
+	__flush_cache_one(vaddr);
+#else
+	flush_cache_all();
+#endif
+
+#ifdef HIGHMEM_DEBUG
+	/*
+	 *  Force other mappings to oops if they try to access
+	 *  this pte without first remapping it.
+	 */
+	pte_clear(kmap_pte + idx);
+/* XXX Fix - Anton */
+#if 0
+	__flush_tlb_one(vaddr);
+#else
+	flush_tlb_all();
+#endif
+#endif
+}
diff -urN linux-2.4.20-pre11/arch/sparc64/defconfig linux-2.4.20-rc1/arch/sparc64/defconfig
--- linux-2.4.20-pre11/arch/sparc64/defconfig	Tue Oct 29 08:34:23 2002
+++ linux-2.4.20-rc1/arch/sparc64/defconfig	Tue Oct 29 08:34:45 2002
@@ -499,6 +499,7 @@
 CONFIG_SIS900=m
 CONFIG_EPIC100=m
 CONFIG_SUNDANCE=m
+CONFIG_SUNDANCE_MMIO=y
 # CONFIG_TLAN is not set
 # CONFIG_TC35815 is not set
 CONFIG_VIA_RHINE=m
diff -urN linux-2.4.20-pre11/arch/sparc64/kernel/ioctl32.c linux-2.4.20-rc1/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.20-pre11/arch/sparc64/kernel/ioctl32.c	Tue Oct 29 08:34:23 2002
+++ linux-2.4.20-rc1/arch/sparc64/kernel/ioctl32.c	Tue Oct 29 08:34:46 2002
@@ -799,6 +799,11 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -847,6 +852,9 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
+	if (mysock)
+		sockfd_put(mysock);
+
 	return ret;
 }
 
@@ -867,10 +875,39 @@
 	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
 	set_fs (old_fs);
 	if (!err) {
-		err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
-		err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
+		if (copy_to_user ((struct hd_geometry32 *)arg, &geo, 4) ||
+		    __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)))
+			err = -EFAULT;
 	}
-	return err ? -EFAULT : 0;
+	return err;
+}
+
+struct hd_big_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	u32 start;
+};
+                        
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		struct hd_big_geometry32 *up = (struct hd_big_geometry32 *) arg;
+
+		if (put_user(geo.heads, &up->heads) ||
+		    __put_user(geo.sectors, &up->sectors) ||
+		    __put_user(geo.cylinders, &up->cylinders) ||
+		    __put_user(((u32) geo.start), &up->start))
+			err = -EFAULT;
+	}
+	return err;
 }
 
 struct  fbcmap32 {
@@ -4216,6 +4253,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -4342,10 +4412,6 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKBSZGET)
-COMPATIBLE_IOCTL(BLKBSZSET)
-COMPATIBLE_IOCTL(BLKGETSIZE64)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -4885,9 +4951,6 @@
 COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
 COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
 #endif /* DRM */
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
 /* Big W */
 /* WIOC_GETSUPPORT not yet implemented -E */
 COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
@@ -5007,6 +5070,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
+HANDLE_IOCTL(HDIO_GETGEO_BIG, hdio_getgeo_big)
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big)
 HANDLE_IOCTL(BLKRAGET, w_long)
 HANDLE_IOCTL(BLKGETSIZE, w_long)
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
@@ -5147,6 +5212,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
 IOCTL_TABLE_END
 
 unsigned int ioctl32_hash_table[1024];
diff -urN linux-2.4.20-pre11/arch/sparc64/kernel/pci_schizo.c linux-2.4.20-rc1/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.20-pre11/arch/sparc64/kernel/pci_schizo.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-rc1/arch/sparc64/kernel/pci_schizo.c	Tue Oct 29 08:34:46 2002
@@ -1112,7 +1112,7 @@
 	u64 tmp;
 
 	/* Build IRQs and register handlers. */
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_UE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_UE_INO);
 	if (request_irq(irq, schizo_ue_intr,
 			SA_SHIRQ, "SCHIZO UE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register UE interrupt.\n",
@@ -1123,7 +1123,7 @@
 	tmp = readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_CE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_CE_INO);
 	if (request_irq(irq, schizo_ce_intr,
 			SA_SHIRQ, "SCHIZO CE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register CE interrupt.\n",
@@ -1143,9 +1143,9 @@
 	}
 	bucket = __bucket(irq);
 	tmp = upa_readl(bucket->imap);
-	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+	upa_writel(tmp, (base + SCHIZO_PBM_A_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
 	if (request_irq(irq, schizo_pcierr_intr,
 			SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n",
@@ -1156,7 +1156,7 @@
 	tmp = upa_readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_SERR_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_SERR_INO);
 	if (request_irq(irq, schizo_safarierr_intr,
 			SA_SHIRQ, "SCHIZO SERR", p) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n",
diff -urN linux-2.4.20-pre11/arch/sparc64/lib/U3copy_from_user.S linux-2.4.20-rc1/arch/sparc64/lib/U3copy_from_user.S
--- linux-2.4.20-pre11/arch/sparc64/lib/U3copy_from_user.S	Mon Feb 25 11:37:56 2002
+++ linux-2.4.20-rc1/arch/sparc64/lib/U3copy_from_user.S	Tue Oct 29 08:34:46 2002
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #define EXNV(x,y,a,b)			\
 98:	x,y;				\
@@ -181,6 +183,16 @@
 
 	.align		64
 U3copy_from_user_begin:
+#ifdef __KERNEL__
+	.globl		U3copy_from_user_nop_1_6
+U3copy_from_user_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetcha	[%o1 + 0x000] %asi, #one_read	! MS	Group1
 	prefetcha	[%o1 + 0x040] %asi, #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -321,6 +333,13 @@
 	stda		%f16, [%o0] ASI_BLK_P		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3copy_from_user_nop_2_3
+U3copy_from_user_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -urN linux-2.4.20-pre11/arch/sparc64/lib/U3copy_to_user.S linux-2.4.20-rc1/arch/sparc64/lib/U3copy_to_user.S
--- linux-2.4.20-pre11/arch/sparc64/lib/U3copy_to_user.S	Thu Nov  9 15:57:41 2000
+++ linux-2.4.20-rc1/arch/sparc64/lib/U3copy_to_user.S	Tue Oct 29 08:34:46 2002
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #define EXNV(x,y,a,b)	\
 98:	x,y;				\
@@ -228,6 +230,16 @@
 
 	.align		64
 U3copy_to_user_begin:
+#ifdef __KERNEL__
+	.globl		U3copy_to_user_nop_1_6
+U3copy_to_user_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
 	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -368,6 +380,13 @@
 	EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3copy_to_user_nop_2_3
+U3copy_to_user_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -urN linux-2.4.20-pre11/arch/sparc64/lib/U3memcpy.S linux-2.4.20-rc1/arch/sparc64/lib/U3memcpy.S
--- linux-2.4.20-pre11/arch/sparc64/lib/U3memcpy.S	Thu Nov  9 15:57:41 2000
+++ linux-2.4.20-rc1/arch/sparc64/lib/U3memcpy.S	Tue Oct 29 08:34:46 2002
@@ -7,6 +7,8 @@
 #ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #undef SMALL_COPY_USES_FPU
 #else
 #define ASI_BLK_P 0xf0
@@ -109,6 +111,16 @@
 
 	.align		64
 U3memcpy_begin:
+#ifdef __KERNEL__
+	.globl		U3memcpy_nop_1_6
+U3memcpy_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o3
+	sllx		%o3, 32, %o3
+	or		%g3, %o3, %o3
+	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+#endif
 	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
 	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
 	andn		%o2, (0x40 - 1), %o4		! A0
@@ -249,6 +261,13 @@
 	stda		%f16, [%o0] ASI_BLK_P		! MS
 	add		%o0, 0x40, %o0			! A0
 	add		%o1, 0x40, %o1			! A1
+#ifdef __KERNEL__
+	.globl		U3memcpy_nop_2_3
+U3memcpy_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o3
+	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
+#endif
 	membar		#Sync				! MS	Group26 (7-cycle stall)
 
 	/* Now we copy the (len modulo 64) bytes at the end.
diff -urN linux-2.4.20-pre11/arch/sparc64/lib/VIScopy.S linux-2.4.20-rc1/arch/sparc64/lib/VIScopy.S
--- linux-2.4.20-pre11/arch/sparc64/lib/VIScopy.S	Mon Oct  1 09:19:56 2001
+++ linux-2.4.20-rc1/arch/sparc64/lib/VIScopy.S	Tue Oct 29 08:34:46 2002
@@ -368,6 +368,28 @@
 	or	%g3, %lo(NOP), %g3; \
 	stw	%g3, [%g2 + 0x4]; \
 	flush	%g2;
+#define ULTRA3_PCACHE_DO_NOP(symbol)	\
+	sethi	%hi(symbol##_nop_1_6), %g1; \
+	or	%g1, %lo(symbol##_nop_1_6), %g1; \
+	sethi	%hi(NOP), %g2; \
+	stw	%g2, [%g1 + 0x00]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x00; \
+	stw	%g2, [%g1 + 0x08]; \
+	stw	%g2, [%g1 + 0x0c]; \
+	flush	%g1 + 0x08; \
+	stw	%g2, [%g1 + 0x10]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x10; \
+	sethi	%hi(symbol##_nop_2_3), %g1; \
+	or	%g1, %lo(symbol##_nop_2_3), %g1; \
+	stw	%g2, [%g1 + 0x00]; \
+	stw	%g2, [%g1 + 0x04]; \
+	flush	%g1 + 0x00; \
+	stw	%g2, [%g1 + 0x08]; \
+	flush	%g1 + 0x08;
+
+#include <asm/dcu.h>
 
 	.globl	cheetah_patch_copyops
 cheetah_patch_copyops:
@@ -375,6 +397,23 @@
 	ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user)
 	ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user)
 	ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user)
+#if 0 /* Causes data corruption, nop out the optimization
+       * for now -DaveM
+       */
+	ldxa			[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi			%uhi(DCU_PE), %o3
+	sllx			%o3, 32, %o3
+	andcc			%g3, %o3, %g0
+	be,pn			%xcc, pcache_disabled
+	 nop
+#endif
+	ULTRA3_PCACHE_DO_NOP(U3memcpy)
+	ULTRA3_PCACHE_DO_NOP(U3copy_from_user)
+	ULTRA3_PCACHE_DO_NOP(U3copy_to_user)
+	ULTRA3_PCACHE_DO_NOP(cheetah_copy_user_page)
+#if 0
+pcache_disabled:
+#endif
 	retl
 	 nop
 #undef BRANCH_ALWAYS
diff -urN linux-2.4.20-pre11/arch/sparc64/lib/blockops.S linux-2.4.20-rc1/arch/sparc64/lib/blockops.S
--- linux-2.4.20-pre11/arch/sparc64/lib/blockops.S	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/arch/sparc64/lib/blockops.S	Tue Oct 29 08:34:46 2002
@@ -8,6 +8,8 @@
 #include "VIS.h"
 #include <asm/visasm.h>
 #include <asm/page.h>
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
 #include <asm/pgtable.h>
 #include <asm/asm_offsets.h>
 
@@ -109,6 +111,15 @@
 	 nop
 
 cheetah_copy_user_page:
+	.globl		cheetah_copy_user_page_nop_1_6
+cheetah_copy_user_page_nop_1_6:
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
+	sethi		%uhi(DCU_PE), %o2
+	sllx		%o2, 32, %o2
+	or		%g3, %o2, %o2
+	stxa		%o2, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
+	membar		#Sync
+
 	sethi		%hi((PAGE_SIZE/64)-7), %o2	! A0 Group
 	prefetch	[%o1 + 0x000], #one_read	! MS
 	or		%o2, %lo((PAGE_SIZE/64)-7), %o2	! A1 Group
@@ -200,6 +211,11 @@
 	fmovd		%f12, %f44			! FGA Group
 	fmovd		%f14, %f46			! FGA Group
 	stda		%f32, [%o0] ASI_BLK_P		! MS
+	.globl		cheetah_copy_user_page_nop_2_3
+cheetah_copy_user_page_nop_2_3:
+	mov		PRIMARY_CONTEXT, %o2
+	stxa		%g0, [%o2] ASI_DMMU		! Flush P-cache
+	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
 	ba,a,pt		%xcc, copy_user_page_continue
 
 spitfire_copy_user_page:
diff -urN linux-2.4.20-pre11/arch/sparc64/mm/init.c linux-2.4.20-rc1/arch/sparc64/mm/init.c
--- linux-2.4.20-pre11/arch/sparc64/mm/init.c	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/arch/sparc64/mm/init.c	Tue Oct 29 08:34:46 2002
@@ -1268,6 +1268,8 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
+	max_pfn = max_low_pfn = end_pfn;
+	min_low_pfn = phys_base >> PAGE_SHIFT;
 	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, end_pfn);
 
 	/* Now register the available physical memory with the
diff -urN linux-2.4.20-pre11/arch/sparc64/solaris/misc.c linux-2.4.20-rc1/arch/sparc64/solaris/misc.c
--- linux-2.4.20-pre11/arch/sparc64/solaris/misc.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-rc1/arch/sparc64/solaris/misc.c	Tue Oct 29 08:34:46 2002
@@ -724,6 +724,7 @@
 
 MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
 MODULE_DESCRIPTION("Solaris binary emulation module");
+MODULE_LICENSE("GPL");
 EXPORT_NO_SYMBOLS;
 
 #ifdef __sparc_v9__
diff -urN linux-2.4.20-pre11/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.20-rc1/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.20-pre11/arch/x86_64/ia32/ia32_ioctl.c	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/arch/x86_64/ia32/ia32_ioctl.c	Tue Oct 29 08:34:46 2002
@@ -716,6 +716,11 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file);
+}
+
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -764,6 +769,9 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
+	if (mysock)
+		sockfd_put(mysock);
+
 	return ret;
 }
 
diff -urN linux-2.4.20-pre11/drivers/block/genhd.c linux-2.4.20-rc1/drivers/block/genhd.c
--- linux-2.4.20-pre11/drivers/block/genhd.c	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/drivers/block/genhd.c	Tue Oct 29 08:34:48 2002
@@ -155,13 +155,14 @@
 
 #ifdef CONFIG_PROC_FS
 /* iterator */
-static void *part_start(struct seq_file *s, loff_t *pos)
+static void *part_start(struct seq_file *s, loff_t *ppos)
 {
 	struct gendisk *gp;
+	loff_t pos = *ppos;
 
 	read_lock(&gendisk_lock);
 	for (gp = gendisk_head; gp; gp = gp->next)
-		if (!*pos--)
+		if (!pos--)
 			return gp;
 	return NULL;
 }
diff -urN linux-2.4.20-pre11/drivers/char/ChangeLog linux-2.4.20-rc1/drivers/char/ChangeLog
--- linux-2.4.20-pre11/drivers/char/ChangeLog	Mon Aug 13 16:37:33 2001
+++ linux-2.4.20-rc1/drivers/char/ChangeLog	Tue Oct 29 08:34:48 2002
@@ -550,7 +550,7 @@
 		the StarTech 16650 chip.  Treat it as a 16450 for now,
 		because of its FIFO bugs.
 
-Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
+Thu Jan  5 21:21:57 1995  <dahinds@users.sourceforge.net>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
 		when a PCMCIA serial device is ejected.
diff -urN linux-2.4.20-pre11/drivers/char/Config.in linux-2.4.20-rc1/drivers/char/Config.in
--- linux-2.4.20-pre11/drivers/char/Config.in	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/drivers/char/Config.in	Tue Oct 29 08:34:48 2002
@@ -148,7 +148,10 @@
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
-dep_bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE $CONFIG_PPC64
+
+if [ "$CONFIG_PPC64" ] ; then 
+bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
+fi
 
 source drivers/i2c/Config.in
 
diff -urN linux-2.4.20-pre11/drivers/ide/ide-cs.c linux-2.4.20-rc1/drivers/ide/ide-cs.c
--- linux-2.4.20-pre11/drivers/ide/ide-cs.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/ide/ide-cs.c	Tue Oct 29 08:34:55 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/ide/ide-pci.c linux-2.4.20-rc1/drivers/ide/ide-pci.c
--- linux-2.4.20-pre11/drivers/ide/ide-pci.c	Tue Oct 29 08:34:24 2002
+++ linux-2.4.20-rc1/drivers/ide/ide-pci.c	Tue Oct 29 08:34:55 2002
@@ -405,7 +405,7 @@
 #ifndef CONFIG_PDC202XX_FORCE
         {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
         {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
         {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
 #else /* !CONFIG_PDC202XX_FORCE */
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
diff -urN linux-2.4.20-pre11/drivers/mtd/ftl.c linux-2.4.20-rc1/drivers/mtd/ftl.c
--- linux-2.4.20-pre11/drivers/mtd/ftl.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/mtd/ftl.c	Tue Oct 29 08:35:02 2002
@@ -26,7 +26,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -1455,5 +1455,5 @@
 
 
 MODULE_LICENSE("Dual MPL/GPL");
-MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
diff -urN linux-2.4.20-pre11/drivers/net/e100/e100.h linux-2.4.20-rc1/drivers/net/e100/e100.h
--- linux-2.4.20-pre11/drivers/net/e100/e100.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e100/e100.h	Tue Oct 29 08:35:06 2002
@@ -121,7 +121,6 @@
 #define E100_DEFAULT_CPUSAVER_BUNDLE_MAX	6
 #define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY	0x600
 #define E100_DEFAULT_BUNDLE_SMALL_FR		false
-#define E100_DEFAULT_RX_CONGESTION_CONTROL	true
 
 /* end of configurables */
 
@@ -146,8 +145,6 @@
 	unsigned long xmt_tco_pkts;
 	unsigned long rcv_tco_pkts;
 	unsigned long rx_intr_pkts;
-	unsigned long rx_tasklet_pkts;
-	unsigned long poll_intr_switch;
 };
 
 /* TODO: kill me when we can do C99 */
@@ -838,7 +835,6 @@
 #define PRM_FC           0x00000004
 #define PRM_IFS          0x00000008
 #define PRM_BUNDLE_SMALL 0x00000010
-#define PRM_RX_CONG      0x00000020
 
 struct cfg_params {
 	int e100_speed_duplex;
@@ -847,7 +843,6 @@
 	int IntDelay;
 	int BundleMax;
 	int ber;
-	int PollingMaxWork;
 	u32 b_params;
 };
 struct ethtool_lpbk_data{
@@ -949,8 +944,6 @@
 
 	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
 
-	struct tasklet_struct polling_tasklet;
-
 	/* WOL params for ethtool */
 	u32 wolsupported;
 	u32 wolopts;
@@ -961,6 +954,7 @@
 #ifdef CONFIG_PM
 	u32 pci_state[16];
 #endif
+	char ifname[IFNAMSIZ];
 };
 
 #define E100_AUTONEG        0
diff -urN linux-2.4.20-pre11/drivers/net/e100/e100_main.c linux-2.4.20-rc1/drivers/net/e100/e100_main.c
--- linux-2.4.20-pre11/drivers/net/e100/e100_main.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e100/e100_main.c	Tue Oct 29 08:35:06 2002
@@ -46,6 +46,15 @@
 
 /* Change Log
  *
+ * 2.1.24       10/7/02
+ *   o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
+ *     name is changed
+ *   o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
+ *     are executing during stress traffic at shared interrupt system. 
+ *     Removed Rx polling code
+ *   o Added detailed printk if selftest failed when insmod
+ *   o Removed misleading printks
+ *
  * 2.1.12       8/2/02
  *   o Feature: ethtool register dump
  *   o Bug fix: Driver passes wrong name to /proc/interrupts
@@ -62,25 +71,6 @@
  *   o Bug fix: PHY loopback diagnostic fails
  *
  * 2.1.6        7/5/02
- *   o Added device ID support for Dell LOM.
- *   o Added device ID support for 82511QM mobile nics.
- *   o Bug fix: ethtool get/set EEPROM routines modified to use byte
- *     addressing rather than word addressing.
- *   o Feature: added MDIX mode support for 82550 and up.
- *   o Bug fix: added reboot notifer to setup WOL settings when
- *     shutting system down.
- *   o Cleanup: removed yield() redefinition (Andrew Morton, 
- *     akpm@zip.com.au).
- *   o Bug fix: flow control now working when link partner is 
- *     autoneg capable but not flow control capable.
- *   o Bug fix: added check for corrupted EEPROM
- *   o Bug fix: don't report checksum offloading for the older
- *     controllers that don't support the feature.
- *   o Bug fix: calculate cable diagnostics when link goes down
- *     rather than when queuering /proc file.
- *   o Cleanup: move mdi_access_lock to local get/set mdi routines.
- *
- * 2.0.30       5/30/02
  */
  
 #include <linux/config.h>
@@ -94,8 +84,8 @@
 #include "e100_vendor.h"
 
 #ifdef CONFIG_PROC_FS
-extern int e100_create_proc_subdir(struct e100_private *);
-extern void e100_remove_proc_subdir(struct e100_private *);
+extern int e100_create_proc_subdir(struct e100_private *, char *);
+extern void e100_remove_proc_subdir(struct e100_private *, char *);
 #else
 #define e100_create_proc_subdir(X) 0
 #define e100_remove_proc_subdir(X) do {} while(0)
@@ -145,7 +135,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.15-k1";
+char e100_driver_version[]="2.1.24-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -154,12 +144,19 @@
 static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
 static int e100_suspend(struct pci_dev *pcid, u32 state);
 static int e100_resume(struct pci_dev *pcid);
-struct notifier_block e100_notifier = {
+struct notifier_block e100_notifier_reboot = {
         notifier_call:  e100_notify_reboot,
         next:           NULL,
         priority:       0
 };
 #endif
+static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
+ 
+struct notifier_block e100_notifier_netdev = {
+	notifier_call:  e100_notify_netdev,
+	next:           NULL,
+	priority:       0
+};
 
 static void e100_get_mdix_status(struct e100_private *bdp);
 
@@ -349,9 +346,7 @@
 }
 
 void e100_tx_srv(struct e100_private *);
-u32 e100_rx_srv(struct e100_private *, u32, int *);
-
-void e100_polling_tasklet(unsigned long);
+u32 e100_rx_srv(struct e100_private *);
 
 void e100_watchdog(struct net_device *);
 static void e100_do_hwi(struct net_device *);
@@ -379,9 +374,6 @@
 E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");
 E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");
 E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");
-E100_PARAM(RxCongestionControl, "Disable or enable switch to polling mode");
-E100_PARAM(PollingMaxWork, "Max number of receive packets processed on single "
-	   "polling call");
 
 /**
  * e100_exec_cmd - issue a comand
@@ -656,6 +648,8 @@
 	if ((rc = register_netdev(dev)) != 0) {
 		goto err_pci;
 	}
+        memcpy(bdp->ifname, dev->name, IFNAMSIZ);
+        bdp->ifname[IFNAMSIZ-1] = 0;	
 
 	bdp->device_type = ent->driver_data;
 	printk(KERN_NOTICE
@@ -674,7 +668,7 @@
 			bdp->cable_status = "Not available";
 	}
 
-	if (e100_create_proc_subdir(bdp) < 0) {
+	if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
 		printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
 		       bdp->device->name);
 	}
@@ -738,7 +732,7 @@
 
 	unregister_netdev(dev);
 
-	e100_remove_proc_subdir(bdp);
+	e100_remove_proc_subdir(bdp, bdp->ifname);
 
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 
@@ -756,13 +750,13 @@
 MODULE_DEVICE_TABLE(pci, e100_id_table);
 
 static struct pci_driver e100_driver = {
-	name:           "e100",
-	id_table:       e100_id_table,
-	probe:          e100_found1,
-	remove:         __devexit_p(e100_remove1),
-#ifdef CONFIG_PM			
-	suspend:        e100_suspend,
-	resume:         e100_resume,
+	.name         = "e100",
+	.id_table     = e100_id_table,
+	.probe        = e100_found1,
+	.remove       = __devexit_p(e100_remove1),
+#ifdef CONFIG_PM
+	.suspend      = e100_suspend,
+	.resume       = e100_resume,
 #endif
 };
 
@@ -772,10 +766,12 @@
 	int ret;
         ret = pci_module_init(&e100_driver);
 
-#ifdef CONFIG_PM	
-	if(ret >= 0)
-		register_reboot_notifier(&e100_notifier);
-#endif	
+	if(ret >= 0) {
+#ifdef CONFIG_PM
+		register_reboot_notifier(&e100_notifier_reboot);
+#endif 
+		register_netdevice_notifier(&e100_notifier_netdev);
+	}
 
 	return ret;
 }
@@ -784,8 +780,9 @@
 e100_cleanup_module(void)
 {
 #ifdef CONFIG_PM	
-	unregister_reboot_notifier(&e100_notifier);
-#endif	
+	unregister_reboot_notifier(&e100_notifier_reboot);
+#endif 
+	unregister_netdevice_notifier(&e100_notifier_netdev);
 
 	pci_unregister_driver(&e100_driver);
 }
@@ -856,14 +853,6 @@
 			    0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX,
 			    "CPU saver bundle max value");
 
-	e100_set_bool_option(bdp, RxCongestionControl[board], PRM_RX_CONG,
-			     E100_DEFAULT_RX_CONGESTION_CONTROL,
-			     "Rx Congestion Control value");
-
-	e100_set_int_option(&(bdp->params.PollingMaxWork),
-			    PollingMaxWork[board], 1, E100_MAX_RFD,
-			    bdp->params.RxDescriptors,
-			    "Polling Max Work value");
 }
 
 /**
@@ -991,11 +980,6 @@
 		del_timer_sync(&bdp->watchdog_timer);
 		goto err_exit;
 	}
-	if (bdp->params.b_params & PRM_RX_CONG) {
-		DECLARE_TASKLET(polling_tasklet,
-				e100_polling_tasklet, (unsigned long) bdp);
-		bdp->polling_tasklet = polling_tasklet;
-	}
 	bdp->intr_mask = 0;
 	e100_set_intr_mask(bdp);
 
@@ -1024,10 +1008,6 @@
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
-	if (bdp->params.b_params & PRM_RX_CONG) {
-		tasklet_kill(&(bdp->polling_tasklet));
-	}
-
 	/* set the isolate flag to false, so e100_open can be called */
 	bdp->driver_isolated = false;
 
@@ -1263,12 +1243,21 @@
 static unsigned char __devinit
 e100_init(struct e100_private *bdp)
 {
+	u32 st_timeout = 0;
+	u32 st_result = 0;
 	e100_sw_init(bdp);
 
-	if (!e100_selftest(bdp, NULL, NULL)) {
-		printk(KERN_ERR "e100: selftest failed\n");
+	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+        	if (st_timeout) {
+			printk(KERN_ERR "e100: selftest timeout\n");
+		} else {
+			printk(KERN_ERR "e100: selftest failed. Results: %x\n",
+					st_result);
+		}
 		return false;
 	}
+	else
+		printk(KERN_DEBUG "e100: selftest OK.\n");
 
 	/* read the MAC address from the eprom */
 	e100_rd_eaddr(bdp);
@@ -1802,47 +1791,6 @@
 	}
 }
 
-void
-e100_polling_tasklet(unsigned long ptr)
-{
-	struct e100_private *bdp = (struct e100_private *) ptr;
-	unsigned int rx_congestion = 0;
-	u32 skb_cnt;
-
-	/* the device is closed, don't continue or else bad things may happen. */
-	if (!netif_running(bdp->device)) {
-		return;
-	}
-
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		tasklet_schedule(&(bdp->polling_tasklet));
-		goto exit;
-	}
-
-	e100_alloc_skbs(bdp);
-
-	skb_cnt = e100_rx_srv(bdp, bdp->params.PollingMaxWork, &rx_congestion);
-
-	bdp->drv_stats.rx_tasklet_pkts += skb_cnt;
-
-	if (rx_congestion || skb_cnt) {
-		tasklet_schedule(&(bdp->polling_tasklet));
-	} else {
-		bdp->intr_mask &= ~SCB_INT_MASK;
-
-		bdp->drv_stats.poll_intr_switch++;
-	}
-
-	bdp->tx_count = 0;	/* restart tx interrupt batch count */
-	e100_tx_srv(bdp);
-
-	e100_set_intr_mask(bdp);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
-}
-
 /**
  * e100intr - interrupt handler
  * @irq: the IRQ number
@@ -1892,18 +1840,8 @@
 
 	/* do recv work if any */
 	if (intr_status &
-	    (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) {
-		int rx_congestion;
-
-		bdp->drv_stats.rx_intr_pkts +=
-			e100_rx_srv(bdp, 0, &rx_congestion);
-		if ((bdp->params.b_params & PRM_RX_CONG) && rx_congestion) {
-			bdp->intr_mask |= SCB_INT_MASK;
-			tasklet_schedule(&(bdp->polling_tasklet));
-
-			bdp->drv_stats.poll_intr_switch++;
-		}
-	}
+	    (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) 
+		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
 
 	/* clean up after tx'ed packets */
 	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
@@ -1997,8 +1935,7 @@
  * It returns the number of serviced RFDs.
  */
 u32
-e100_rx_srv(struct e100_private *bdp, u32 max_number_of_rfds,
-	    int *rx_congestion)
+e100_rx_srv(struct e100_private *bdp)
 {
 	rfd_t *rfd;		/* new rfd, received rfd */
 	int i;
@@ -2009,10 +1946,6 @@
 	struct rx_list_elem *rx_struct;
 	u32 rfd_cnt = 0;
 
-	if (rx_congestion) {
-		*rx_congestion = 0;
-	}
-
 	dev = bdp->device;
 
 	/* current design of rx is as following:
@@ -2027,9 +1960,6 @@
 	 *    (watchdog trigger SWI intr and isr should allocate new skbs)
 	 */
 	for (i = 0; i < bdp->params.RxDescriptors; i++) {
-		if (max_number_of_rfds && (rfd_cnt >= max_number_of_rfds)) {
-			break;
-		}
 		if (list_empty(&(bdp->active_rx_list))) {
 			break;
 		}
@@ -2094,20 +2024,12 @@
 		} else {
 			skb->ip_summed = CHECKSUM_NONE;
 		}
-
 		switch (netif_rx(skb)) {
 		case NET_RX_BAD:
-			break;
-
 		case NET_RX_DROP:
 		case NET_RX_CN_MOD:
 		case NET_RX_CN_HIGH:
-			if (bdp->params.b_params & PRM_RX_CONG) {
-				if (rx_congestion) {
-					*rx_congestion = 1;
-				}
-			}
-			/* FALL THROUGH TO STATISTICS UPDATE */
+			break;
 		default:
 			bdp->drv_stats.net_stats.rx_bytes += skb->len;
 			break;
@@ -3032,11 +2954,6 @@
 		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
 		       (unsigned long) bdp->device->mem_start,
 		       bdp->device->irq, 0, "N/A");
-
-		/* Auto negotiation failed so we should display an error */
-		printk(KERN_NOTICE "  Failed to detect cable link\n");
-		printk(KERN_NOTICE "  Speed and duplex will be determined "
-		       "at time of connection\n");
 	}
 
 	/* Print the string if checksum Offloading was enabled */
@@ -4176,11 +4093,34 @@
 	spin_unlock_bh(&(bdp->bd_non_tx_lock));
 }
 
+int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+{
+	struct e100_private *bdp;
+	struct net_device *netdev = p;
+	
+	if(netdev == NULL)
+		return NOTIFY_DONE;
+	
+	switch(event) {
+	case NETDEV_CHANGENAME:
+		if(netdev->open == e100_open) {
+			bdp = netdev->priv;
+			/* rename the proc nodes the easy way */
+			e100_remove_proc_subdir(bdp, bdp->ifname);
+			memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
+			bdp->ifname[IFNAMSIZ-1] = 0;
+			e100_create_proc_subdir(bdp, bdp->ifname);
+		}
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
 #ifdef CONFIG_PM
 static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
-        struct pci_dev *pdev = NULL;
+        struct pci_dev *pdev;
 	
         switch(event) {
         case SYS_DOWN:
diff -urN linux-2.4.20-pre11/drivers/net/e100/e100_proc.c linux-2.4.20-rc1/drivers/net/e100/e100_proc.c
--- linux-2.4.20-pre11/drivers/net/e100/e100_proc.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e100/e100_proc.c	Tue Oct 29 08:35:06 2002
@@ -249,8 +249,6 @@
 	{"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
 	{"\n",},
 	{"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
-	{"Rx_Polling_Packets",    read_gen_ulong, 0, bdp_drv_off(rx_tasklet_pkts)},
-	{"Polling_Interrupt_Switch", read_gen_ulong, 0, bdp_drv_off(poll_intr_switch)},
 	{"Identify_Adapter", 0, write_blink_led_timer, 0},
 	{"", 0, 0, 0}
 };
@@ -291,7 +289,7 @@
 	return generic_read(page, start, off, count, eof, len);
 }
 
-static struct proc_dir_entry * __devinit
+static struct proc_dir_entry *
 create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
 	       read_proc_t * read_proc, write_proc_t * write_proc)
 {
@@ -318,7 +316,7 @@
 }
 
 void
-e100_remove_proc_subdir(struct e100_private *bdp)
+e100_remove_proc_subdir(struct e100_private *bdp, char *name)
 {
 	e100_proc_entry *pe;
 	char info[256];
@@ -329,8 +327,8 @@
 		return;
 	}
 
-	len = strlen(bdp->device->name);
-	strncpy(info, bdp->device->name, sizeof (info));
+	len = strlen(bdp->ifname);
+	strncpy(info, bdp->ifname, sizeof (info));
 	strncat(info + len, ".info", sizeof (info) - len);
 
 	if (bdp->proc_parent) {
@@ -341,7 +339,7 @@
 			remove_proc_entry(pe->name, bdp->proc_parent);
 		}
 
-		remove_proc_entry(bdp->device->name, adapters_proc_dir);
+		remove_proc_entry(bdp->ifname, adapters_proc_dir);
 		bdp->proc_parent = NULL;
 	}
 
@@ -351,7 +349,7 @@
 	e100_proc_cleanup();
 }
 
-int __devinit
+int
 e100_create_proc_subdir(struct e100_private *bdp)
 {
 	struct proc_dir_entry *dev_dir;
@@ -366,7 +364,7 @@
 			return -ENOMEM;
 	}
 
-	strncpy(info, bdp->device->name, sizeof (info));
+	strncpy(info, bdp->ifname, sizeof (info));
 	len = strlen(info);
 	strncat(info + len, ".info", sizeof (info) - len);
 
@@ -376,12 +374,12 @@
 		return -ENOMEM;
 	}
 
-	dev_dir = create_proc_entry(bdp->device->name, S_IFDIR,
+	dev_dir = create_proc_entry(bdp->ifname, S_IFDIR,
 				    adapters_proc_dir);
 	bdp->proc_parent = dev_dir;
 
 	if (!dev_dir) {
-		e100_remove_proc_subdir(bdp);
+		e100_remove_proc_subdir(bdp, bdp->ifname);
 		return -ENOMEM;
 	}
 
@@ -396,7 +394,7 @@
 
 		if (!(create_proc_rw(pe->name, data, dev_dir,
 				     pe->read_proc, pe->write_proc))) {
-			e100_remove_proc_subdir(bdp);
+			e100_remove_proc_subdir(bdp, bdp->ifname);
 			return -ENOMEM;
 		}
 	}
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000.h linux-2.4.20-rc1/drivers/net/e1000/e1000.h
--- linux-2.4.20-pre11/drivers/net/e1000/e1000.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000.h	Tue Oct 29 08:35:06 2002
@@ -94,6 +94,15 @@
 #define E1000_RXBUFFER_8192  8192
 #define E1000_RXBUFFER_16384 16384
 
+/* Flow Control High-Watermark: 43464 bytes */
+#define E1000_FC_HIGH_THRESH 0xA9C8
+
+/* Flow Control Low-Watermark: 43456 bytes */
+#define E1000_FC_LOW_THRESH 0xA9C0
+
+/* Flow Control Pause Time: 858 usec */
+#define E1000_FC_PAUSE_TIME 0x0680
+
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define E1000_TX_QUEUE_WAKE	16
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
@@ -193,5 +202,6 @@
 
 
 	uint32_t pci_state[16];
+	char ifname[IFNAMSIZ];
 };
 #endif /* _E1000_H_ */
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_ethtool.c linux-2.4.20-rc1/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_ethtool.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_ethtool.c	Tue Oct 29 08:35:06 2002
@@ -117,7 +117,8 @@
 
 	if(ecmd->autoneg == AUTONEG_ENABLE) {
 		hw->autoneg = 1;
-		hw->autoneg_advertised = (ecmd->advertising & 0x002F);
+		hw->autoneg_advertised = 0x002F;
+		ecmd->advertising = 0x002F;
 	} else {
 		hw->autoneg = 0;
 		switch(ecmd->speed + ecmd->duplex) {
@@ -211,7 +212,7 @@
 	int i, max_len, first_word, last_word;
 
 	if(eeprom->len == 0)
-		return -EOPNOTSUPP;
+		return -EINVAL;
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
@@ -228,6 +229,7 @@
 
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
+
 	return 0;
 }
 
@@ -290,7 +292,6 @@
 	case E1000_DEV_ID_82543GC_FIBER:
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
-	default:
 		wol->supported = 0;
 		wol->wolopts   = 0;
 		return;
@@ -304,14 +305,7 @@
 		}
 		/* Fall Through */
 
-	case E1000_DEV_ID_82544EI_COPPER:
-	case E1000_DEV_ID_82544GC_COPPER:
-	case E1000_DEV_ID_82544GC_LOM:
-	case E1000_DEV_ID_82540EM:
-	case E1000_DEV_ID_82540EM_LOM:
-	case E1000_DEV_ID_82545EM_COPPER:
-	case E1000_DEV_ID_82545EM_FIBER:
-	case E1000_DEV_ID_82546EB_COPPER:
+	default:
 		wol->supported = WAKE_PHY | WAKE_UCAST | 
 				 WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
 		
@@ -340,7 +334,6 @@
 	case E1000_DEV_ID_82543GC_FIBER:
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
-	default:
 		return wol->wolopts ? -EOPNOTSUPP : 0;
 
 	case E1000_DEV_ID_82546EB_FIBER:
@@ -349,14 +342,7 @@
 			return wol->wolopts ? -EOPNOTSUPP : 0;
 		/* Fall Through */
 
-	case E1000_DEV_ID_82544EI_COPPER:
-	case E1000_DEV_ID_82544GC_COPPER:
-	case E1000_DEV_ID_82544GC_LOM:
-	case E1000_DEV_ID_82540EM:
-	case E1000_DEV_ID_82540EM_LOM:
-	case E1000_DEV_ID_82545EM_COPPER:
-	case E1000_DEV_ID_82545EM_FIBER:
-	case E1000_DEV_ID_82546EB_COPPER:
+	default:
 		if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
 			return -EOPNOTSUPP;
 
@@ -518,7 +504,8 @@
 		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
 			return -EFAULT;
 
-		if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))<0)
+		if((err = e1000_ethtool_geeprom(adapter, 
+			&eeprom, eeprom_buff)))
 			return err;
 
 		if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_hw.c linux-2.4.20-rc1/drivers/net/e1000/e1000_hw.c
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_hw.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_hw.c	Tue Oct 29 08:35:06 2002
@@ -47,9 +47,9 @@
 static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
 static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
 static void e1000_setup_eeprom(struct e1000_hw *hw);
-static void e1000_standby_eeprom(struct e1000_hw *hw);
 static void e1000_clock_eeprom(struct e1000_hw *hw);
 static void e1000_cleanup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
 
 /******************************************************************************
@@ -88,6 +88,9 @@
         break;
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
         hw->mac_type = e1000_82540;
         break;
     case E1000_DEV_ID_82545EM_COPPER:
@@ -655,14 +658,17 @@
         return -E1000_ERR_PHY;
     }
     phy_data |= M88E1000_EPSCR_TX_CLK_25;
-    /* Configure Master and Slave downshift values */
-    phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-                  M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-    phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-                 M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
+
+    if (hw->phy_revision < M88E1011_I_REV_4) {
+        /* Configure Master and Slave downshift values */
+        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
     }
 
     /* SW Reset the PHY so all changes take effect */
@@ -1008,7 +1014,6 @@
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
-    /* Write the MII Control Register with the new PHY configuration. */
     if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
         DEBUGOUT("PHY Read Error\n");
         return -E1000_ERR_PHY;
@@ -1023,9 +1028,11 @@
         return -E1000_ERR_PHY;
     }
     DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-    
+
     /* Need to reset the PHY or these changes will be ignored */
     mii_ctrl_reg |= MII_CR_RESET;
+
+    /* Write back the modified PHY MII control register. */
     if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
         DEBUGOUT("PHY Write Error\n");
         return -E1000_ERR_PHY;
@@ -2100,7 +2107,8 @@
         return -E1000_ERR_PHY;
     }
     hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
-    
+    hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
     switch(hw->mac_type) {
     case e1000_82543:
         if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
@@ -2242,7 +2250,7 @@
                    uint32_t *eecd)
 {
     /* Raise the clock input to the EEPROM (by setting the SK bit), and then
-     * wait 50 microseconds.
+     * wait <delay> microseconds.
      */
     *eecd = *eecd | E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
@@ -2331,11 +2339,11 @@
     uint32_t i;
     uint16_t data;
 
-    /* In order to read a register from the EEPROM, we need to shift 16 bits 
-     * in from the EEPROM. Bits are "shifted in" by raising the clock input to
-     * the EEPROM (setting the SK bit), and then reading the value of the "DO"
-     * bit.  During this "shifting in" process the "DI" bit should always be 
-     * clear..
+    /* In order to read a register from the EEPROM, we need to shift 'count'
+     * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+     * input to the EEPROM (setting the SK bit), and then reading the value of
+     * the "DO" bit.  During this "shifting in" process the "DI" bit should
+     * always be clear.
      */
 
     eecd = E1000_READ_REG(hw, EECD);
@@ -3140,6 +3148,9 @@
         ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
         E1000_WRITE_REG(hw, LEDCTL, ledctl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
@@ -3173,6 +3184,9 @@
     case E1000_DEV_ID_82544GC_LOM:
         /* No cleanup necessary */
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
@@ -3223,6 +3237,9 @@
         ctrl |= E1000_CTRL_SWDPIO0;
         E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
@@ -3270,6 +3287,9 @@
         ctrl |= E1000_CTRL_SWDPIO0;
         E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_hw.h linux-2.4.20-rc1/drivers/net/e1000/e1000_hw.h
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_hw.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_hw.h	Tue Oct 29 08:35:07 2002
@@ -237,20 +237,23 @@
     e1000_write_reg_io((a), E1000_##reg, val)
 
 /* PCI Device IDs */
-#define E1000_DEV_ID_82542          0x1000
-#define E1000_DEV_ID_82543GC_FIBER  0x1001
-#define E1000_DEV_ID_82543GC_COPPER 0x1004
-#define E1000_DEV_ID_82544EI_COPPER 0x1008
-#define E1000_DEV_ID_82544EI_FIBER  0x1009
-#define E1000_DEV_ID_82544GC_COPPER 0x100C
-#define E1000_DEV_ID_82544GC_LOM    0x100D
-#define E1000_DEV_ID_82540EM        0x100E
-#define E1000_DEV_ID_82540EM_LOM    0x1015
-#define E1000_DEV_ID_82545EM_COPPER 0x100F
-#define E1000_DEV_ID_82545EM_FIBER  0x1011
-#define E1000_DEV_ID_82546EB_COPPER 0x1010
-#define E1000_DEV_ID_82546EB_FIBER  0x1012
-#define NUM_DEV_IDS 13
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define NUM_DEV_IDS 16
 
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -851,6 +854,7 @@
     e1000_bus_type bus_type;
     uint32_t io_base;
     uint32_t phy_id;
+    uint32_t phy_revision;
     uint32_t phy_addr;
     uint32_t original_fc;
     uint32_t txcw;
@@ -1755,6 +1759,7 @@
 #define M88E1011_I_PHY_ID  0x01410C20
 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4   0x04
 
 /* Miscellaneous PHY bit definitions. */
 #define PHY_PREAMBLE        0xFFFFFFFF
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_main.c linux-2.4.20-rc1/drivers/net/e1000/e1000_main.c
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_main.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_main.c	Tue Oct 29 08:35:07 2002
@@ -31,6 +31,19 @@
 
 /* Change Log
  *
+ * 4.4.12       10/15/02
+ *   o Clean up: use members of pci_device rather than direct calls to
+ *     pci_read_config_word.
+ *   o Bug fix: changed default flow control settings.
+ *   o Clean up: ethtool file now has an inclusive list for adapters in the
+ *     Wake-On-LAN capabilities instead of an exclusive list.
+ *   o Bug fix: miscellaneous WoL bug fixes.
+ *   o Added software interrupt for clearing rx ring
+ *   o Bug fix: easier to undo "forcing" of 1000/fd using ethtool.
+ *   o Now setting netdev->mem_end in e1000_probe.
+ *   o Clean up: Moved tx_timeout from interrupt context to process context
+ *     using schedule_task.
+ *
  * 4.3.15      8/9/02
  *   o Converted from Dual BSD/GPL license to GPL license.
  *   o Clean up: use pci_[clear|set]_mwi rather than direct calls to
@@ -44,31 +57,13 @@
  *   o Feature: exposed two Tx and one Rx interrupt delay knobs for finer
  *     control over interurpt rate tuning.
  *   o Misc ethtool bug fixes.
- *         
- * 4.3.2       7/5/02
- *   o Bug fix: perform controller reset using I/O rather than mmio because
- *     some chipsets try to perform a 64-bit write, but the controller ignores
- *     the upper 32-bit write once the reset is intiated by the lower 32-bit
- *     write, causing a master abort.
- *   o Bug fix: fixed jumbo frames sized from 1514 to 2048.
- *   o ASF support: disable ARP when driver is loaded or resumed; enable when 
- *     driver is removed or suspended.
- *   o Bug fix: changed default setting for RxIntDelay to 0 for 82542/3/4
- *     controllers to workaround h/w errata where controller will hang when
- *     RxIntDelay <> 0 under certian network conditions.
- *   o Clean up: removed unused and undocumented user-settable settings for
- *     PHY.
- *   o Bug fix: ethtool GEEPROM was using byte address rather than word
- *     addressing.
- *   o Feature: added support for ethtool SEEPROM.
- *   o Feature: added support for entropy pool.
  *
- * 4.2.17      5/30/02
+ * 4.3.2       7/5/02
  */
  
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.3.15-k1";
+char e1000_driver_version[] = "4.4.12-k1";
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -110,6 +105,9 @@
 	{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	/* required last entry */
 	{0,}
 };
@@ -172,15 +170,22 @@
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 
 static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
+static int e1000_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
 static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
 #endif
 
-struct notifier_block e1000_notifier = {
-	notifier_call:	e1000_notify_reboot,
-	next:		NULL,
-	priority:	0
+struct notifier_block e1000_notifier_reboot = {
+	.notifier_call	= e1000_notify_reboot,
+	.next		= NULL,
+	.priority	= 0
+};
+
+struct notifier_block e1000_notifier_netdev = {
+	.notifier_call	= e1000_notify_netdev,
+	.next		= NULL,
+	.priority	= 0
 };
 
 /* Exported from other modules */
@@ -191,14 +196,14 @@
 extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
 
 static struct pci_driver e1000_driver = {
-	name:     e1000_driver_name,
-	id_table: e1000_pci_tbl,
-	probe:    e1000_probe,
-	remove:   __devexit_p(e1000_remove),
+	.name     = e1000_driver_name,
+	.id_table = e1000_pci_tbl,
+	.probe    = e1000_probe,
+	.remove   = __devexit_p(e1000_remove),
 	/* Power Managment Hooks */
 #ifdef CONFIG_PM
-	suspend:  e1000_suspend,
-	resume:   e1000_resume
+	.suspend  = e1000_suspend,
+	.resume   = e1000_resume
 #endif
 };
 
@@ -223,8 +228,10 @@
 	printk(KERN_INFO "%s\n", e1000_copyright);
 
 	ret = pci_module_init(&e1000_driver);
-	if(ret >= 0)
-		register_reboot_notifier(&e1000_notifier);
+	if(ret >= 0) {
+		register_reboot_notifier(&e1000_notifier_reboot);
+		register_netdevice_notifier(&e1000_notifier_netdev);
+	}
 	return ret;
 }
 
@@ -240,7 +247,8 @@
 static void __exit
 e1000_exit_module(void)
 {
-	unregister_reboot_notifier(&e1000_notifier);
+	unregister_reboot_notifier(&e1000_notifier_reboot);
+	unregister_netdevice_notifier(&e1000_notifier_netdev);
 	pci_unregister_driver(&e1000_driver);
 }
 
@@ -397,6 +405,7 @@
 
 	netdev->irq = pdev->irq;
 	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
 	netdev->base_addr = adapter->hw.io_base;
 
 	adapter->bd_number = cards_found;
@@ -459,6 +468,8 @@
 		(void (*)(void *))e1000_tx_timeout_task, netdev);
 
 	register_netdev(netdev);
+	memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
+	adapter->ifname[IFNAMSIZ-1] = 0;
 
 	/* we're going to reset, so assume we have no link for now */
 
@@ -511,7 +522,7 @@
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
 	uint32_t manc;
-	
+
 	if(adapter->hw.mac_type >= e1000_82540) {
 		manc = E1000_READ_REG(&adapter->hw, MANC);
 		if(manc & E1000_MANC_SMBUS_EN) {
@@ -519,7 +530,7 @@
 			E1000_WRITE_REG(&adapter->hw, MANC, manc);
 		}
 	}
-		
+
 	unregister_netdev(netdev);
 
 	e1000_phy_hw_reset(&adapter->hw);
@@ -572,9 +583,9 @@
 
 	/* flow control settings */
 
-	hw->fc_high_water = FC_DEFAULT_HI_THRESH;
-	hw->fc_low_water = FC_DEFAULT_LO_THRESH;
-	hw->fc_pause_time = FC_DEFAULT_TX_TIMER;
+	hw->fc_high_water = E1000_FC_HIGH_THRESH;
+	hw->fc_low_water = E1000_FC_LOW_THRESH;
+	hw->fc_pause_time = E1000_FC_PAUSE_TIME;
 	hw->fc_send_xon = 1;
 
 	/* Media type - copper or fiber */
@@ -895,8 +906,9 @@
 
 	/* set the Receive Delay Timer Register */
 
+	E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+
 	if(adapter->hw.mac_type >= e1000_82540) {
-		E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
 		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
 
 		/* Set the interrupt throttling rate.  Value is calculated
@@ -904,9 +916,6 @@
 #define MAX_INTS_PER_SEC        8000
 #define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
 		E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
-
-	} else {
-		E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
 	}
 
 	/* Setup the Base and Length of the Rx Descriptor Ring */
@@ -1264,6 +1273,10 @@
 	e1000_update_stats(adapter);
 	e1000_update_adaptive(&adapter->hw);
 
+
+	/* Cause software interrupt to ensure rx ring is cleaned */
+	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
+
 	/* Early detection of hung controller */
 	i = txdr->next_to_clean;
 	if(txdr->buffer_info[i].dma &&
@@ -1422,12 +1435,12 @@
 
 	int f;
 
-
 	count = TXD_USE_COUNT(skb->len - skb->data_len,
 	                      adapter->max_data_per_txd);
 	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
 		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
 		                       adapter->max_data_per_txd);
+
 	if(skb->ip_summed == CHECKSUM_HW)
 		count++;
 
@@ -1662,6 +1675,7 @@
 	                               adapter->stats.latecol;
 	adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
 	adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+	adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
 
 	/* Tx Dropped needs to be maintained elsewhere */
 
@@ -1674,7 +1688,8 @@
 			adapter->phy_stats.idle_errors += phy_tmp;
 		}
 
-		if(!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+		if((hw->mac_type <= e1000_82546) &&
+		   !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
 			adapter->phy_stats.receive_errors += phy_tmp;
 	}
 }
@@ -1914,8 +1929,7 @@
 	while(!rx_ring->buffer_info[i].skb) {
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
 
-		skb = alloc_skb(adapter->rx_buffer_len + reserve_len,
-		                GFP_ATOMIC);
+		skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
 
 		if(!skb) {
 			/* Better luck next round */
@@ -2147,6 +2161,29 @@
 }
 
 static int
+e1000_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+{
+	struct e1000_adapter *adapter;
+	struct net_device *netdev = p;
+	if(netdev == NULL)
+		return NOTIFY_DONE;
+
+	switch(event) {
+	case NETDEV_CHANGENAME:
+		if(netdev->open == e1000_open) {
+			adapter = netdev->priv;
+			/* rename the proc nodes the easy way */
+			e1000_proc_dev_free(adapter);
+			memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
+			adapter->ifname[IFNAMSIZ-1] = 0;
+			e1000_proc_dev_setup(adapter);
+		}
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
@@ -2162,30 +2199,40 @@
 		e1000_setup_rctl(adapter);
 		e1000_set_multi(netdev);
 
+		/* turn on all-multi mode if wake on multicast is enabled */
 		if(adapter->wol & E1000_WUFC_MC) {
 			rctl = E1000_READ_REG(&adapter->hw, RCTL);
 			rctl |= E1000_RCTL_MPE;
 			E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 		}
 
-		if(adapter->hw.media_type == e1000_media_type_fiber) {
-			#define E1000_CTRL_ADVD3WUC 0x00100000
+		if(adapter->hw.mac_type >= e1000_82540) {
 			ctrl = E1000_READ_REG(&adapter->hw, CTRL);
-			ctrl |= E1000_CTRL_ADVD3WUC;
+			/* advertise wake from D3Cold */
+			#define E1000_CTRL_ADVD3WUC 0x00100000
+			/* phy power management enable */
+			#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+			ctrl |= E1000_CTRL_ADVD3WUC |
+				E1000_CTRL_EN_PHY_PWR_MGMT;
 			E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+		}
 
+		if(adapter->hw.media_type == e1000_media_type_fiber) {
+			/* keep the laser running in D3 */
 			ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
-        		ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
 			E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext);
 		}
 
-		E1000_WRITE_REG(&adapter->hw, WUC, 0);
+		E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
 		E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
 		pci_enable_wake(pdev, 3, 1);
+		pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
 	} else {
 		E1000_WRITE_REG(&adapter->hw, WUC, 0);
 		E1000_WRITE_REG(&adapter->hw, WUFC, 0);
 		pci_enable_wake(pdev, 3, 0);
+		pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
 	}
 
 	pci_save_state(pdev, adapter->pci_state);
@@ -2195,9 +2242,12 @@
 		if(manc & E1000_MANC_SMBUS_EN) {
 			manc |= E1000_MANC_ARP_EN;
 			E1000_WRITE_REG(&adapter->hw, MANC, manc);
+			state = 0;
 		}
-	} else
-		pci_set_power_state(pdev, 3);
+	}
+
+	state = (state > 0) ? 3 : 0;
+	pci_set_power_state(pdev, state);
 
 	return 0;
 }
@@ -2212,10 +2262,11 @@
 
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev, adapter->pci_state);
-	pci_enable_wake(pdev, 0, 0);
 
-	/* Clear the wakeup status bits */
+	pci_enable_wake(pdev, 3, 0);
+	pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
 
+	e1000_reset(adapter);
 	E1000_WRITE_REG(&adapter->hw, WUS, ~0);
 
 	if(netif_running(netdev))
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_osdep.h linux-2.4.20-rc1/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_osdep.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_osdep.h	Tue Oct 29 08:35:07 2002
@@ -96,6 +96,6 @@
         readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
         readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
 
-#define E1000_WRITE_FLUSH(a) ((void)E1000_READ_REG(a, STATUS))
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
 
 #endif /* _E1000_OSDEP_H_ */
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_param.c linux-2.4.20-rc1/drivers/net/e1000/e1000_param.c
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_param.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_param.c	Tue Oct 29 08:35:07 2002
@@ -197,8 +197,7 @@
 #define MIN_RXD                       80
 #define MAX_82544_RXD               4096
 
-#define DEFAULT_RDTR                 128
-#define DEFAULT_RDTR_82544             0
+#define DEFAULT_RDTR                   0
 #define MAX_RXDELAY               0xFFFF
 #define MIN_RXDELAY                    0
 
@@ -307,15 +306,16 @@
 
 	{ /* Transmit Descriptor Count */
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Transmit Descriptors",
-			err:  "using default of " __MODULE_STRING(DEFAULT_TXD),
-			def:  DEFAULT_TXD,
-			arg: { r: { min: MIN_TXD }}
+			.type = range_option,
+			.name = "Transmit Descriptors",
+			.err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
+			.def  = DEFAULT_TXD,
+			.arg  = { r: { min: MIN_TXD }}
 		};
 		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
-		opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD;
+		opt.arg.r.max = mac_type < e1000_82544 ? 
+			MAX_TXD : MAX_82544_TXD;
 
 		tx_ring->count = TxDescriptors[bd];
 		e1000_validate_option(&tx_ring->count, &opt);
@@ -323,11 +323,11 @@
 	}
 	{ /* Receive Descriptor Count */
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Receive Descriptors",
-			err:  "using default of " __MODULE_STRING(DEFAULT_RXD),
-			def:  DEFAULT_RXD,
-			arg: { r: { min: MIN_RXD }}
+			.type = range_option,
+			.name = "Receive Descriptors",
+			.err  = "using default of " __MODULE_STRING(DEFAULT_RXD),
+			.def  = DEFAULT_RXD,
+			.arg  = { r: { min: MIN_RXD }}
 		};
 		struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
@@ -339,10 +339,10 @@
 	}
 	{ /* Checksum Offload Enable/Disable */
 		struct e1000_option opt = {
-			type: enable_option,
-			name: "Checksum Offload",
-			err:  "defaulting to Enabled",
-			def:  OPTION_ENABLED
+			.type = enable_option,
+			.name = "Checksum Offload",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
 		};
 		
 		int rx_csum = XsumRX[bd];
@@ -359,11 +359,11 @@
 			 { e1000_fc_default, "Flow Control Hardware Default" }};
 
 		struct e1000_option opt = {
-			type: list_option,
-			name: "Flow Control",
-			err:  "reading default settings from EEPROM",
-			def:  e1000_fc_default,
-			arg: { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
+			.type = list_option,
+			.name = "Flow Control",
+			.err  = "reading default settings from EEPROM",
+			.def  = e1000_fc_default,
+			.arg  = { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
 		};
 
 		int fc = FlowControl[bd];
@@ -373,9 +373,9 @@
 	{ /* Transmit Interrupt Delay */
 		char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Transmit Interrupt Delay",
-			arg: { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }}
+			.type = range_option,
+			.name = "Transmit Interrupt Delay",
+			.arg  = { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }}
 		};
 		opt.def = DEFAULT_TIDV;
 		opt.err = tidv;
@@ -386,9 +386,9 @@
 	{ /* Transmit Absolute Interrupt Delay */
 		char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Transmit Absolute Interrupt Delay",
-			arg: { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }}
+			.type = range_option,
+			.name = "Transmit Absolute Interrupt Delay",
+			.arg  = { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }}
 		};
 		opt.def = DEFAULT_TADV;
 		opt.err = tadv;
@@ -398,16 +398,13 @@
 	}
 	{ /* Receive Interrupt Delay */
 		char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
-		char *rdtr_82544 = "using default of "
-				   __MODULE_STRING(DEFAULT_RDTR_82544);
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Receive Interrupt Delay",
-			arg: { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
+			.type = range_option,
+			.name = "Receive Interrupt Delay",
+			.arg  = { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
 		};
-		e1000_mac_type mac_type = adapter->hw.mac_type;
-		opt.def = mac_type > e1000_82544 ? DEFAULT_RDTR : 0;
-		opt.err = mac_type > e1000_82544 ? rdtr : rdtr_82544;
+		opt.def = DEFAULT_RDTR;
+		opt.err = rdtr;
 
 		adapter->rx_int_delay = RxIntDelay[bd];
 		e1000_validate_option(&adapter->rx_int_delay, &opt);
@@ -415,9 +412,9 @@
 	{ /* Receive Absolute Interrupt Delay */
 		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
 		struct e1000_option opt = {
-			type: range_option,
-			name: "Receive Absolute Interrupt Delay",
-			arg: { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }}
+			.type = range_option,
+			.name = "Receive Absolute Interrupt Delay",
+			.arg  = { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }}
 		};
 		opt.def = DEFAULT_RADV;
 		opt.err = radv;
@@ -485,11 +482,11 @@
 		                                      {  SPEED_100, "" },
 		                                      { SPEED_1000, "" }};
 		struct e1000_option opt = {
-			type: list_option,
-			name: "Speed",
-			err:  "parameter ignored",
-			def:  0,
-			arg: { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
+			.type = list_option,
+			.name = "Speed",
+			.err  = "parameter ignored",
+			.def  = 0,
+			.arg  = { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
 		};
 
 		speed = Speed[bd];
@@ -500,11 +497,11 @@
 		                                     { HALF_DUPLEX, "" },
 		                                     { FULL_DUPLEX, "" }};
 		struct e1000_option opt = {
-			type: list_option,
-			name: "Duplex",
-			err:  "parameter ignored",
-			def:  0,
-			arg: { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
+			.type = list_option,
+			.name = "Duplex",
+			.err  = "parameter ignored",
+			.def  = 0,
+			.arg  = { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
 		};
 
 		dplx = Duplex[bd];
@@ -552,11 +549,11 @@
 			 { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
 
 		struct e1000_option opt = {
-			type: list_option,
-			name: "AutoNeg",
-			err:  "parameter ignored",
-			def:  AUTONEG_ADV_DEFAULT,
-			arg: { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
+			.type = list_option,
+			.name = "AutoNeg",
+			.err  = "parameter ignored",
+			.def  = AUTONEG_ADV_DEFAULT,
+			.arg  = { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
 		};
 
 		int an = AutoNeg[bd];
diff -urN linux-2.4.20-pre11/drivers/net/e1000/e1000_proc.c linux-2.4.20-rc1/drivers/net/e1000/e1000_proc.c
--- linux-2.4.20-pre11/drivers/net/e1000/e1000_proc.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/e1000/e1000_proc.c	Tue Oct 29 08:35:07 2002
@@ -132,7 +132,7 @@
 	return e1000_proc_read(page, start, off, count, eof);
 }
 
-static void __devexit
+static void
 e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
 {
 	struct proc_dir_entry *intel_proc_dir, *proc_dir;
@@ -188,7 +188,7 @@
 }
 
 
-static int __devinit
+static int
 e1000_proc_singles_create(struct proc_dir_entry *parent,
                           struct list_head *proc_list_head)
 {
@@ -215,7 +215,7 @@
 	return 1;
 }
 
-static void __devinit
+static void
 e1000_proc_dirs_create(void *data, char *name, 
                        struct list_head *proc_list_head)
 {
@@ -255,7 +255,7 @@
 	info_entry->data = proc_list_head;
 }
 
-static void __devinit
+static void
 e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
                     void *data, size_t len, 
 		    char *(*func)(void *, size_t, char *))
@@ -274,7 +274,7 @@
 	list_add_tail(&new->list, proc_list_head);
 }
 
-static void __devexit
+static void
 e1000_proc_list_free(struct list_head *proc_list_head)
 {
 	struct proc_list *elem;
@@ -542,7 +542,7 @@
 #define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex)
 #define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned)
 
-static void __devinit
+static void
 e1000_proc_list_setup(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -572,7 +572,7 @@
 	}
 
 	LIST_ADD_U("IRQ", &adapter->pdev->irq);
-	LIST_ADD_S("System_Device_Name", adapter->netdev->name);
+	LIST_ADD_S("System_Device_Name", adapter->ifname);
 	LIST_ADD_F("Current_HWaddr",
 	            adapter->netdev->dev_addr, e1000_proc_hwaddr);
 	LIST_ADD_F("Permanent_HWaddr",
@@ -621,11 +621,11 @@
 	LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc);
 	LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc);
 	LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
-	
+
 	/* The 82542 does not have an alignment error count register */
 	if(adapter->hw.mac_type >= e1000_82543)
 		LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
-	
+
 	LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
 	LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc);
 	LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc);
@@ -667,13 +667,13 @@
  * @adapter: board private structure
  */
 
-void __devinit
+void
 e1000_proc_dev_setup(struct e1000_adapter *adapter)
 {
 	e1000_proc_list_setup(adapter);
 
 	e1000_proc_dirs_create(adapter, 
-	                       adapter->netdev->name,
+	                       adapter->ifname,
 	                       &adapter->proc_list_head);
 }
 
@@ -682,18 +682,18 @@
  * @adapter: board private structure
  */
 
-void __devexit
+void
 e1000_proc_dev_free(struct e1000_adapter *adapter)
 {
-	e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head);
+	e1000_proc_dirs_free(adapter->ifname, &adapter->proc_list_head);
 
 	e1000_proc_list_free(&adapter->proc_list_head);
 }
 
 #else /* CONFIG_PROC_FS */
 
-void __devinit e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
-void __devexit e1000_proc_dev_free(struct e1000_adapter *adapter) {}
+void e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
+void e1000_proc_dev_free(struct e1000_adapter *adapter) {}
 
 #endif /* CONFIG_PROC_FS */
 
diff -urN linux-2.4.20-pre11/drivers/net/eepro100.c linux-2.4.20-rc1/drivers/net/eepro100.c
--- linux-2.4.20-pre11/drivers/net/eepro100.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/eepro100.c	Tue Oct 29 08:35:09 2002
@@ -65,7 +65,6 @@
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1;			/* The debug level */
 
 /* A few values that may be tweaked. */
 /* The ring sizes should be a power of two for efficiency. */
@@ -119,6 +118,15 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
+
+static int debug = -1;
+#define DEBUG_DEFAULT		(NETIF_MSG_DRV		| \
+				 NETIF_MSG_HW		| \
+				 NETIF_MSG_RX_ERR	| \
+				 NETIF_MSG_TX_ERR)
+#define DEBUG			((debug >= 0) ? (1<<debug)-1 : DEBUG_DEFAULT)
+
 
 MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>");
 MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver");
@@ -167,7 +175,6 @@
 								} while(0)
 
 
-static int speedo_debug = 1;
 
 /*
 				Theory of Operation
@@ -316,23 +323,11 @@
 #define outl writel
 #endif
 
-/* How to wait for the command unit to accept a command.
-   Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(long cmd_ioaddr)
-{
-	int wait = 1000;
-	do  udelay(1) ;
-	while(inb(cmd_ioaddr) && --wait >= 0);
-#ifndef final_version
-	if (wait < 0)
-		printk(KERN_ALERT "eepro100: wait_for_cmd_done timeout!\n");
-#endif
-}
-
 /* Offsets to the various registers.
    All accesses need not be longword aligned. */
 enum speedo_offsets {
 	SCBStatus = 0, SCBCmd = 2,	/* Rx/Command Unit command and status. */
+	SCBIntmask = 3,
 	SCBPointer = 4,				/* General purpose pointer. */
 	SCBPort = 8,				/* Misc. commands and operands.  */
 	SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
@@ -488,7 +483,6 @@
 	unsigned char acpi_pwr;
 	signed char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;			/* The Tx queue is full. */
-	unsigned int full_duplex:1;		/* Full-duplex operation requested. */
 	unsigned int flow_ctrl:1;		/* Use 802.3x flow control. */
 	unsigned int rx_bug:1;			/* Work around receiver hang errata. */
 	unsigned char default_port:8;		/* Last dev->if_port value. */
@@ -496,6 +490,7 @@
 	unsigned short phy[2];			/* PHY media interfaces available. */
 	unsigned short partner;			/* Link partner caps. */
 	struct mii_if_info mii_if;		/* MII API hooks, info */
+	u32 msg_enable;				/* debug message level */
 #ifdef CONFIG_PM
 	u32 pm_state[16];
 #endif
@@ -558,6 +553,24 @@
 						   0x2000, 0x2100, 0x0400, 0x3100};
 #endif
 
+/* How to wait for the command unit to accept a command.
+   Typically this takes 0 ticks. */
+static inline unsigned char wait_for_cmd_done(struct net_device *dev)
+{
+	int wait = 1000;
+	long cmd_ioaddr = dev->base_addr + SCBCmd;
+	unsigned char r;
+
+	do  {
+		udelay(1);
+		r = inb(cmd_ioaddr);
+	} while(r && --wait >= 0);
+
+	if (wait < 0)
+		printk(KERN_ALERT "%s: wait_for_cmd_done timeout!\n", dev->name);
+	return r;
+}
+
 static int __devinit eepro100_init_one (struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
@@ -566,9 +579,12 @@
 	int acpi_idle_state = 0, pm;
 	static int cards_found /* = 0 */;
 
-	static int did_version /* = 0 */;		/* Already printed version info. */
-	if (speedo_debug > 0  &&  did_version++ == 0)
+#ifndef MODULE
+	/* when built-in, we only print version if device is found */
+	static int did_version;
+	if (did_version++ == 0)
 		printk(version);
+#endif
 
 	/* save power state before pci_enable_device overwrites it */
 	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
@@ -597,7 +613,7 @@
 	irq = pdev->irq;
 #ifdef USE_IO
 	ioaddr = pci_resource_start(pdev, 1);
-	if (speedo_debug > 2)
+	if (DEBUG & NETIF_MSG_PROBE)
 		printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
 			   ioaddr, irq);
 #else
@@ -608,7 +624,7 @@
 				pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
 		goto err_out_free_mmio_region;
 	}
-	if (speedo_debug > 2)
+	if (DEBUG & NETIF_MSG_PROBE)
 		printk("Found Intel i82557 PCI Speedo, MMIO at %#lx, IRQ %d.\n",
 			   pci_resource_start(pdev, 0), irq);
 #endif
@@ -814,6 +830,7 @@
 
 	sp = dev->priv;
 	sp->pdev = pdev;
+	sp->msg_enable = DEBUG;
 	sp->acpi_pwr = acpi_idle_state;
 	sp->tx_ring = tx_ring_space;
 	sp->tx_ring_dma = tx_ring_dma;
@@ -831,7 +848,9 @@
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
 
-	sp->mii_if.phy_id = eeprom[6];
+	sp->mii_if.phy_id = eeprom[6] & 0x1f;
+	sp->mii_if.phy_id_mask = 0x1f;
+	sp->mii_if.reg_num_mask = 0x1f;
 	sp->mii_if.dev = dev;
 	sp->mii_if.mdio_read = mdio_read;
 	sp->mii_if.mdio_write = mdio_write;
@@ -959,7 +978,7 @@
 	long ioaddr = dev->base_addr;
 	int retval;
 
-	if (speedo_debug > 1)
+	if (netif_msg_ifup(sp))
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
 	pci_set_power_state(sp->pdev, 0);
@@ -1016,12 +1035,9 @@
 	if ((sp->phy[0] & 0x8000) == 0)
 		sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE);
 
-	if (mdio_read(dev, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS)
-		netif_carrier_on(dev);
-	else
-		netif_carrier_off(dev);
+	mii_check_link(&sp->mii_if);
 
-	if (speedo_debug > 2) {
+	if (netif_msg_ifup(sp)) {
 		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -1053,8 +1069,7 @@
 	sp->tx_threshold = 0x01208000;
 
 	/* Set the segment registers to '0'. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	if (inb(ioaddr + SCBCmd)) {
+	if (wait_for_cmd_done(dev) != 0) {
 		outl(PortPartialReset, ioaddr + SCBPort);
 		udelay(10);
 	}
@@ -1073,10 +1088,10 @@
 
 	outb(CUStatsAddr, ioaddr + SCBCmd);
 	sp->lstats->done_marker = 0;
-	wait_for_cmd_done(ioaddr + SCBCmd);
+	wait_for_cmd_done(dev);
 
 	if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
-		if (speedo_debug > 2)
+		if (netif_msg_rx_err(sp))
 			printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
 					dev->name);
 	} else {
@@ -1132,8 +1147,7 @@
 	long ioaddr;
 
 	ioaddr = dev->base_addr;
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	if (inb(ioaddr + SCBCmd) != 0) {
+	if (wait_for_cmd_done(dev) != 0) {
 		printk("%s: previous command stalled\n", dev->name);
 		return;
 	}
@@ -1146,9 +1160,7 @@
 
 	rfd->rx_buf_addr = 0xffffffff;
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-
-	if (inb(ioaddr + SCBCmd) != 0) {
+	if (wait_for_cmd_done(dev) != 0) {
 		printk("%s: RxAbort command stalled\n", dev->name);
 		return;
 	}
@@ -1171,7 +1183,7 @@
 		int partner = mdio_read(dev, phy_num, MII_LPA);
 		if (partner != sp->partner) {
 			int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0;
-			if (speedo_debug > 2) {
+			if (netif_msg_link(sp)) {
 				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
 				printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
 					   dev->name, sp->partner, partner, sp->mii_if.advertising);
@@ -1181,16 +1193,10 @@
 				sp->flow_ctrl = flow_ctrl;
 				sp->rx_mode = -1;	/* Trigger a reload. */
 			}
-			/* Clear sticky bit. */
-			mdio_read(dev, phy_num, MII_BMSR);
-			/* If link beat has returned... */
-			if (mdio_read(dev, phy_num, MII_BMSR) & BMSR_LSTATUS)
-				netif_carrier_on(dev);
-			else
-				netif_carrier_off(dev);
 		}
 	}
-	if (speedo_debug > 3) {
+	mii_check_link(&sp->mii_if);
+	if (netif_msg_timer(sp)) {
 		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -1199,7 +1205,7 @@
 		/* We haven't received a packet in a Long Time.  We might have been
 		   bitten by the receiver hang bug.  This can be cleared by sending
 		   a set multicast list command. */
-		if (speedo_debug > 3)
+		if (netif_msg_timer(sp))
 			printk(KERN_DEBUG "%s: Sending a multicast list set command"
 				   " from a timer routine,"
 				   " m=%d, j=%ld, l=%ld.\n",
@@ -1219,28 +1225,26 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int i;
 
-	/* Print a few items for debugging. */
-	if (speedo_debug > 0) {
-		int i;
-		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n", dev->name,
-			   sp->cur_tx, sp->dirty_tx);
+	if (netif_msg_pktdata(sp)) {
+		printk(KERN_DEBUG "%s: Tx ring dump,  Tx queue %u / %u:\n", 
+		    dev->name, sp->cur_tx, sp->dirty_tx);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(KERN_DEBUG "%s:  %c%c%2d %8.8x.\n", dev->name,
-				   i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
-				   i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
-				   i, sp->tx_ring[i].status);
-	}
-	printk(KERN_DEBUG "%s: Printing Rx ring"
-		   " (next to receive into %u, dirty index %u).\n",
-		   dev->name, sp->cur_rx, sp->dirty_rx);
-
-	for (i = 0; i < RX_RING_SIZE; i++)
-		printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
-			   sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
-			   i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
-			   i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
-			   i, (sp->rx_ringp[i] != NULL) ?
-					   (unsigned)sp->rx_ringp[i]->status : 0);
+			    i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ',
+			    i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ',
+			    i, sp->tx_ring[i].status);
+
+		printk(KERN_DEBUG "%s: Printing Rx ring"
+		    " (next to receive into %u, dirty index %u).\n",
+		    dev->name, sp->cur_rx, sp->dirty_rx);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name,
+			    sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ',
+			    i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ',
+			    i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ',
+			    i, (sp->rx_ringp[i] != NULL) ?
+			    (unsigned)sp->rx_ringp[i]->status : 0);
+	}
 
 #if 0
 	{
@@ -1326,7 +1330,7 @@
 	}
 	while (sp->mc_setup_head != NULL) {
 		struct speedo_mc_block *t;
-		if (speedo_debug > 1)
+		if (netif_msg_tx_err(sp))
 			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
 		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
 				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
@@ -1369,12 +1373,14 @@
 	int status = inw(ioaddr + SCBStatus);
 	unsigned long flags;
 
-	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
+	if (netif_msg_tx_err(sp)) {
+		printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   " %4.4x at %d/%d command %8.8x.\n",
 		   dev->name, status, inw(ioaddr + SCBCmd),
 		   sp->dirty_tx, sp->cur_tx,
 		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
 
+	}
 	speedo_show_state(dev);
 #if 0
 	if ((status & 0x00C0) != 0x0080
@@ -1464,13 +1470,13 @@
 	/* workaround for hardware bug on 10 mbit half duplex */
 
 	if ((sp->partner == 0) && (sp->chip_id == 1)) {
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		outb(0 , ioaddr + SCBCmd);
 		udelay(1);
 	}
 
 	/* Trigger the command unit resume. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
+	wait_for_cmd_done(dev);
 	clear_suspend(sp->last_cmd);
 	/* We want the time window between clearing suspend flag on the previous
 	   command and resuming CU to be as small as possible.
@@ -1502,14 +1508,14 @@
 		int entry = dirty_tx % TX_RING_SIZE;
 		int status = le32_to_cpu(sp->tx_ring[entry].status);
 
-		if (speedo_debug > 5)
+		if (netif_msg_tx_done(sp))
 			printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
 				   entry, status);
 		if ((status & StatusComplete) == 0)
 			break;			/* It still hasn't been processed. */
 		if (status & TxUnderrun)
 			if (sp->tx_threshold < 0x01e08000) {
-				if (speedo_debug > 2)
+				if (netif_msg_tx_err(sp))
 					printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n",
 						   dev->name);
 				sp->tx_threshold += 0x00040000;
@@ -1527,7 +1533,7 @@
 		dirty_tx++;
 	}
 
-	if (speedo_debug && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
+	if (netif_msg_tx_err(sp) && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) {
 		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"
 			   " full=%d.\n",
 			   dirty_tx, sp->cur_tx, sp->tx_full);
@@ -1537,7 +1543,7 @@
 	while (sp->mc_setup_head != NULL
 		   && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) {
 		struct speedo_mc_block *t;
-		if (speedo_debug > 1)
+		if (netif_msg_tx_err(sp))
 			printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name);
 		pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma,
 				sp->mc_setup_head->len, PCI_DMA_TODEVICE);
@@ -1560,13 +1566,6 @@
 	long ioaddr, boguscnt = max_interrupt_work;
 	unsigned short status;
 
-#ifndef final_version
-	if (dev == NULL) {
-		printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-#endif
-
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 
@@ -1587,7 +1586,7 @@
 		   FCP and ER interrupts --Dragan */
 		outw(status & 0xfc00, ioaddr + SCBStatus);
 
-		if (speedo_debug > 4)
+		if (netif_msg_intr(sp))
 			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",
 				   dev->name, status);
 
@@ -1649,7 +1648,7 @@
 		}
 	} while (1);
 
-	if (speedo_debug > 3)
+	if (netif_msg_intr(sp))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
@@ -1710,12 +1709,12 @@
 		if (rxf == NULL) {
 			unsigned int forw;
 			int forw_entry;
-			if (speedo_debug > 2 || !(sp->rx_ring_state & RrOOMReported)) {
+			if (netif_msg_rx_err(sp) || !(sp->rx_ring_state & RrOOMReported)) {
 				printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n",
 						dev->name, force);
-				speedo_show_state(dev);
 				sp->rx_ring_state |= RrOOMReported;
 			}
+			speedo_show_state(dev);
 			if (!force)
 				return -1;	/* Better luck next time!  */
 			/* Borrow an skb from one of next entries. */
@@ -1756,8 +1755,9 @@
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
 	int alloc_ok = 1;
+	int npkts = 0;
 
-	if (speedo_debug > 4)
+	if (netif_msg_intr(sp))
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while (sp->rx_ringp[entry] != NULL) {
@@ -1780,14 +1780,14 @@
 		if (sp->last_rxf == sp->rx_ringp[entry]) {
 			/* Postpone the packet.  It'll be reaped at an interrupt when this
 			   packet is no longer the last packet in the ring. */
-			if (speedo_debug > 2)
+			if (netif_msg_rx_err(sp))
 				printk(KERN_DEBUG "%s: RX packet postponed!\n",
 					   dev->name);
 			sp->rx_ring_state |= RrPostponed;
 			break;
 		}
 
-		if (speedo_debug > 4)
+		if (netif_msg_rx_status(sp))
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   pkt_len);
 		if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) {
@@ -1822,6 +1822,7 @@
 				memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
 					   pkt_len);
 #endif
+				npkts++;
 			} else {
 				/* Pass up the already-filled skbuff. */
 				skb = sp->rx_skbuff[entry];
@@ -1832,6 +1833,7 @@
 				}
 				sp->rx_skbuff[entry] = NULL;
 				skb_put(skb, pkt_len);
+				npkts++;
 				sp->rx_ringp[entry] = NULL;
 				pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry],
 						PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
@@ -1852,7 +1854,8 @@
 	/* Try hard to refill the recently taken buffers. */
 	speedo_refill_rx_buffers(dev, 1);
 
-	sp->last_rx_time = jiffies;
+	if (npkts)
+		sp->last_rx_time = jiffies;
 
 	return 0;
 }
@@ -1867,21 +1870,25 @@
 	netdevice_stop(dev);
 	netif_stop_queue(dev);
 
-	if (speedo_debug > 1)
+	if (netif_msg_ifdown(sp))
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
 	/* Shut off the media monitoring timer. */
 	del_timer_sync(&sp->timer);
 
+	outw(SCBMaskAll, ioaddr + SCBCmd);
+
 	/* Shutting down the chip nicely fails to disable flow control. So.. */
 	outl(PortPartialReset, ioaddr + SCBPort);
+	inl(ioaddr + SCBPort); /* flush posted write */
+	/*
+	 * The chip requires a 10 microsecond quiet period.  Wait here!
+	 */
+	udelay(10);
 
 	free_irq(dev->irq, dev);
-
-	/* Print a few items for debugging. */
-	if (speedo_debug > 3)
-		speedo_show_state(dev);
+	speedo_show_state(dev);
 
     /* Free all the skbuffs in the Rx and Tx queues. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -1916,7 +1923,7 @@
 		sp->mc_setup_head = t;
 	}
 	sp->mc_setup_tail = NULL;
-	if (speedo_debug > 0)
+	if (netif_msg_ifdown(sp))
 		printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i);
 
 	pci_set_power_state(sp->pdev, 2);
@@ -1957,7 +1964,7 @@
 			/* Take a spinlock to make wait_for_cmd_done and sending the
 			   command atomic.  --SAW */
 			spin_lock_irqsave(&sp->lock, flags);
-			wait_for_cmd_done(ioaddr + SCBCmd);
+			wait_for_cmd_done(dev);
 			outb(CUDumpStats, ioaddr + SCBCmd);
 			spin_unlock_irqrestore(&sp->lock, flags);
 		}
@@ -2019,6 +2026,22 @@
 			return -EFAULT;
 		return 0;
 	}
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = sp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		sp->msg_enable = edata.data;
+		return 0;
+	}
 
         }
 	
@@ -2096,7 +2119,7 @@
 	} else
 		new_rx_mode = 0;
 
-	if (speedo_debug > 3)
+	if (netif_msg_rx_status(sp))
 		printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name,
 				sp->rx_mode, new_rx_mode);
 
@@ -2137,7 +2160,7 @@
 			config_cmd_data[8] = 0;
 		}
 		/* Trigger the command unit resume. */
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		outb(CUResume, ioaddr + SCBCmd);
 		if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) {
@@ -2174,7 +2197,7 @@
 			*setup_params++ = *eaddrs++;
 		}
 
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
 		outb(CUResume, ioaddr + SCBCmd);
@@ -2207,7 +2230,7 @@
 		mc_setup_frm = &mc_blk->frame;
 
 		/* Fill the setup frame. */
-		if (speedo_debug > 1)
+		if (netif_msg_ifup(sp))
 			printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n",
 				   dev->name, mc_setup_frm);
 		mc_setup_frm->cmd_status =
@@ -2250,7 +2273,7 @@
 		pci_dma_sync_single(sp->pdev, mc_blk->frame_dma,
 				mc_blk->len, PCI_DMA_TODEVICE);
 
-		wait_for_cmd_done(ioaddr + SCBCmd);
+		wait_for_cmd_done(dev);
 		clear_suspend(last_cmd);
 		/* Immediately trigger the command unit resume. */
 		outb(CUResume, ioaddr + SCBCmd);
@@ -2261,7 +2284,7 @@
 		}
 		spin_unlock_irqrestore(&sp->lock, flags);
 
-		if (speedo_debug > 5)
+		if (netif_msg_rx_status(sp))
 			printk(" CmdMCSetup frame length %d in entry %d.\n",
 				   dev->mc_count, entry);
 	}
@@ -2404,11 +2427,9 @@
 
 static int __init eepro100_init_module(void)
 {
-	if (debug >= 0 && speedo_debug != debug)
-		printk(KERN_INFO "eepro100.c: Debug level is %d.\n", debug);
-	if (debug >= 0)
-		speedo_debug = debug;
-
+#ifdef MODULE
+	printk(version);
+#endif
 	return pci_module_init(&eepro100_driver);
 }
 
diff -urN linux-2.4.20-pre11/drivers/net/ewrk3.c linux-2.4.20-rc1/drivers/net/ewrk3.c
--- linux-2.4.20-pre11/drivers/net/ewrk3.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/ewrk3.c	Tue Oct 29 08:35:09 2002
@@ -135,8 +135,10 @@
    0.43    16-Aug-96   Update alloc_device() to conform to de4x5.c
    0.44    08-Nov-01   use library crc32 functions <Matt_Domsch@dell.com>
    0.45    19-Jul-02   fix unaligned access on alpha <martin@bruli.net>
-   0.46    10-Oct-02   cli/sti removal <VDA@port.imtp.ilyichevsk.odessa.ua>
-   Multiple NIC support when module <akropel1@rochester.rr.com>
+   0.46    10-Oct-02   Multiple NIC support when module <akropel1@rochester.rr.com>
+   0.47    18-Oct-02   ethtool support <akropel1@rochester.rr.com>
+   0.48    18-Oct-02   cli/sti removal for 2.5 <vda@port.imtp.ilyichevsk.odessa.ua>
+   ioctl locking, signature search cleanup <akropel1@rochester.rr.com>
 
    =========================================================================
  */
@@ -161,6 +163,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <linux/time.h>
 #include <linux/types.h>
@@ -169,8 +172,11 @@
 
 #include "ewrk3.h"
 
+#define DRV_NAME	"ewrk3"
+#define DRV_VERSION	"0.48"
+
 static char version[] __initdata =
-"ewrk3.c:v0.46 2002/10/09 davies@maniac.ultranet.com\n";
+DRV_NAME ":v" DRV_VERSION " 2002/10/18 davies@maniac.ultranet.com\n";
 
 #ifdef EWRK3_DEBUG
 static int ewrk3_debug = EWRK3_DEBUG;
@@ -258,26 +264,29 @@
 #define EWRK3_PKT_BIN_SZ  128	/* Should be >=100 unless you
 				   increase EWRK3_PKT_STAT_SZ */
 
+struct ewrk3_stats {
+	u32 bins[EWRK3_PKT_STAT_SZ];
+	u32 unicast;
+	u32 multicast;
+	u32 broadcast;
+	u32 excessive_collisions;
+	u32 tx_underruns;
+	u32 excessive_underruns;
+};
+
 struct ewrk3_private {
 	char adapter_name[80];	/* Name exported to /proc/ioports */
 	u_long shmem_base;	/* Shared memory start address */
 	u_long shmem_length;	/* Shared memory window length */
 	struct net_device_stats stats;	/* Public stats */
-	struct {
-		u32 bins[EWRK3_PKT_STAT_SZ];	/* Private stats counters */
-		u32 unicast;
-		u32 multicast;
-		u32 broadcast;
-		u32 excessive_collisions;
-		u32 tx_underruns;
-		u32 excessive_underruns;
-	} pktStats;
+	struct ewrk3_stats pktStats; /* Private stats counters */
 	u_char irq_mask;	/* Adapter IRQ mask bits */
 	u_char mPage;		/* Maximum 2kB Page number */
 	u_char lemac;		/* Chip rev. level */
 	u_char hard_strapped;	/* Don't allow a full open */
 	u_char txc;		/* Transmit cut through */
 	u_char *mctbl;		/* Pointer to the multicast table */
+	u_char led_mask;	/* Used to reserve LED access for ethtool */
 	spinlock_t hw_lock;
 };
 
@@ -533,6 +542,7 @@
 							lp->shmem_length = shmem_length;
 							lp->lemac = lemac;
 							lp->hard_strapped = hard_strapped;
+							lp->led_mask = CR_LED;
 							spin_lock_init(&lp->hw_lock);
 
 							lp->mPage = 64;
@@ -903,7 +913,7 @@
 	DISABLE_IRQs;
 
 	cr = inb(EWRK3_CR);
-	cr |= CR_LED;
+	cr |= lp->led_mask;
 	outb(cr, EWRK3_CR);
 
 	if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */
@@ -928,12 +938,13 @@
 	}
 
 	/* Unmask the EWRK3 board interrupts and turn off the LED */
-	cr &= ~CR_LED;
+	cr &= ~(lp->led_mask);
 	outb(cr, EWRK3_CR);
 	ENABLE_IRQs;
 	spin_unlock(&lp->hw_lock);
 }
 
+/* Called with lp->hw_lock held */
 static int ewrk3_rx(struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
@@ -1059,8 +1070,9 @@
 }
 
 /*
-   ** Buffer sent - check for TX buffer errors.
- */
+** Buffer sent - check for TX buffer errors.
+** Called with lp->hw_lock held
+*/
 static int ewrk3_tx(struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
@@ -1468,27 +1480,20 @@
  */
 static void __init EthwrkSignature(char *name, char *eeprom_image)
 {
-	u_long i, j, k;
+	int i;
 	char *signatures[] = EWRK3_SIGNATURE;
 
-	strcpy(name, "");
-	for (i = 0; *signatures[i] != '\0' && *name == '\0'; i++) {
-		for (j = EEPROM_PNAME7, k = 0; j <= EEPROM_PNAME0 && k < strlen(signatures[i]); j++) {
-			if (signatures[i][k] == eeprom_image[j]) {	/* track signature */
-				k++;
-			} else {	/* lost signature; begin search again */
-				k = 0;
-			}
-		}
-		if (k == strlen(signatures[i])) {
-			for (k = 0; k < EWRK3_STRLEN; k++) {
-				name[k] = eeprom_image[EEPROM_PNAME7 + k];
-				name[EWRK3_STRLEN] = '\0';
-			}
-		}
-	}
+	for (i=0; *signatures[i] != '\0'; i++)
+		if( !strncmp(eeprom_image+EEPROM_PNAME7, signatures[i], strlen(signatures[i])) )
+			break;
+
+	if (*signatures[i] != '\0') {
+		memcpy(name, eeprom_image+EEPROM_PNAME7, EWRK3_STRLEN);
+		name[EWRK3_STRLEN] = '\0';
+	} else
+		name[0] = '\0';
 
-	return;			/* return the device name string */
+	return;
 }
 
 /*
@@ -1624,6 +1629,197 @@
 	return status;		/* return the device name string */
 }
 
+static int ewrk3_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	u_long iobase = dev->base_addr;
+	u32 ethcmd;
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	/* Get driver info */
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
+
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		sprintf(info.fw_version, "%d", fwrev);
+		strcpy(info.bus_info, "N/A");
+		info.eedump_len = EEPROM_MAX;
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		u_char cr = inb(EWRK3_CR);
+
+		switch (lp->adapter_name[4]) {
+		case '3': /* DE203 */
+			ecmd.supported = SUPPORTED_BNC;
+			ecmd.port = PORT_BNC;
+			break;
+
+		case '4': /* DE204 */
+			ecmd.supported = SUPPORTED_TP;
+			ecmd.port = PORT_TP;
+			break;
+
+		case '5': /* DE205 */
+			ecmd.supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
+			ecmd.autoneg = !(cr & CR_APD);
+			/*
+			** Port is only valid if autoneg is disabled
+			** and even then we don't know if AUI is jumpered.
+			*/
+			if (!ecmd.autoneg)
+				ecmd.port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
+			break;
+		}
+
+		ecmd.supported |= SUPPORTED_10baseT_Half;
+		ecmd.speed = SPEED_10;
+		ecmd.duplex = DUPLEX_HALF;
+
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Set settings */
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd ecmd;
+		u_char cr;
+		u_long flags;
+
+		/* DE205 is the only card with anything to set */
+		if (lp->adapter_name[4] != '5')
+			return -EOPNOTSUPP;
+
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+
+		/* Sanity-check parameters */
+		if (ecmd.speed != SPEED_10)
+			return -EINVAL;
+		if (ecmd.port != PORT_TP && ecmd.port != PORT_BNC)
+			return -EINVAL; /* AUI is not software-selectable */
+		if (ecmd.transceiver != XCVR_INTERNAL)
+			return -EINVAL;
+		if (ecmd.duplex != DUPLEX_HALF)
+			return -EINVAL;
+		if (ecmd.phy_address != 0)
+			return -EINVAL;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+		cr = inb(EWRK3_CR);
+
+		/* If Autoneg is set, change to Auto Port mode */
+		/* Otherwise, disable Auto Port and set port explicitly */
+		if (ecmd.autoneg) {
+			cr &= ~CR_APD;
+		} else {
+			cr |= CR_APD;
+			if (ecmd.port == PORT_TP)
+				cr &= ~CR_PSEL;		/* Force TP */
+			else
+				cr |= CR_PSEL;		/* Force BNC */
+		}
+
+		/* Commit the changes */
+		outb(cr, EWRK3_CR);
+
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* Get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		u_char cmr = inb(EWRK3_CMR);
+
+		/* DE203 has BNC only and link status does not apply */
+		if (lp->adapter_name[4] == '3')
+			return -EOPNOTSUPP;
+
+		/* On DE204 this is always valid since TP is the only port. */
+		/* On DE205 this reflects TP status even if BNC or AUI is selected. */
+		edata.data = !(cmr & CMR_LINK);
+
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef BROKEN
+	/* Blink LED for identification */
+	case ETHTOOL_PHYS_ID: {
+		struct ethtool_value edata;
+		u_long flags;
+		long delay, ret;
+		u_char cr;
+		int count;
+		wait_queue_head_t wait;
+
+		init_waitqueue_head(&wait);
+
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+
+		/* Toggle LED 4x per second */
+		delay = HZ >> 2;
+		count = edata.data << 2;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+
+		/* Bail if a PHYS_ID is already in progress */
+		if (lp->led_mask == 0) {
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
+			return -EBUSY;
+		}
+
+		/* Prevent ISR from twiddling the LED */
+		lp->led_mask = 0;
+
+		while (count--) {
+			/* Toggle the LED */
+			cr = inb(EWRK3_CR);
+			outb(cr ^ CR_LED, EWRK3_CR);
+
+			/* Wait a little while */
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
+			ret = delay;
+			__wait_event_interruptible_timeout(wait, 0, ret);
+			spin_lock_irqsave(&lp->hw_lock, flags);
+
+			/* Exit if we got a signal */
+			if (ret == -ERESTARTSYS)
+				goto out;
+		}
+
+		ret = 0;
+out:
+		lp->led_mask = CR_LED;
+		cr = inb(EWRK3_CR);
+		outb(cr & ~CR_LED, EWRK3_CR);
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
+		return ret;
+	}
+#endif /* BROKEN */
+
+	}
+
+	return -EOPNOTSUPP;
+}
+
 /*
    ** Perform IOCTL call functions here. Some are privileged operations and the
    ** effective uid is checked in those cases.
@@ -1635,6 +1831,7 @@
 	u_long iobase = dev->base_addr;
 	int i, j, status = 0;
 	u_char csr;
+	unsigned long flags;
 	union ewrk3_addr {
 		u_char addr[HASH_TABLE_LEN * ETH_ALEN];
 		u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
@@ -1642,6 +1839,14 @@
 	
 	union ewrk3_addr *tmp;
 
+	/* ethtool IOCTLs are handled elsewhere */
+	if (cmd == SIOCETHTOOL)
+		return ewrk3_ethtool_ioctl(dev, (void *)rq->ifr_data);
+
+	/* Other than ethtool, all we handle are private IOCTLs */
+	if (cmd != EWRK3IOCTL)
+		return -EOPNOTSUPP;
+
 	tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
 	if(tmp==NULL)
 		return -ENOMEM;
@@ -1658,21 +1863,26 @@
 		
 	case EWRK3_SET_HWADDR:	/* Set the hardware address */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= (CSR_TXD | CSR_RXD);
 			outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 
 			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
 				status = -EFAULT;
 				break;
 			}
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			for (i = 0; i < ETH_ALEN; i++) {
 				dev->dev_addr[i] = tmp->addr[i];
 				outb(tmp->addr[i], EWRK3_PAR0 + i);
 			}
 
+			csr = inb(EWRK3_CSR);
 			csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1680,10 +1890,12 @@
 		break;
 	case EWRK3_SET_PROM:	/* Set Promiscuous Mode */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= CSR_PME;
 			csr &= ~CSR_MCE;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1691,16 +1903,18 @@
 		break;
 	case EWRK3_CLR_PROM:	/* Clear Promiscuous Mode */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr &= ~CSR_PME;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
 
 		break;
 	case EWRK3_GET_MCA:	/* Get the multicast address table */
-		spin_lock_irq(&lp->hw_lock);
+		spin_lock_irqsave(&lp->hw_lock, flags);
 		if (lp->shmem_length == IO_ONLY) {
 			outb(0, EWRK3_IOPR);
 			outw(PAGE0_HTE, EWRK3_PIR1);
@@ -1711,7 +1925,7 @@
 			outb(0, EWRK3_MPR);
 			isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
 		}
-		spin_unlock_irq(&lp->hw_lock);
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
 
 		ioc->len = (HASH_TABLE_LEN >> 3);
 		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
@@ -1745,28 +1959,37 @@
 		break;
 	case EWRK3_MCA_EN:	/* Enable multicast addressing */
 		if (capable(CAP_NET_ADMIN)) {
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			csr = inb(EWRK3_CSR);
 			csr |= CSR_MCE;
 			csr &= ~CSR_PME;
 			outb(csr, EWRK3_CSR);
+			spin_unlock_irqrestore(&lp->hw_lock, flags);
 		} else {
 			status = -EPERM;
 		}
 
 		break;
-	case EWRK3_GET_STATS:	/* Get the driver statistics */
-		cli();
-		ioc->len = sizeof(lp->pktStats);
-		if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
-			status = -EFAULT;
-		sti();
+	case EWRK3_GET_STATS: { /* Get the driver statistics */
+		struct ewrk3_stats *tmp_stats =
+        		kmalloc(sizeof(lp->pktStats), GFP_KERNEL);
+		if (!tmp_stats) return -ENOMEM;
+
+		spin_lock_irqsave(&lp->hw_lock, flags);
+		memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats));
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
 
+		ioc->len = sizeof(lp->pktStats);
+		if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats)))
+    			status = -EFAULT;
+		kfree(tmp_stats);
 		break;
+	}
 	case EWRK3_CLR_STATS:	/* Zero out the driver statistics */
 		if (capable(CAP_NET_ADMIN)) {
-			cli();
+			spin_lock_irqsave(&lp->hw_lock, flags);
 			memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-			sti();
+			spin_unlock_irqrestore(&lp->hw_lock,flags);
 		} else {
 			status = -EPERM;
 		}
@@ -1854,7 +2077,7 @@
 #ifdef MODULE
 static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
 static int ndevs;
-static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };		/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
 static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, };		/* or use the insmod io= irq= options           */
 
 /* '21' below should really be 'MAX_NUM_EWRK3S' */
@@ -1895,8 +2118,7 @@
 {
 	int i;
 
-	for( i=0; i<ndevs; i++ )
-	{
+	for( i=0; i<ndevs; i++ ) {
 		unregister_netdev(ewrk3_devs[i]);
 		if (ewrk3_devs[i]->priv) {
 			kfree(ewrk3_devs[i]->priv);
diff -urN linux-2.4.20-pre11/drivers/net/mii.c linux-2.4.20-rc1/drivers/net/mii.c
--- linux-2.4.20-pre11/drivers/net/mii.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/mii.c	Tue Oct 29 08:35:14 2002
@@ -192,9 +192,12 @@
 
 void mii_check_link (struct mii_if_info *mii)
 {
-	if (mii_link_ok(mii))
+	int cur_link = mii_link_ok(mii);
+	int prev_link = netif_carrier_ok(mii->dev);
+
+	if (cur_link && !prev_link)
 		netif_carrier_on(mii->dev);
-	else
+	else if (prev_link && !cur_link)
 		netif_carrier_off(mii->dev);
 }
 
@@ -299,9 +302,9 @@
 			case MII_BMCR: {
 				unsigned int new_duplex = 0;
 				if (val & (BMCR_RESET|BMCR_ANENABLE))
-					mii_if->force_media = 1;
-				else
 					mii_if->force_media = 0;
+				else
+					mii_if->force_media = 1;
 				if (mii_if->force_media &&
 				    (val & BMCR_FULLDPLX))
 					new_duplex = 1;
diff -urN linux-2.4.20-pre11/drivers/net/natsemi.c linux-2.4.20-rc1/drivers/net/natsemi.c
--- linux-2.4.20-pre11/drivers/net/natsemi.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/natsemi.c	Tue Oct 29 08:35:14 2002
@@ -184,7 +184,7 @@
 				 NETIF_MSG_WOL		| \
 				 NETIF_MSG_RX_ERR	| \
 				 NETIF_MSG_TX_ERR)
-static int debug = NATSEMI_DEF_MSG;
+static int debug = -1;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -256,7 +256,7 @@
 MODULE_PARM_DESC(max_interrupt_work, 
 	"DP8381x maximum events handled per interrupt");
 MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
-MODULE_PARM_DESC(debug, "DP8381x default debug bitmask");
+MODULE_PARM_DESC(debug, "DP8381x default debug level");
 MODULE_PARM_DESC(rx_copybreak, 
 	"DP8381x copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(options, 
@@ -796,7 +796,7 @@
 	pci_set_drvdata(pdev, dev);
 	np->iosize = iosize;
 	spin_lock_init(&np->lock);
-	np->msg_enable = debug;
+	np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
 	np->hands_off = 0;
 
 	/* Reset the chip to erase previous misconfiguration. */
diff -urN linux-2.4.20-pre11/drivers/net/pcmcia/axnet_cs.c linux-2.4.20-rc1/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.20-pre11/drivers/net/pcmcia/axnet_cs.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/pcmcia/axnet_cs.c	Tue Oct 29 08:35:14 2002
@@ -11,8 +11,8 @@
 
     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
 
-    axnet_cs.c 1.24 2001/11/18 02:46:51
-    
+    axnet_cs.c 1.28 2002/06/29 06:27:37
+
     The network driver code is based on Donald Becker's NE2000 code:
 
     Written 1992,1993 by Donald Becker.
@@ -55,12 +55,17 @@
 #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
 #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
 #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
+#define AXNET_TEST	0x15	/* Offset of TEST Register port */
+#define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
 
 #define AXNET_START_PG	0x40	/* First page of TX buffer */
 #define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
 
+#define IS_AX88190	0x0001
+#define IS_AX88790	0x0002
+
 /*====================================================================*/
 
 /* Module parameters */
@@ -80,7 +85,7 @@
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"axnet_cs.c 1.24 2001/11/18 02:46:51 (David Hinds)";
+"axnet_cs.c 1.28 2002/06/29 06:27:37 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -117,6 +122,7 @@
 static int axdev_init(struct net_device *dev);
 static void AX88190_init(struct net_device *dev, int startp);
 static int ax_open(struct net_device *dev);
+static int ax_close(struct net_device *dev);
 static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 /*====================================================================*/
@@ -131,6 +137,7 @@
     u_short		link_status;
     u_char		duplex_flag;
     int			phy_id;
+    int			flags;
 } axnet_dev_t;
 
 /*======================================================================
@@ -475,17 +482,37 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
-    printk(KERN_INFO "%s: Asix AX88190: io %#3lx, irq %d, hw_addr ",
-	   dev->name, dev->base_addr, dev->irq);
+    if (inb(dev->base_addr + AXNET_TEST) != 0)
+	info->flags |= IS_AX88790;
+    else
+	info->flags |= IS_AX88190;
+
+    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
+	   dev->base_addr, dev->irq);
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    if (info->flags & IS_AX88790)
+	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
+
     for (i = 0; i < 32; i++) {
 	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
 	if ((j != 0) && (j != 0xffff)) break;
     }
+
+    /* Maybe PHY is in power down mode. (PPD_SET = 1) 
+       Bit 2 of CCSR is active low. */ 
+    if (i == 32) {
+	conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
+ 	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	for (i = 0; i < 32; i++) {
+	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
+	    if ((j != 0) && (j != 0xffff)) break;
+	}
+    }
+
     info->phy_id = (i < 32) ? i : -1;
     if (i < 32) {
 	DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
@@ -493,12 +520,14 @@
 	printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     axnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* axnet_config */
 
@@ -557,7 +586,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	axnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -680,6 +709,7 @@
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
+    ax_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
@@ -912,7 +942,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "axnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &axnet_attach, &axnet_detach);
     return 0;
@@ -1103,6 +1133,29 @@
 	return 0;
 }
 
+#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
+
+/**
+ * ax_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
+ */
+int ax_close(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 *      Hold the page lock during close
+	 */
+
+	spin_lock_irqsave(&dev_lock(dev), flags);
+	AX88190_init(dev, 0);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
+	netif_stop_queue(dev);
+	return 0;
+}
+
 /**
  * ei_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
@@ -1758,8 +1811,6 @@
  *	not called too often. Must protect against both bh and irq users
  */
 
-#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
-
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
diff -urN linux-2.4.20-pre11/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.20-rc1/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.20-pre11/drivers/net/pcmcia/fmvj18x_cs.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/pcmcia/fmvj18x_cs.c	Tue Oct 29 08:35:15 2002
@@ -362,7 +362,7 @@
     if (*linkp == NULL)
 	return;
 
-    del_timer(&link->release);
+    del_timer_sync(&link->release);
     if (link->state & DEV_CONFIG) {
 	fmvj18x_release((u_long)link);
 	if (link->state & DEV_STALE_CONFIG) {
@@ -571,8 +571,7 @@
     case XXX10304:
 	/* Read MACID from Buggy CIS */
 	if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) {
-	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net 
-		address.");
+	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
 	    unregister_netdev(dev);
 	    goto failed;
 	}
diff -urN linux-2.4.20-pre11/drivers/net/pcmcia/nmclan_cs.c linux-2.4.20-rc1/drivers/net/pcmcia/nmclan_cs.c
--- linux-2.4.20-pre11/drivers/net/pcmcia/nmclan_cs.c	Mon Feb 25 11:37:59 2002
+++ linux-2.4.20-rc1/drivers/net/pcmcia/nmclan_cs.c	Tue Oct 29 08:35:15 2002
@@ -437,8 +437,8 @@
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
-
 static void set_multicast_list(struct net_device *dev);
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 static dev_link_t *nmclan_attach(void);
 static void nmclan_detach(dev_link_t *);
@@ -520,6 +520,7 @@
     dev->set_config = &mace_config;
     dev->get_stats = &mace_get_stats;
     dev->set_multicast_list = &set_multicast_list;
+    dev->do_ioctl = &mace_ioctl;
     ether_setup(dev);
     dev->open = &mace_open;
     dev->stop = &mace_close;
@@ -1057,7 +1058,7 @@
 	return -EOPNOTSUPP;
 }
 
-static int smc91c92_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	switch (cmd) {
 	case SIOCETHTOOL:
diff -urN linux-2.4.20-pre11/drivers/net/pcmcia/pcnet_cs.c linux-2.4.20-rc1/drivers/net/pcmcia/pcnet_cs.c
--- linux-2.4.20-pre11/drivers/net/pcmcia/pcnet_cs.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/pcmcia/pcnet_cs.c	Tue Oct 29 08:35:15 2002
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    pcnet_cs.c 1.144 2001/11/07 04:06:56
+    pcnet_cs.c 1.149 2002/06/29 06:27:37
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -75,7 +75,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.144 2001/11/07 04:06:56 (David Hinds)";
+"pcnet_cs.c 1.149 2002/06/29 06:27:37 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -765,12 +765,13 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
 	u_char id = inb(dev->base_addr + 0x1a);
 	dev->do_ioctl = &ei_ioctl;
 	mii_phy_probe(dev);
+	if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
+	    info->eth_phy = 0;
 	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
 	if (info->pna_phy)
@@ -787,12 +788,14 @@
     printk(" hw_addr ");
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     pcnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* pcnet_config */
 
@@ -856,7 +859,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	pcnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1051,6 +1054,7 @@
 
     DEBUG(2, "pcnet_close('%s')\n", dev->name);
 
+    ei_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
@@ -1620,7 +1624,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "pcnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);
     return 0;
diff -urN linux-2.4.20-pre11/drivers/net/pcmcia/ray_cs.c linux-2.4.20-rc1/drivers/net/pcmcia/ray_cs.c
--- linux-2.4.20-pre11/drivers/net/pcmcia/ray_cs.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/pcmcia/ray_cs.c	Tue Oct 29 08:35:15 2002
@@ -2,7 +2,7 @@
  *
  * A  PCMCIA client driver for the Raylink wireless LAN card.
  * The starting point for this module was the skeleton.c in the
- * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu
+ * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net
  *
  *
  * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
diff -urN linux-2.4.20-pre11/drivers/net/pcnet32.c linux-2.4.20-rc1/drivers/net/pcnet32.c
--- linux-2.4.20-pre11/drivers/net/pcnet32.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/net/pcnet32.c	Tue Oct 29 08:35:16 2002
@@ -22,8 +22,8 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.27a"
-#define DRV_RELDATE	"10.02.2002"
+#define DRV_VERSION	"1.27b"
+#define DRV_RELDATE	"01.10.2002"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
@@ -97,6 +97,8 @@
 
 #define PCNET32_DMA_MASK 0xffffffff
 
+#define PCNET32_WATCHDOG_TIMEOUT (jiffies + (2 * HZ))
+
 /*
  * table to translate option values from tulip
  * to internal options
@@ -212,6 +214,8 @@
  *	   fix pci probe not increment cards_found
  *	   FD auto negotiate error workaround for xSeries250
  *	   clean up and using new mii module
+ * v1.27b  Sep 30 2002 Kent Yoder <yoder1@us.ibm.com>
+ * 	   Added timer for cable connection state changes.
  */
 
 
@@ -319,6 +323,7 @@
 	mii:1;				/* mii port available */
     struct net_device	*next;
     struct mii_if_info mii_if;
+    struct timer_list	watchdog_timer;
 };
 
 static void pcnet32_probe_vlbus(void);
@@ -334,6 +339,7 @@
 static struct net_device_stats *pcnet32_get_stats(struct net_device *);
 static void pcnet32_set_multicast_list(struct net_device *);
 static int  pcnet32_ioctl(struct net_device *, struct ifreq *, int);
+static void pcnet32_watchdog(struct net_device *);
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num);
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val);
 
@@ -778,6 +784,13 @@
 	}
     }
 
+    /* Set the mii phy_id so that we can query the link state */
+    if (lp->mii)
+	lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f;
+
+    init_timer (&lp->watchdog_timer);
+    lp->watchdog_timer.data = (unsigned long) dev;
+    lp->watchdog_timer.function = (void *) &pcnet32_watchdog;
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -902,6 +915,12 @@
 
     netif_start_queue(dev);
 
+    /* If we have mii, print the link status and start the watchdog */
+    if (lp->mii) {
+	mii_check_media (&lp->mii_if, 1, 1);
+	mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+    }
+    
     i = 0;
     while (i++ < 100)
 	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
@@ -1372,6 +1391,8 @@
     struct pcnet32_private *lp = dev->priv;
     int i;
 
+    del_timer_sync(&lp->watchdog_timer);
+
     netif_stop_queue(dev);
 
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
@@ -1652,6 +1673,17 @@
     return -EOPNOTSUPP;
 }
 
+static void pcnet32_watchdog(struct net_device *dev)
+{
+    struct pcnet32_private *lp = dev->priv;
+
+    /* Print the link status if it has changed */
+    if (lp->mii)
+	mii_check_media (&lp->mii_if, 1, 0);
+
+    mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+}
+
 static struct pci_driver pcnet32_driver = {
     name:	DRV_NAME,
     probe:	pcnet32_probe_pci,
diff -urN linux-2.4.20-pre11/drivers/net/tulip/tulip_core.c linux-2.4.20-rc1/drivers/net/tulip/tulip_core.c
--- linux-2.4.20-pre11/drivers/net/tulip/tulip_core.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/tulip/tulip_core.c	Tue Oct 29 08:35:22 2002
@@ -218,6 +218,7 @@
 	{ 0x13D1, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x104A, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x104A, 0x2774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x1259, 0xa120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
 	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },
@@ -1482,7 +1483,6 @@
 	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
 
 	dev->base_addr = ioaddr;
-	dev->irq = irq;
 
 #ifdef CONFIG_TULIP_MWI
 	if (!force_csr0 && (tp->flags & HAS_PCI_MWI))
@@ -1655,6 +1655,7 @@
 	for (i = 0; i < 6; i++)
 		last_phys_addr[i] = dev->dev_addr[i];
 	last_irq = irq;
+	dev->irq = irq;
 
 	/* The lower four bits are the media type. */
 	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
diff -urN linux-2.4.20-pre11/drivers/net/wavelan.p.h linux-2.4.20-rc1/drivers/net/wavelan.p.h
--- linux-2.4.20-pre11/drivers/net/wavelan.p.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/net/wavelan.p.h	Tue Oct 29 08:35:26 2002
@@ -143,7 +143,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * 2.00 cards correctly (2.4 GHz with frequency selection).
- * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * PCMCIA package (and bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
diff -urN linux-2.4.20-pre11/drivers/net/wireless/airo_cs.c linux-2.4.20-rc1/drivers/net/wireless/airo_cs.c
--- linux-2.4.20-pre11/drivers/net/wireless/airo_cs.c	Mon Feb 25 11:38:03 2002
+++ linux-2.4.20-rc1/drivers/net/wireless/airo_cs.c	Tue Oct 29 08:35:27 2002
@@ -15,7 +15,7 @@
 
     In addition this module was derived from dummy_cs.
     The initial developer of dummy_cs is David A. Hinds
-    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
     
 ======================================================================*/
diff -urN linux-2.4.20-pre11/drivers/pcmcia/cardbus.c linux-2.4.20-rc1/drivers/pcmcia/cardbus.c
--- linux-2.4.20-pre11/drivers/pcmcia/cardbus.c	Mon Nov 12 09:39:01 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/cardbus.c	Tue Oct 29 08:35:30 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/cirrus.h linux-2.4.20-rc1/drivers/pcmcia/cirrus.h
--- linux-2.4.20-pre11/drivers/pcmcia/cirrus.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/cirrus.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/i82365.c linux-2.4.20-rc1/drivers/pcmcia/i82365.c
--- linux-2.4.20-pre11/drivers/pcmcia/i82365.c	Mon Nov 12 09:39:01 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/i82365.c	Tue Oct 29 08:35:30 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/i82365.h linux-2.4.20-rc1/drivers/pcmcia/i82365.h
--- linux-2.4.20-pre11/drivers/pcmcia/i82365.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/i82365.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/o2micro.h linux-2.4.20-rc1/drivers/pcmcia/o2micro.h
--- linux-2.4.20-pre11/drivers/pcmcia/o2micro.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/o2micro.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/ricoh.h linux-2.4.20-rc1/drivers/pcmcia/ricoh.h
--- linux-2.4.20-pre11/drivers/pcmcia/ricoh.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/pcmcia/ricoh.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/tcic.c linux-2.4.20-rc1/drivers/pcmcia/tcic.c
--- linux-2.4.20-pre11/drivers/pcmcia/tcic.c	Sun Sep 30 12:26:07 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/tcic.c	Tue Oct 29 08:35:30 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -67,7 +67,7 @@
 #define DEBUG(n, args...)
 #endif
 
-MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
 MODULE_LICENSE("Dual MPL/GPL");
 
diff -urN linux-2.4.20-pre11/drivers/pcmcia/tcic.h linux-2.4.20-rc1/drivers/pcmcia/tcic.h
--- linux-2.4.20-pre11/drivers/pcmcia/tcic.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/tcic.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/ti113x.h linux-2.4.20-rc1/drivers/pcmcia/ti113x.h
--- linux-2.4.20-pre11/drivers/pcmcia/ti113x.h	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/pcmcia/ti113x.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/topic.h linux-2.4.20-rc1/drivers/pcmcia/topic.h
--- linux-2.4.20-pre11/drivers/pcmcia/topic.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/topic.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/pcmcia/vg468.h linux-2.4.20-rc1/drivers/pcmcia/vg468.h
--- linux-2.4.20-pre11/drivers/pcmcia/vg468.h	Fri Feb 16 16:02:36 2001
+++ linux-2.4.20-rc1/drivers/pcmcia/vg468.h	Tue Oct 29 08:35:30 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/drivers/scsi/3w-xxxx.c linux-2.4.20-rc1/drivers/scsi/3w-xxxx.c
--- linux-2.4.20-pre11/drivers/scsi/3w-xxxx.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/scsi/3w-xxxx.c	Tue Oct 29 08:35:32 2002
@@ -149,6 +149,17 @@
                  Cleanup some AEN severity levels.
    1.02.00.027 - Add drive not supported AEN code for SATA controllers.
                  Remove spurious unknown ioctl error message.
+   1.02.00.028 - Fix bug where multiple controllers with no units were the
+                 same card number.
+                 Fix bug where cards were being shut down more than once.
+   1.02.00.029 - Add new pci dma mapping for kernel 2.4 for highmem support.
+                 Replace pci_map_single() with pci_map_page() for highmem.
+                 Check for tw_setfeature() failure.
+   1.02.00.030 - Make driver 64-bit clean.
+   1.02.00.031 - Cleanup polling timeouts/routines in several places.
+                 Add support for mode sense opcode.
+                 Add support for cache mode page.
+                 Add support for synchronize cache opcode.
 */
 
 #include <linux/module.h>
@@ -195,6 +206,9 @@
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
 
 /* Notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block tw_notifier = {
@@ -202,7 +216,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.027";
+char *tw_driver_version="1.02.00.031";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -278,11 +292,10 @@
 {
 	TW_Command *command_packet;
 	TW_Param *param;
-	int tries = 0;
 	int request_id = 0;
-	u32 command_que_value = 0, command_que_addr;
-	u32 status_reg_value = 0, status_reg_addr;
-	u32 param_value;
+	u32 command_que_addr;
+	unsigned long command_que_value;
+	unsigned long param_value;
 	TW_Response_Queue response_queue;
 	u32 response_que_addr;
 	unsigned short aen;
@@ -290,13 +303,11 @@
 	int finished = 0;
 	int first_reset = 0;
 	int queue = 0;
-	int imax, i;
 	int found = 0, table_max = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
 
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
@@ -348,114 +359,95 @@
 	command_packet->byte8.param.sgl[0].address = param_value;
 	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
 
-	imax = TW_POLL_MAX_RETRIES;
-
 	/* Now drain the controller's aen queue */
 	do {
 		/* Post command packet */
 		outl(command_que_value, command_que_addr);
 
 		/* Now poll for completion */
-		for (i=0;i<imax;i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value, 0);
+		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+			response_queue.value = inl(response_que_addr);
+			request_id = (unsigned char)response_queue.u.response_id;
+			if (request_id != 0) {
+				/* Unexpected request id */
+				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
 				return 1;
 			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-    
-				if (request_id != 0) {
-					/* Unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
+	
+			if (command_packet->status != 0) {
+				if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
+					/* Bad response */
+					tw_decode_sense(tw_dev, request_id, 0);
 					return 1;
+				} else {
+					/* We know this is a 3w-1x00, and doesn't support aen's */
+					return 0;
 				}
-	
-				if (command_packet->status != 0) {
-					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
-						/* Bad response */
-						tw_decode_sense(tw_dev, request_id, 0);
+			}
+
+			/* Now check the aen */
+			aen = *(unsigned short *)(param->data);
+			aen_code = (aen & 0x0ff);
+			queue = 0;
+			switch (aen_code) {
+				case TW_AEN_QUEUE_EMPTY:
+					dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+					if (first_reset != 1) {
 						return 1;
 					} else {
-						/* We know this is a 3w-1x00, and doesn't support aen's */
-						return 0;
+						finished = 1;
 					}
-				}
-
-				/* Now check the aen */
-				aen = *(unsigned short *)(param->data);
-				aen_code = (aen & 0x0ff);
-				queue = 0;
-				switch (aen_code) {
-					case TW_AEN_QUEUE_EMPTY:
-						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-						if (first_reset != 1) {
-							continue;
-						} else {
-							finished = 1;
-						}
-						break;
-					case TW_AEN_SOFT_RESET:
-						if (first_reset == 0) {
-							first_reset = 1;
-						} else {
-							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-							tw_dev->aen_count++;
-							queue = 1;
-						}
-						break;
-					default:
-						if (aen == 0x0ff) {
-							printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
-						} else {
-							table_max = sizeof(tw_aen_string)/sizeof(char *);
-							if ((aen & 0x0ff) < table_max) {
-								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
-									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
-								} else {
-									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-								}
-							} else
-								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
-						}
+					break;
+				case TW_AEN_SOFT_RESET:
+					if (first_reset == 0) {
+						first_reset = 1;
+					} else {
+						printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
 						tw_dev->aen_count++;
 						queue = 1;
-				}
-
-				/* Now put the aen on the aen_queue */
-				if (queue == 1) {
-					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;
+					}
+					break;
+				default:
+					if (aen == 0x0ff) {
+						printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
 					} else {
-						tw_dev->aen_tail = tw_dev->aen_tail + 1;
+						table_max = sizeof(tw_aen_string)/sizeof(char *);
+						if ((aen & 0x0ff) < table_max) {
+							if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
+							} else {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+							}
+						} else
+							printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
 					}
-					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;
-						}
+					tw_dev->aen_count++;
+					queue = 1;
+			}
+
+			/* Now put the aen on the aen_queue */
+			if (queue == 1) {
+				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;
+					} else {
+						tw_dev->aen_head = tw_dev->aen_head + 1;
 					}
 				}
-				found = 1;
-				break;
 			}
+			found = 1;
 		}
 		if (found == 0) {
 			printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
 			return 1;
 		}
-		tries++;
-	} while ((tries < TW_MAX_AEN_TRIES) && (finished == 0));
-
-	if (tries >=TW_MAX_AEN_TRIES) {
-		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Aen queue error.\n");
-		return 1;
-	}
+	} while (finished == 0);
 
 	return 0;
 } /* End tw_aen_drain_queue() */
@@ -465,9 +457,10 @@
 {
 	TW_Command *command_packet;
 	TW_Param *param;
-	u32 command_que_value = 0, command_que_addr;
+	u32 command_que_addr;
+	unsigned long command_que_value;
 	u32 status_reg_value = 0, status_reg_addr;
-	u32 param_value = 0;
+	unsigned long param_value = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
@@ -532,39 +525,55 @@
 } /* End tw_aen_read_queue() */
 
 /* This function will allocate memory and check if it is 16 d-word aligned */
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
 {
-	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
+	int i, imax;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr = NULL;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
 
-	if (!virt_addr) {
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-		return 1;
-	}
 
-	if ((u32)virt_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
-		kfree(virt_addr);
-		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
-		return 1;
-	}
+	if (which == 2)
+		imax = TW_MAX_BOUNCEBUF;
+	else
+		imax = TW_Q_LENGTH;
 
-	switch(which) {
-	case 0:
-		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 1:
-		tw_dev->alignment_virtual_address[request_id] = virt_addr;
-		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 2:
-		tw_dev->bounce_buffer[request_id] = virt_addr;
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
-		return 1;
+	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;
+		}
+
+		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;
+		}
+
+		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);
+			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);
+			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);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+			return 1;
+		}
 	}
+
 	return 0;
 } /* End tw_allocate_memory() */
 
@@ -809,19 +818,29 @@
 	struct pci_dev *tw_pci_dev = NULL;
 	u32 status_reg_value;
 	unsigned char c = 1;
-	int i;
+	int i, j = -1;
 	u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
 
 	for (i=0;i<TW_NUMDEVICES;i++) {
 		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+			j++;
 			if (pci_enable_device(tw_pci_dev))
 				continue;
+
+			/* We only need 32-bit addressing for 5,6,7xxx cards */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
+			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
+				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
+				continue;
+			}
+#endif
+
 			/* Prepare temporary device extension */
 			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
 			if (tw_dev == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", j);
 				continue;
 			}
 			memset(tw_dev, 0, sizeof(TW_Device_Extension));
@@ -831,7 +850,7 @@
 
 			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -851,7 +870,7 @@
 			
 			/* Poll status register for 60 secs for 'Controller Ready' flag */
 			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -866,14 +885,14 @@
 
 				error = tw_aen_drain_queue(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", j);
 					tries++;
 					continue;
 				}
 
 				/* Check for controller errors */
 				if (tw_check_errors(tw_dev)) {
-					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", j);
 					tries++;
 					continue;
 				}
@@ -883,7 +902,7 @@
 			}
 
 			if (tries >= TW_MAX_RESET_TRIES) {
-				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -894,7 +913,7 @@
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
 				       (tw_dev->tw_pci_dev->resource[0].start), 
 				       (tw_dev->tw_pci_dev->resource[0].start) + 
-				       TW_IO_ADDRESS_RANGE, numcards);
+				       TW_IO_ADDRESS_RANGE, j);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -904,7 +923,7 @@
 			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
 			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -913,13 +932,16 @@
 
 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
 			}
 
+			/* Set card status as online */
+			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)) {
@@ -938,7 +960,7 @@
 		/* Register the card with the kernel SCSI layer */
 			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
 			if (host == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", j);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -980,7 +1002,7 @@
 				tw_device_extension_count = numcards;
 				tw_dev2->host = host;
 			} else { 
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", j);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
@@ -989,12 +1011,21 @@
 			}
 
 			/* Tell the firmware we support shutdown notification*/
-			tw_setfeature(tw_dev2, 2, 1, &c);
+			error = tw_setfeature(tw_dev2, 2, 1, &c);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				numcards--;
+				continue;
+			}
 
 			/* Now setup the interrupt handler */
 			error = tw_setup_irq(tw_dev2);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", j);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 
@@ -1029,16 +1060,16 @@
 	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]) 
-			kfree(tw_dev->command_packet_virtual_address[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->alignment_virtual_address[i])
-			kfree(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]);
 
 	}
 	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
 		if (tw_dev->bounce_buffer[i])
-			kfree(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]);
 	}
 } /* End tw_free_device_extension() */
 
@@ -1048,8 +1079,11 @@
 	int i;
 
 	for (i=0;i<tw_device_extension_count;i++) {
-		printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i);
-		tw_shutdown_device(tw_device_extension_list[i]);
+		if (tw_device_extension_list[i]->online == 1) {
+			printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i);
+			tw_shutdown_device(tw_device_extension_list[i]);
+			tw_device_extension_list[i]->online = 0;
+		}
 	}
 	unregister_reboot_notifier(&tw_notifier);
 
@@ -1059,18 +1093,15 @@
 /* This function will send an initconnection command to controller */
 int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) 
 {
-	u32 command_que_addr, command_que_value;
-	u32 status_reg_addr, status_reg_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
 	TW_Command  *command_packet;
 	TW_Response_Queue response_queue;
 	int request_id = 0;
-	int i = 0;
-	int imax = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	/* Initialize InitConnection command packet */
@@ -1102,29 +1133,18 @@
 	outl(command_que_value, command_que_addr);
     
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for (i=0;i<imax;i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			break;	/* Response was okay, so we exit */
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
 	}
 	return 0;
@@ -1133,27 +1153,25 @@
 /* This function will initialize the fields of a device extension */
 int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i;
+	int i, error = 0;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
 
-	for (i=0;i<TW_Q_LENGTH;i++) {
-		/* Initialize command packet buffers */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
-		if (tw_dev->command_packet_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
-    
-		/* Initialize generic buffer */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
-		if (tw_dev->alignment_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
+	/* Initialize command packet buffers */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
+		return 1;
+	}
 
+	/* Initialize generic buffer */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
+		return 1;
+	}
+	
+	for (i=0;i<TW_Q_LENGTH;i++) {
 		tw_dev->free_queue[i] = i;
 		tw_dev->state[i] = TW_S_INITIAL;
 	}
@@ -1168,22 +1186,21 @@
 /* This function will get unit info from the controller */
 int tw_initialize_units(TW_Device_Extension *tw_dev) 
 {
-	int found = 0;
+	int found = 0, error = 0;
 	unsigned char request_id = 0;
 	TW_Command *command_packet;
 	TW_Param *param;
 	int i, j, imax, num_units = 0, num_raid_five = 0;
-	u32 status_reg_addr, status_reg_value;
-	u32 command_que_addr, command_que_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
 	TW_Response_Queue response_queue;
-	u32 param_value;
+	unsigned long param_value;
 	unsigned char *is_unit_present;
 	unsigned char *raid_level;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
 
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	command_que_addr = tw_dev->registers.command_que_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
   
@@ -1232,31 +1249,20 @@
 	outl(command_que_value, command_que_addr);
 
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for(i=0; i<imax; i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			found = 1;
-			break;
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
+		found = 1;
 	}
 	if (found == 0) {
 		/* response never received */
@@ -1335,31 +1341,20 @@
 		outl(command_que_value, command_que_addr);
 
 		/* Poll for completion */
-		imax = TW_POLL_MAX_RETRIES;
-		for(i=0; i<imax; i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value, 0);
+		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+			response_queue.value = inl(response_que_addr);
+			request_id = (unsigned char)response_queue.u.response_id;
+			if (request_id != 0) {
+				/* unexpected request id */
+				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
 				return 1;
 			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-				if (request_id != 0) {
-					/* unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-					return 1;
-				}
-				if (command_packet->status != 0) {
-					/* bad response */
-					tw_decode_sense(tw_dev, request_id, 0);
-					return 1;
-				}
-				found = 1;
-				break;
+			if (command_packet->status != 0) {
+				/* bad response */
+				tw_decode_sense(tw_dev, request_id, 0);
+				return 1;
 			}
+			found = 1;
 		}
 		if (found == 0) {
 			/* response never received */
@@ -1379,13 +1374,10 @@
 
 	/* Now allocate raid5 bounce buffers */
 	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, 2);
-			if (tw_dev->bounce_buffer[i] == NULL) {
-				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
-				return 1;
-			}
-			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS);
+		error = tw_allocate_memory(tw_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, 2);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
+			return 1;
 		}
 	}
   
@@ -1540,6 +1532,13 @@
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
 						error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
 						break;
+					case MODE_SENSE:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
+						error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
+						break;
+					case SYNCHRONIZE_CACHE:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
+						break;
 					case TW_IOCTL:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n");
 						error = tw_ioctl_complete(tw_dev, request_id);
@@ -1566,6 +1565,7 @@
 						tw_state_request_finish(tw_dev, request_id);
 						tw_dev->posted_request_count--;
 						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
 					}
 				}
 
@@ -1596,12 +1596,13 @@
 	int bufflen, error = 0;
 	TW_Param *param;
 	TW_Command *command_packet, *command_save;
-	u32 param_value;
+	unsigned long param_value;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
 	int tw_aen_code, i, use_sg;
-	char *data_ptr;
+	unsigned long *data_ptr;
 	int total_bytes = 0, posted = 0;
+	dma_addr_t dma_handle;
 	struct timeval before, timeout;
 
 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
@@ -1706,10 +1707,10 @@
 			passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id];
 			passthru->sg_list[0].length = passthru->sector_count*512;
 			if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
 				return 1;
 			}
-			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
+			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			tw_post_command_packet(tw_dev, request_id);
 			return 0;
 		case TW_CMD_PACKET:
@@ -1741,17 +1742,18 @@
 					use_sg = command_packet->size - 3;
 					for (i=0;i<use_sg;i++)
 						total_bytes+=command_packet->byte8.param.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC);
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
 					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
 						return 1;
 					}
 
 					/* Copy param sglist into the kernel */
 					data_ptr = tw_dev->ioctl_data[request_id];
 					for (i=0;i<use_sg;i++) {
-						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
-							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
+						if (command_packet->byte8.param.sgl[i].address != 0) {
+							error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
 							if (error) {
 								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
 								goto tw_ioctl_bail;
@@ -1764,24 +1766,25 @@
 						data_ptr+=command_packet->byte8.param.sgl[i].length;
 					}
 					command_packet->size = 4;
-					command_packet->byte8.param.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]);
+					command_packet->byte8.param.sgl[0].address = dma_handle;
 					command_packet->byte8.param.sgl[0].length = total_bytes;
 				}
 				if (command_packet->byte0.sgl_offset == 3) {
 					use_sg = command_packet->size - 4;
 					for (i=0;i<use_sg;i++)
 						total_bytes+=command_packet->byte8.io.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = kmalloc(total_bytes, GFP_ATOMIC);
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
 					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
 						return 1;
 					}
 					if (command_packet->byte0.opcode == TW_OP_WRITE) {
 						/* Copy io sglist into the kernel */
 						data_ptr = tw_dev->ioctl_data[request_id];
 						for (i=0;i<use_sg;i++) {
-							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
-								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
+							if (command_packet->byte8.io.sgl[i].address != 0) {
+								error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
 								if (error) {
 									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
 									goto tw_ioctl_bail;
@@ -1795,7 +1798,7 @@
 						}
 					}
 					command_packet->size = 5;
-					command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->ioctl_data[request_id]);
+					command_packet->byte8.io.sgl[0].address = dma_handle;
 					command_packet->byte8.io.sgl[0].length = total_bytes;
 				}
 
@@ -1835,10 +1838,10 @@
 				/* Now copy up the param or io sglist to userspace */
 				if (command_packet->byte0.sgl_offset == 2) {
 					use_sg = command_save->size - 3;
-					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
+					data_ptr = tw_dev->ioctl_data[request_id];
 					for (i=0;i<use_sg;i++) {
-						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
-							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
+						if (command_save->byte8.param.sgl[i].address != 0) {
+							error = copy_to_user((void *)(unsigned long)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
 							if (error) {
 								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
 								goto tw_ioctl_bail;
@@ -1855,10 +1858,10 @@
 				if (command_packet->byte0.sgl_offset == 3) {
 					use_sg = command_save->size - 4;
 					if (command_packet->byte0.opcode == TW_OP_READ) {
-						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
+						data_ptr = tw_dev->ioctl_data[request_id];
 						for(i=0;i<use_sg;i++) {
-							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
-								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
+							if (command_save->byte8.io.sgl[i].address != 0) {
+								error = copy_to_user((void *)(unsigned long)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
 								if (error) {
 									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
 									goto tw_ioctl_bail;
@@ -1878,7 +1881,7 @@
 
 				/* Free up sglist memory */
 				if (tw_dev->ioctl_data[request_id])
-					kfree(tw_dev->ioctl_data[request_id]);
+					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
 				else
 					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
 				
@@ -1977,6 +1980,55 @@
 	return 0;
 } /* End tw_ioctl_complete() */
 
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+	
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+
+	if (use_sg == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = use_sg;
+
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+	
+	if (cmd->request_bufflen == 0)
+		return 0;
+#ifdef BLK_BOUNCE_HIGH
+	mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), ((unsigned long)cmd->request_buffer & ~PAGE_MASK), cmd->request_bufflen, dma_dir);
+#else
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
+#endif
+
+	if (mapping == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = 1;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
 /* This function will mask the command interrupt */
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -2020,11 +2072,45 @@
 	return 0;
 } /* End tw_poll_status() */
 
+/* This function will poll the status register for disappearance of a flag */
+int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+        u32 status_reg_addr, status_reg_value;
+        struct timeval before, timeout;
+
+        status_reg_addr = tw_dev->registers.status_reg_addr;
+        do_gettimeofday(&before);
+        status_reg_value = inl(status_reg_addr);
+
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+	}
+
+        while ((status_reg_value & flag) != 0) {
+                status_reg_value = inl(status_reg_addr);
+
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value, 0);
+		}
+
+                do_gettimeofday(&timeout);
+                if (before.tv_sec + seconds < timeout.tv_sec) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n", flag);
+                        return 1;
+                }
+                mdelay(5);
+        }
+        return 0;
+} /* End tw_poll_status_gone() */
+
 /* This function will attempt to post a command packet to the board */
 int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
 {
 	u32 status_reg_addr, status_reg_value;
-	u32 command_que_addr, command_que_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
 	command_que_addr = tw_dev->registers.command_que_addr;
@@ -2090,6 +2176,7 @@
 			if (srb != NULL) {
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
 			}
 		}
 	}
@@ -2233,14 +2320,14 @@
 	for (i=0;i<TW_Q_LENGTH;i++) {
 		if (tw_dev->srb[i] == SCpnt) {
 			if (tw_dev->state[i] == TW_S_STARTED) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				tw_dev->state[i] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, i);
 				spin_unlock(&tw_dev->tw_lock);
 				return (SUCCESS);
 			}
 			if (tw_dev->state[i] == TW_S_PENDING) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				if (tw_dev->pending_head == TW_Q_LENGTH-1) {
 					tw_dev->pending_head = TW_Q_START;
 				} else {
@@ -2254,7 +2341,7 @@
 			}
 			if (tw_dev->state[i] == TW_S_POSTED) {
 				/* If the command has already been posted, we have to reset the card */
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt);
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt);
 				/* We have to let AEN requests through before the reset */
 				spin_unlock(&tw_dev->tw_lock);
 				spin_unlock_irq(&io_request_lock);
@@ -2347,9 +2434,9 @@
 					printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j);
 					printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode);
 					printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count);
-					printk(KERN_INFO "LBA: 0x%x\n", (u32)command->byte8.io.lba);
-					printk(KERN_INFO "Physical command packet addr: 0x%x\n", tw_dev->command_packet_physical_address[j]);
-					printk(KERN_INFO "Scsi_Cmnd: 0x%x\n", (u32)tw_dev->srb[j]);
+					printk(KERN_INFO "LBA: 0x%x\n", command->byte8.io.lba);
+					printk(KERN_INFO "Physical command packet addr: 0x%lx\n", tw_dev->command_packet_physical_address[j]);
+					printk(KERN_INFO "Scsi_Cmnd: %p\n", tw_dev->srb[j]);
 				}
 			}
 			printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head);
@@ -2442,6 +2529,14 @@
 		        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
 		        error = tw_scsiop_request_sense(tw_dev, request_id);
 		        break;
+		case MODE_SENSE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n");
+			error = tw_scsiop_mode_sense(tw_dev, request_id);
+			break;
+		case SYNCHRONIZE_CACHE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n");
+			error = tw_scsiop_synchronize_cache(tw_dev, request_id);
+			break;
 		case TW_IOCTL:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
 			error = tw_ioctl(tw_dev, request_id);
@@ -2497,8 +2592,9 @@
 {
 	TW_Param *param;
 	TW_Command *command_packet;
-	u32 command_que_value, command_que_addr;
-	u32 param_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
 
@@ -2596,13 +2692,115 @@
 	return 0;
 } /* End tw_scsiop_inquiry_complete() */
 
+/* This function handles scsi mode_sense commands */
+int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
+
+	/* Only page control = 0, page code = 0x8 (cache page) supported */
+	if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		tw_dev->srb[request_id]->result = (DID_OK << 16);
+		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+		return 0;
+	}
+
+	/* Now read firmware cache setting for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_GET_PARAM;
+	command_packet->byte0.sgl_offset = 2;
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = 0;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
+		return 1;
+	}
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->target;
+	param->parameter_id = 7; /* unit flags */
+	param->parameter_size_bytes = 1;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_mode_sense() */
+
+/* This function is called by the isr to complete a mode sense command */
+int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	unsigned char *flags;
+	unsigned char *request_buffer;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	flags = (char *)&(param->data[0]);
+	request_buffer = tw_dev->srb[request_id]->buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+
+	request_buffer[0] = 0xf;        /* mode data length */
+	request_buffer[1] = 0;          /* default medium type */
+	request_buffer[2] = 0x10;       /* dpo/fua support on */
+	request_buffer[3] = 0;          /* no block descriptors */
+	request_buffer[4] = 0x8;        /* caching page */
+	request_buffer[5] = 0xa;        /* page length */
+	if (*flags & 0x1)
+		request_buffer[6] = 0x4;        /* WCE on */
+	else
+		request_buffer[6] = 0x0;        /* WCE off */
+
+	return 0;
+} /* End tw_scsiop_mode_sense_complete() */
+
 /* This function handles scsi read_capacity commands */
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
 {
 	TW_Param *param;
 	TW_Command *command_packet;
-	u32 command_que_addr, command_que_value;
-	u32 param_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
 
@@ -2706,9 +2904,10 @@
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
 {
 	TW_Command *command_packet;
-	u32 command_que_addr, command_que_value = 0;
-	u32 lba = 0x0, num_sectors = 0x0;
-	int i, count = 0;
+	unsigned long command_que_value;
+	u32 command_que_addr = 0x0;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg, count = 0;
 	Scsi_Cmnd *srb;
 	struct scatterlist *sglist;
 
@@ -2769,16 +2968,24 @@
 		/* Do this if there are no sg list entries */
 		if (tw_dev->srb[request_id]->use_sg == 0) {    
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+			buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (buffaddr == 0)
+				return 1;
+
+			command_packet->byte8.io.sgl[0].address = buffaddr;
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
 			command_packet->size+=2;
 		}
 
 		/* Do this if we have multiple sg list entries */
 		if (tw_dev->srb[request_id]->use_sg > 0) {
-			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-				command_packet->byte8.io.sgl[i].length = sglist[i].length;
+			use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (use_sg == 0)
+				return 1;
+
+			for (i=0;i<use_sg; i++) {
+				command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+				command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
 				command_packet->size+=2;
 			}
 		}
@@ -2787,7 +2994,7 @@
                 if (tw_dev->srb[request_id]->use_sg == 0) {
 			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
 			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+			command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
 			command_packet->size+=2;
                 }
@@ -2799,7 +3006,7 @@
                                 memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
 				count+=sglist[i].length;
                         }
-                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+                        command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
                         command_packet->byte8.io.sgl[0].length = count;
                         command_packet->size = 5; /* single sgl */
                 }
@@ -2840,6 +3047,44 @@
 	return 0;
 } /* End tw_scsiop_request_sense() */
 
+/* This function will handle synchronize cache scsi command */
+int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
+
+	/* Send firmware flush command for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_FLUSH_CACHE;
+	command_packet->byte0.sgl_offset = 0;
+	command_packet->size = 2;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = tw_dev->srb[request_id]->target;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_synchronize_cache() */
+
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
@@ -2862,11 +3107,10 @@
 	TW_Command  *command_packet;
 	TW_Response_Queue response_queue;
 	int request_id = 0;
-	u32 command_que_value, command_que_addr;
-	u32 status_reg_addr, status_reg_value;
+	unsigned long command_que_value;
+	u32 command_que_addr;
 	u32 response_que_addr;
-	u32 param_value;
-	int imax, i;
+	unsigned long param_value;
 
   	/* Initialize SetParam command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -2905,40 +3149,28 @@
 	return 1;
 	}
 	command_que_addr = tw_dev->registers.command_que_addr;
-	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;
 
 	/* Send command packet to the board */
 	outl(command_que_value, command_que_addr);
 
 	/* Poll for completion */
-	imax = TW_POLL_MAX_RETRIES;
-	for (i=0;i<imax;i++) {
-		mdelay(5);
-		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 1);
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(response_que_addr);
+		request_id = (unsigned char)response_queue.u.response_id;
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
 			return 1;
 		}
-		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-			response_queue.value = inl(response_que_addr);
-			request_id = (unsigned char)response_queue.u.response_id;
-			if (request_id != 0) {
-				/* unexpected request id */
-				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
-				return 1;
-			}
-			if (command_packet->status != 0) {
-				/* bad response */
-				tw_decode_sense(tw_dev, request_id, 0);
-				return 1;
-			}
-			break; /* Response was okay, so we exit */
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
 		}
 	}
 
-  return 0;
+	return 0;
 } /* End tw_setfeature() */
 
 /* This function will setup the interrupt handler */
@@ -3042,6 +3274,26 @@
 	return 0;
 } /* End tw_state_request_start() */
 
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	
+	dprintk(KERN_WARNING "3w-xxxx: tw_unamp_scsi_data()\n");
+	
+	switch(cmd->SCp.phase) {
+		case 1:
+#ifdef BLK_BOUNCE_HIGH
+			pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+#else
+			pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+#endif
+			break;
+		case 2:
+			pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+			break;
+	}
+} /* End tw_unmap_scsi_data() */
+
 /* This function will unmask the command interrupt on the controller */
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
 {
diff -urN linux-2.4.20-pre11/drivers/scsi/3w-xxxx.h linux-2.4.20-rc1/drivers/scsi/3w-xxxx.h
--- linux-2.4.20-pre11/drivers/scsi/3w-xxxx.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/scsi/3w-xxxx.h	Tue Oct 29 08:35:32 2002
@@ -165,7 +165,7 @@
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
 
 /* PCI related defines */
-#define TW_IO_ADDRESS_RANGE		       0xD
+#define TW_IO_ADDRESS_RANGE		       0x10
 #define TW_DEVICE_NAME			       "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)	/* 3ware */
 #define TW_DEVICE_ID (0x1000)	/* Storage Controller */
@@ -184,6 +184,7 @@
 #define TW_OP_SET_PARAM	      0x13
 #define TW_OP_SECTOR_INFO     0x1a
 #define TW_OP_AEN_LISTEN      0x1c
+#define TW_OP_FLUSH_CACHE     0x0e
 #define TW_CMD_PACKET         0x1d
 #define TW_ATA_PASSTHRU       0x1e
 #define TW_CMD_PACKET_WITH_DATA 0x1f
@@ -223,7 +224,6 @@
 #define TW_MAX_CMDS_PER_LUN		      255
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
-#define TW_MAX_AEN_TRIES                      100
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
 #define TW_IN_IOCTL                           2
@@ -252,8 +252,8 @@
 
 /* Scatter Gather List Entry */
 typedef struct TAG_TW_SG_Entry {
-	unsigned long address;
-	unsigned long length;
+	u32 address;
+	u32 length;
 } TW_SG_Entry;
 
 typedef unsigned char TW_Sector[512];
@@ -281,17 +281,17 @@
 	} byte6;
 	union {
 		struct {
-			unsigned long lba;
+			u32 lba;
 			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
-			unsigned long padding;	/* pad to 512 bytes */
+			u32 padding;	/* pad to 512 bytes */
 		} io;
 		struct {
 			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
-			unsigned long padding[2];
+			u32 padding[2];
 		} param;
 		struct {
-			unsigned long response_queue_pointer;
-			unsigned long padding[125];
+			u32 response_queue_pointer;
+			u32 padding[125];
 		} init_connection;
 		struct {
 			char version[504];
@@ -383,15 +383,16 @@
 
 typedef struct TAG_TW_Device_Extension {
 	TW_Registers		registers;
-	u32			*alignment_virtual_address[TW_Q_LENGTH];
-	u32			alignment_physical_address[TW_Q_LENGTH];
-	u32			*bounce_buffer[TW_Q_LENGTH];
+	unsigned long		*alignment_virtual_address[TW_Q_LENGTH];
+	unsigned long		alignment_physical_address[TW_Q_LENGTH];
+	unsigned long		*bounce_buffer[TW_Q_LENGTH];
+	unsigned long		bounce_buffer_phys[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
 	int			is_raid_five[TW_MAX_UNITS];
 	int			num_units;
 	int			num_raid_five;
-	u32			*command_packet_virtual_address[TW_Q_LENGTH];
-	u32			command_packet_physical_address[TW_Q_LENGTH];
+	unsigned long		*command_packet_virtual_address[TW_Q_LENGTH];
+	unsigned long		command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
 	Scsi_Cmnd		*srb[TW_Q_LENGTH];
 	unsigned char		free_queue[TW_Q_LENGTH];
@@ -421,15 +422,16 @@
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
 	volatile long		flags; /* long req'd for set_bit --RR */
-	char			*ioctl_data[TW_Q_LENGTH];
+	unsigned long		*ioctl_data[TW_Q_LENGTH];
 	int			reset_print;
+	char                    online;
 } TW_Device_Extension;
 
 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
 int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
 void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
@@ -450,6 +452,7 @@
 int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id);
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev);
 int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
 int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id);
 int tw_reset_device_extension(TW_Device_Extension *tw_dev);
 int tw_reset_sequence(TW_Device_Extension *tw_dev);
@@ -462,10 +465,13 @@
 int tw_scsi_release(struct Scsi_Host *tw_host);
 int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
+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_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
@@ -477,6 +483,40 @@
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
 
 /* Scsi_Host_Template Initializer */
+#ifdef BLK_BOUNCE_HIGH
+#define TWXXXX {					\
+	next : NULL,					\
+	module : NULL,					\
+	proc_name : "3w-xxxx",				\
+	proc_info : tw_scsi_proc_info,			\
+	name : "3ware Storage Controller",		\
+	detect : tw_scsi_detect,			\
+	release : tw_scsi_release,			\
+	info : NULL,					\
+	ioctl : NULL,                  			\
+	command : NULL,					\
+	queuecommand : tw_scsi_queue,			\
+	eh_strategy_handler : NULL,			\
+	eh_abort_handler : tw_scsi_eh_abort,		\
+	eh_device_reset_handler : NULL,			\
+	eh_bus_reset_handler : NULL,			\
+	eh_host_reset_handler : tw_scsi_eh_reset,	\
+	abort : NULL,					\
+	reset : NULL,					\
+	slave_attach : NULL,				\
+	bios_param : tw_scsi_biosparam,			\
+	can_queue : TW_Q_LENGTH-1,			\
+	this_id: -1,					\
+	sg_tablesize : TW_MAX_SGL_LENGTH,		\
+	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
+	present : 0,					\
+	unchecked_isa_dma : 0,				\
+	use_clustering : ENABLE_CLUSTERING,		\
+ 	use_new_eh_code : 1,				\
+	emulated : 1,					\
+	highmem_io : 1					\
+}
+#else
 #define TWXXXX {					\
 	next : NULL,					\
 	module : NULL,					\
@@ -508,4 +548,5 @@
  	use_new_eh_code : 1,				\
 	emulated : 1					\
 }
+#endif /* BLK_BOUNCE_HIGH */
 #endif /* _3W_XXXX_H */
diff -urN linux-2.4.20-pre11/drivers/scsi/esp.h linux-2.4.20-rc1/drivers/scsi/esp.h
--- linux-2.4.20-pre11/drivers/scsi/esp.h	Mon Sep 18 13:40:17 2000
+++ linux-2.4.20-rc1/drivers/scsi/esp.h	Tue Oct 29 08:35:34 2002
@@ -8,6 +8,8 @@
 #ifndef _SPARC_ESP_H
 #define _SPARC_ESP_H
 
+#include <linux/config.h>
+
 /* For dvma controller register definitions. */
 #include <asm/dma.h>
 
@@ -400,6 +402,28 @@
 			 int hostno, int inout);
 extern int esp_revoke(Scsi_Device* SDptr);
 
+#ifdef CONFIG_SPARC64
+#define SCSI_SPARC_ESP {                                        \
+		proc_name:      "esp",				\
+		proc_info:      &esp_proc_info,			\
+		name:           "Sun ESP 100/100a/200",		\
+		detect:         esp_detect,			\
+		revoke:		esp_revoke,			\
+		info:           esp_info,			\
+		command:        esp_command,			\
+		queuecommand:   esp_queue,			\
+		abort:          esp_abort,			\
+		reset:          esp_reset,			\
+		can_queue:      7,				\
+		this_id:        7,				\
+		sg_tablesize:   SG_ALL,				\
+		cmd_per_lun:    1,				\
+		use_clustering: ENABLE_CLUSTERING,		\
+		use_new_eh_code: 0,				\
+		highmem_io:	1				\
+}
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
 #define SCSI_SPARC_ESP {                                        \
 		proc_name:      "esp",				\
 		proc_info:      &esp_proc_info,			\
@@ -416,8 +440,8 @@
 		sg_tablesize:   SG_ALL,				\
 		cmd_per_lun:    1,				\
 		use_clustering: ENABLE_CLUSTERING,		\
-		use_new_eh_code: 0				\
 }
+#endif
 
 /* For our interrupt engine. */
 #define for_each_esp(esp) \
diff -urN linux-2.4.20-pre11/drivers/scsi/qlogicpti.h linux-2.4.20-rc1/drivers/scsi/qlogicpti.h
--- linux-2.4.20-pre11/drivers/scsi/qlogicpti.h	Mon Dec 20 22:06:42 1999
+++ linux-2.4.20-rc1/drivers/scsi/qlogicpti.h	Tue Oct 29 08:35:34 2002
@@ -6,6 +6,8 @@
 #ifndef _QLOGICPTI_H
 #define _QLOGICPTI_H
 
+#include <linux/config.h>
+
 /* Qlogic/SBUS controller registers. */
 #define SBUS_CFG1	0x006UL
 #define SBUS_CTRL	0x008UL
@@ -512,6 +514,7 @@
 #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
 #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
 
+#ifdef CONFIG_SPARC64
 #define QLOGICPTI {						   \
 	detect:		qlogicpti_detect,			   \
 	release:	qlogicpti_release,			   \
@@ -524,8 +527,25 @@
 	sg_tablesize:	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
 	cmd_per_lun:	1,					   \
 	use_clustering:	ENABLE_CLUSTERING,			   \
-	use_new_eh_code: 0					   \
+	use_new_eh_code: 0,					   \
+	highmem_io:	1					   \
 }
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#define QLOGICPTI {						   \
+	detect:		qlogicpti_detect,			   \
+	release:	qlogicpti_release,			   \
+	info:		qlogicpti_info,				   \
+	queuecommand:	qlogicpti_queuecommand_slow,		   \
+	abort:		qlogicpti_abort,			   \
+	reset:		qlogicpti_reset,			   \
+	can_queue:	QLOGICPTI_REQ_QUEUE_LEN,		   \
+	this_id:	7,					   \
+	sg_tablesize:	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
+	cmd_per_lun:	1,					   \
+	use_clustering:	ENABLE_CLUSTERING,			   \
+}
+#endif
 
 /* For our interrupt engine. */
 #define for_each_qlogicpti(qp) \
diff -urN linux-2.4.20-pre11/drivers/scsi/sr_ioctl.c linux-2.4.20-rc1/drivers/scsi/sr_ioctl.c
--- linux-2.4.20-pre11/drivers/scsi/sr_ioctl.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc1/drivers/scsi/sr_ioctl.c	Tue Oct 29 08:35:37 2002
@@ -158,13 +158,11 @@
 			if (!quiet)
 				printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
 				       "REQUEST.\n", target);
+			err = -EIO;
 			if (SRpnt->sr_sense_buffer[12] == 0x20 &&
-			    SRpnt->sr_sense_buffer[13] == 0x00) {
+			    SRpnt->sr_sense_buffer[13] == 0x00)
 				/* sense: Invalid command operation code */
 				err = -EDRIVE_CANT_DO_THIS;
-			} else {
-				err = -EINVAL;
-			}
 #ifdef DEBUG
 			print_command(sr_cmd);
 			print_req_sense("sr", SRpnt);
diff -urN linux-2.4.20-pre11/drivers/zorro/zorro.ids linux-2.4.20-rc1/drivers/zorro/zorro.ids
--- linux-2.4.20-pre11/drivers/zorro/zorro.ids	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/drivers/zorro/zorro.ids	Tue Oct 29 08:35:56 2002
@@ -4,7 +4,7 @@
 #	Maintained by Geert Uytterhoeven <zorro@linux-m68k.org>
 #	If you have any new entries, please send them to the maintainer.
 #
-#	$Id: zorro.ids,v 1.17 2001/10/25 08:21:39 geert Exp $
+#	$Id: zorro.ids,v 1.19 2002/10/14 13:08:58 geert Exp $
 #
 
 # Manufacturers and Products. Please keep sorted.
@@ -364,7 +364,13 @@
 	1300  Warp Engine 40xx [Accelerator, SCSI Host Adapter and RAM Expansion]
 089e  ElBox Computer
 	0600  1200/4 [RAM Expansion]
-	1900  PowerFlyer [IDE Interface]
+	0800  FastATA 1200 [IDE Interface]
+	1200  FastATA 1200 [IDE Interface]
+	1300  FastATA 1200 [IDE Interface]
+	1800  FastATA 1200 [IDE Interface]
+	1900  FastATA 4000 [IDE Interface]
+	1d00  FastATA 4000 [IDE Interface]
+	1e00  FastATA ZIV [IDE Interface]
 0a00  Harms Professional
 	1000  030 Plus [Accelerator]
 	d000  3500 Professional [Accelerator and RAM Expansion]
diff -urN linux-2.4.20-pre11/fs/jffs2/Makefile linux-2.4.20-rc1/fs/jffs2/Makefile
--- linux-2.4.20-pre11/fs/jffs2/Makefile	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/fs/jffs2/Makefile	Tue Oct 29 08:35:56 2002
@@ -1,7 +1,7 @@
 #
 # Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
 #
-# $Id: Makefile,v 1.25 2001/09/25 20:59:41 dwmw2 Exp $
+# $Id: Makefile,v 1.25.2.1 2002/10/11 09:04:44 dwmw2 Exp $
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -urN linux-2.4.20-pre11/fs/jffs2/compr_zlib.c linux-2.4.20-rc1/fs/jffs2/compr_zlib.c
--- linux-2.4.20-pre11/fs/jffs2/compr_zlib.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/fs/jffs2/compr_zlib.c	Tue Oct 29 08:35:56 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: compr_zlib.c,v 1.15 2002/03/04 09:35:48 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.8.2.1 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
@@ -65,28 +65,28 @@
 {
 	deflate_workspace = vmalloc(zlib_deflate_workspacesize());
 	if (!deflate_workspace) {
-		printk("Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
+		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
 		return -ENOMEM;
 	}
-	D1(printk("Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
+	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
 	inflate_workspace = vmalloc(zlib_inflate_workspacesize());
 	if (!inflate_workspace) {
-		printk("Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
+		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
 		vfree(deflate_workspace);
 		return -ENOMEM;
 	}
-	D1(printk("Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
+	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
 	return 0;
 }
 
-void __exit jffs2_zlib_exit(void)
+void jffs2_zlib_exit(void)
 {
 	vfree(deflate_workspace);
 	vfree(inflate_workspace);
 }
 
 int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-		   uint32_t *sourcelen, uint32_t *dstlen)
+		   __u32 *sourcelen, __u32 *dstlen)
 {
 	z_stream strm;
 	int ret;
@@ -146,7 +146,7 @@
 }
 
 void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-		      uint32_t srclen, uint32_t destlen)
+		      __u32 srclen, __u32 destlen)
 {
 	z_stream strm;
 	int ret;
diff -urN linux-2.4.20-pre11/fs/jffs2/nodelist.h linux-2.4.20-rc1/fs/jffs2/nodelist.h
--- linux-2.4.20-pre11/fs/jffs2/nodelist.h	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/fs/jffs2/nodelist.h	Tue Oct 29 08:35:56 2002
@@ -31,8 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.h,v 1.46.2.2 2002/05/27 09:27:50 dwmw2 Exp $
- * + zlib_init calls from v1.65
+ * $Id: nodelist.h,v 1.46.2.3 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
diff -urN linux-2.4.20-pre11/fs/jffs2/super.c linux-2.4.20-rc1/fs/jffs2/super.c
--- linux-2.4.20-pre11/fs/jffs2/super.c	Tue Oct 29 08:34:26 2002
+++ linux-2.4.20-rc1/fs/jffs2/super.c	Tue Oct 29 08:35:56 2002
@@ -31,8 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: super.c,v 1.48.2.2 2002/03/12 15:36:43 dwmw2 Exp $
- * + zlib_init calls from v1.56
+ * $Id: super.c,v 1.48.2.3 2002/10/11 09:04:44 dwmw2 Exp $
  *
  */
 
@@ -365,18 +364,25 @@
 	ret = jffs2_zlib_init();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
-		return ret;
+		goto out;
 	}
 	ret = jffs2_create_slab_caches();
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-		return ret;
+		goto out_zlib;
 	}
 	ret = register_filesystem(&jffs2_fs_type);
 	if (ret) {
 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
-		jffs2_destroy_slab_caches();
+		goto out_slab;
 	}
+	return 0;
+
+ out_slab:
+	jffs2_destroy_slab_caches();
+ out_zlib:
+	jffs2_zlib_exit();
+ out:
 	return ret;
 }
 
diff -urN linux-2.4.20-pre11/fs/jfs/xattr.c linux-2.4.20-rc1/fs/jfs/xattr.c
--- linux-2.4.20-pre11/fs/jfs/xattr.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/fs/jfs/xattr.c	Tue Oct 29 08:35:57 2002
@@ -303,7 +303,7 @@
 	}
 
 	ea->flag = DXD_EXTENT;
-	DXDsize(ea, ealist->size);
+	DXDsize(ea, le32_to_cpu(ealist->size));
 	DXDlength(ea, nblocks);
 	DXDaddress(ea, blkno);
 
@@ -342,7 +342,8 @@
 	/* Sanity Check */
 	if ((sizeDXD(&ji->ea) > sizeof (ji->i_inline_ea)))
 		return -EIO;
-	if (((struct jfs_ea_list *) &ji->i_inline_ea)->size != ea_size)
+	if (le32_to_cpu(((struct jfs_ea_list *) &ji->i_inline_ea)->size)
+	    != ea_size)
 		return -EIO;
 
 	memcpy(ealist, ji->i_inline_ea, ea_size);
diff -urN linux-2.4.20-pre11/fs/nfs/dir.c linux-2.4.20-rc1/fs/nfs/dir.c
--- linux-2.4.20-pre11/fs/nfs/dir.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/fs/nfs/dir.c	Tue Oct 29 08:35:57 2002
@@ -127,7 +127,6 @@
 	return 0;
  error:
 	SetPageError(page);
-	kunmap(page);
 	UnlockPage(page);
 	invalidate_inode_pages(inode);
 	desc->error = error;
diff -urN linux-2.4.20-pre11/fs/nfsd/nfsproc.c linux-2.4.20-rc1/fs/nfsd/nfsproc.c
--- linux-2.4.20-pre11/fs/nfsd/nfsproc.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/fs/nfsd/nfsproc.c	Tue Oct 29 08:35:57 2002
@@ -264,11 +264,11 @@
 					/* this is probably a permission check..
 					 * at least IRIX implements perm checking on
 					 *   echo thing > device-special-file-or-pipe
-					 * by does a CREATE with type==0
+					 * by doing a CREATE with type==0
 					 */
 					nfserr = nfsd_permission(newfhp->fh_export,
 								 newfhp->fh_dentry,
-								 MAY_WRITE);
+								 MAY_WRITE|_NFSD_IRIX_BOGOSITY);
 					if (nfserr && nfserr != nfserr_rofs)
 						goto out_unlock;
 				}
diff -urN linux-2.4.20-pre11/fs/nfsd/vfs.c linux-2.4.20-rc1/fs/nfsd/vfs.c
--- linux-2.4.20-pre11/fs/nfsd/vfs.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/fs/nfsd/vfs.c	Tue Oct 29 08:35:57 2002
@@ -1493,17 +1493,21 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 
-	/* only care about readonly exports for files and
-	 * directories. links don't have meaningful write access,
-	 * and all else is local to the client
-	 */
-	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) 
-		if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
-			if (EX_RDONLY(exp) || IS_RDONLY(inode))
-				return nfserr_rofs;
-			if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
-				return nfserr_perm;
-		}
+	/* The following code is here to make IRIX happy, which
+	 * does a permission check every time a user does
+	 *	echo yaddayadda > special-file
+	 * by sending a CREATE request.
+	 * The original code would check read-only export status
+	 * only for regular files and directories, allowing
+	 * clients to chown/chmod device files and fifos even
+	 * on volumes exported read-only. */
+	if (!(acc & _NFSD_IRIX_BOGOSITY)
+	 && (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC))) {
+		if (EX_RDONLY(exp) || IS_RDONLY(inode))
+			return nfserr_rofs;
+		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
+			return nfserr_perm;
+	}
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
 		return nfserr_perm;
 
diff -urN linux-2.4.20-pre11/include/asm-i386/smpboot.h linux-2.4.20-rc1/include/asm-i386/smpboot.h
--- linux-2.4.20-pre11/include/asm-i386/smpboot.h	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/include/asm-i386/smpboot.h	Tue Oct 29 08:35:59 2002
@@ -26,16 +26,20 @@
 	}
 	return cpu_online_map;
 }
+#ifdef CONFIG_X86_IO_APIC
 extern unsigned char int_delivery_mode;
 extern unsigned int int_dest_addr_mode;
 #define	INT_DEST_ADDR_MODE (int_dest_addr_mode)
 #define	INT_DELIVERY_MODE (int_delivery_mode)
-#else
+#endif /* CONFIG_X86_IO_APIC */
+#else /* CONFIG_X86_LOCAL_APIC */
 #define esr_disable (0)
 #define target_cpus() (0x01)
+#ifdef CONFIG_X86_IO_APIC
 #define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL)	/* logical delivery */
 #define INT_DELIVERY_MODE (dest_LowestPrio)
-#endif
+#endif /* CONFIG_X86_IO_APIC */
+#endif /* CONFIG_X86_LOCAL_APIC */
 
 #define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467)
 #define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469)
diff -urN linux-2.4.20-pre11/include/asm-sparc/highmem.h linux-2.4.20-rc1/include/asm-sparc/highmem.h
--- linux-2.4.20-pre11/include/asm-sparc/highmem.h	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/include/asm-sparc/highmem.h	Tue Oct 29 08:36:23 2002
@@ -20,15 +20,16 @@
 
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/vaddrs.h>
 #include <asm/kmap_types.h>
-#include <asm/pgtable.h>
 
 /* undef for production */
 #define HIGHMEM_DEBUG 1
 
+/* in mm/highmem.c */
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
 
@@ -51,12 +52,13 @@
  */
 #define LAST_PKMAP 1024
 
-#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
-#define PKMAP_NR(virt)  ((virt - pkmap_base) >> PAGE_SHIFT)
-#define PKMAP_ADDR(nr)  (pkmap_base + ((nr) << PAGE_SHIFT))
-
-extern void *kmap_high(struct page *page);
-extern void kunmap_high(struct page *page);
+#define LAST_PKMAP_MASK		(LAST_PKMAP - 1)
+#define PKMAP_NR(virt)		((virt - pkmap_base) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)		(pkmap_base + ((nr) << PAGE_SHIFT))
+
+/* in arch/sparc/mm/highmem.c */
+void *kmap_atomic(struct page *page, enum km_type type);
+void kunmap_atomic(void *kvaddr, enum km_type type);
 
 static inline void *kmap(struct page *page)
 {
@@ -76,78 +78,6 @@
 	kunmap_high(page);
 }
 
-/*
- * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
- * gives a more generic (and caching) interface. But kmap_atomic can
- * be used in IRQ contexts, so in some (very limited) cases we need
- * it.
- */
-static inline void *kmap_atomic(struct page *page, enum km_type type)
-{
-	unsigned long idx;
-	unsigned long vaddr;
-
-	if (page < highmem_start_page)
-		return page_address(page);
-
-	idx = type + KM_TYPE_NR*smp_processor_id();
-	vaddr = fix_kmap_begin + idx * PAGE_SIZE;
-
-/* XXX Fix - Anton */
-#if 0
-	__flush_cache_one(vaddr);
-#else
-	flush_cache_all();
-#endif
-
-#if HIGHMEM_DEBUG
-	if (!pte_none(*(kmap_pte+idx)))
-		BUG();
-#endif
-	set_pte(kmap_pte+idx, mk_pte(page, kmap_prot));
-/* XXX Fix - Anton */
-#if 0
-	__flush_tlb_one(vaddr);
-#else
-	flush_tlb_all();
-#endif
-
-	return (void*) vaddr;
-}
-
-static inline void kunmap_atomic(void *kvaddr, enum km_type type)
-{
-	unsigned long vaddr = (unsigned long) kvaddr;
-	unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
-
-	if (vaddr < fix_kmap_begin) // FIXME
-		return;
-
-	if (vaddr != fix_kmap_begin + idx * PAGE_SIZE)
-		BUG();
-
-/* XXX Fix - Anton */
-#if 0
-	__flush_cache_one(vaddr);
-#else
-	flush_cache_all();
-#endif
-
-#ifdef HIGHMEM_DEBUG
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(kmap_pte+idx);
-/* XXX Fix - Anton */
-#if 0
-	__flush_tlb_one(vaddr);
-#else
-	flush_tlb_all();
-#endif
-#endif
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -urN linux-2.4.20-pre11/include/linux/mtd/ftl.h linux-2.4.20-rc1/include/linux/mtd/ftl.h
--- linux-2.4.20-pre11/include/linux/mtd/ftl.h	Thu Oct  4 15:13:18 2001
+++ linux-2.4.20-rc1/include/linux/mtd/ftl.h	Tue Oct 29 08:36:29 2002
@@ -15,7 +15,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -urN linux-2.4.20-pre11/include/linux/nfsd/nfsd.h linux-2.4.20-rc1/include/linux/nfsd/nfsd.h
--- linux-2.4.20-pre11/include/linux/nfsd/nfsd.h	Thu Nov 22 11:47:20 2001
+++ linux-2.4.20-rc1/include/linux/nfsd/nfsd.h	Tue Oct 29 08:36:32 2002
@@ -37,7 +37,8 @@
 #define MAY_TRUNC		16
 #define MAY_LOCK		32
 #define MAY_OWNER_OVERRIDE	64
-#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAX_OWNER_OVERRIDE) & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_OWNER_OVERRIDE)
+#define _NFSD_IRIX_BOGOSITY	128
+#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAY_OWNER_OVERRIDE | _NFSD_IRIX_BOGOSITY) & (MAY_READ | MAY_WRITE | MAY_EXEC)
 # error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or MAY_OWNER_OVERRIDE."
 #endif
 #define MAY_CREATE		(MAY_EXEC|MAY_WRITE)
diff -urN linux-2.4.20-pre11/include/linux/sisfb.h linux-2.4.20-rc1/include/linux/sisfb.h
--- linux-2.4.20-pre11/include/linux/sisfb.h	Fri Aug  2 17:39:45 2002
+++ linux-2.4.20-rc1/include/linux/sisfb.h	Tue Oct 29 08:36:33 2002
@@ -1,6 +1,11 @@
 #ifndef _LINUX_SISFB
 #define _LINUX_SISFB
 
+#include <linux/spinlock.h>
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 #define DISPTYPE_CRT1       0x00000008L
 #define DISPTYPE_CRT2       0x00000004L
 #define DISPTYPE_LCD        0x00000002L
@@ -20,7 +25,7 @@
 #define HASVB_303       	0x40
 #define HASVB_CHRONTEL  	0x80
 
-/* Never change the order of the following enum */
+/* TW: *Never* change the order of the following enum */
 typedef enum _SIS_CHIP_TYPE {
 	SIS_VGALegacy = 0,
 	SIS_300,
@@ -38,6 +43,12 @@
 	MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
 
+typedef enum _VGA_ENGINE {
+	UNKNOWN_VGA = 0,
+	SIS_300_VGA,
+	SIS_315_VGA,
+} VGA_ENGINE;
+
 typedef enum _TVTYPE {
 	TVMODE_NTSC = 0,
 	TVMODE_PAL,
@@ -83,22 +94,25 @@
 };
 
 struct video_info {
-	int    chip_id;
+	int           chip_id;
 	unsigned int  video_size;
 	unsigned long video_base;
-	char  *video_vbase;
+	char  *       video_vbase;
 	unsigned long mmio_base;
-	char  *mmio_vbase; 
+	char  *       mmio_vbase;
 	unsigned long vga_base;
 	unsigned long mtrr;
+	unsigned long heapstart;
 
 	int    video_bpp;
+	int    video_cmap_len;
 	int    video_width;
 	int    video_height;
 	int    video_vwidth;
 	int    video_vheight;
 	int    org_x;
 	int    org_y;
+	int    video_linelength;
 	unsigned int refresh_rate;
 
 	unsigned long disp_state;
@@ -109,9 +123,46 @@
 	SIS_CHIP_TYPE chip;
 	unsigned char revision_id;
 
+        unsigned short DstColor;		/* TW: For 2d acceleration */
+	unsigned long  SiS310_AccelDepth;
+	unsigned long  CommandReg;
+
+	spinlock_t     lockaccel;
+
 	char reserved[256];
 };
 
+
+/* TW: Addtional IOCTL for communication sisfb <> X driver                 */
+/*     If changing this, vgatypes.h must also be changed (for X driver)    */
+
+/* TW: ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO	  _IOR('n',0xF8,sizeof(__u32))
+
+/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	unsigned long sisfb_id;         /* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	int    chip_id;			/* PCI ID of detected chip */
+	int    memory;			/* video memory in KB which sisfb manages */
+	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
+	unsigned char fbvidmode;	/* current sisfb mode */
+	
+	unsigned char sisfb_version;
+	unsigned char sisfb_revision;
+	unsigned char sisfb_patchlevel;
+
+	unsigned char sisfb_caps;	/* Sisfb capabilities */
+
+	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	char reserved[249]; 		/* for future use */
+};
+
 #ifdef __KERNEL__
 extern struct video_info ivideo;
 
diff -urN linux-2.4.20-pre11/init/do_mounts.c linux-2.4.20-rc1/init/do_mounts.c
--- linux-2.4.20-pre11/init/do_mounts.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/init/do_mounts.c	Tue Oct 29 08:36:35 2002
@@ -244,7 +244,8 @@
 
 kdev_t __init name_to_kdev_t(char *line)
 {
-	int base = 0;
+	int base = 0, offs;
+	char *end;
 
 	if (strncmp(line,"/dev/",5) == 0) {
 		struct dev_name_struct *dev = root_dev_names;
@@ -259,7 +260,10 @@
 			dev++;
 		} while (dev->name);
 	}
-	return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+	offs = simple_strtoul(line, &end, base?10:16);
+	if (*end)
+		offs = 0;
+	return to_kdev_t(base + offs);
 }
 
 static int __init root_dev_setup(char *line)
diff -urN linux-2.4.20-pre11/mm/shmem.c linux-2.4.20-rc1/mm/shmem.c
--- linux-2.4.20-pre11/mm/shmem.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/mm/shmem.c	Tue Oct 29 08:36:39 2002
@@ -615,6 +615,7 @@
 		if (!page)
 			return ERR_PTR(-ENOMEM);
 		clear_highpage(page);
+		flush_dcache_page(page);
 		inode->i_blocks += BLOCKS_PER_PAGE;
 		add_to_page_cache (page, mapping, idx);
 	}
diff -urN linux-2.4.20-pre11/net/core/dev.c linux-2.4.20-rc1/net/core/dev.c
--- linux-2.4.20-pre11/net/core/dev.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/core/dev.c	Tue Oct 29 08:36:40 2002
@@ -14,7 +14,7 @@
  *	Additional Authors:
  *		Florian la Roche <rzsfl@rz.uni-sb.de>
  *		Alan Cox <gw4pts@gw4pts.ampr.org>
- *		David Hinds <dhinds@allegro.stanford.edu>
+ *		David Hinds <dahinds@users.sourceforge.net>
  *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *		Adam Sulmicki <adam@cfar.umd.edu>
  *              Pekka Riikonen <priikone@poesidon.pspt.fi>
diff -urN linux-2.4.20-pre11/net/ipv4/route.c linux-2.4.20-rc1/net/ipv4/route.c
--- linux-2.4.20-pre11/net/ipv4/route.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/ipv4/route.c	Tue Oct 29 08:36:46 2002
@@ -248,7 +248,8 @@
 				r->u.dst.__use,
 				0,
 				(unsigned long)r->rt_src,
-				(int)r->u.dst.advmss + 40,
+				(r->u.dst.advmss ?
+				 (int) r->u.dst.advmss + 40 : 0),
 				r->u.dst.window,
 				(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar),
 				r->key.tos,
diff -urN linux-2.4.20-pre11/net/ipv4/tcp_input.c linux-2.4.20-rc1/net/ipv4/tcp_input.c
--- linux-2.4.20-pre11/net/ipv4/tcp_input.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/ipv4/tcp_input.c	Tue Oct 29 08:36:46 2002
@@ -3692,6 +3692,9 @@
 		if(th->ack)
 			return 1;
 
+		if(th->rst)
+			goto discard;
+
 		if(th->syn) {
 			if(tp->af_specific->conn_request(sk, skb) < 0)
 				return 1;
diff -urN linux-2.4.20-pre11/net/ipv6/addrconf.c linux-2.4.20-rc1/net/ipv6/addrconf.c
--- linux-2.4.20-pre11/net/ipv6/addrconf.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/ipv6/addrconf.c	Tue Oct 29 08:36:46 2002
@@ -1273,9 +1273,8 @@
 int addrconf_notify(struct notifier_block *this, unsigned long event, 
 		    void * data)
 {
-	struct net_device *dev;
-
-	dev = (struct net_device *) data;
+	struct net_device *dev = (struct net_device *) data;
+	struct inet6_dev *idev = __in6_dev_get(dev);
 
 	switch(event) {
 	case NETDEV_UP:
@@ -1292,16 +1291,27 @@
 			addrconf_dev_config(dev);
 			break;
 		};
+		if (idev) {
+			/* If the MTU changed during the interface down, when the 
+			   interface up, the changed MTU must be reflected in the 
+			   idev as well as routers.
+			 */
+			if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {
+				rt6_mtu_change(dev, dev->mtu);
+				idev->cnf.mtu6 = dev->mtu;
+			}
+			/* If the changed mtu during down is lower than IPV6_MIN_MTU
+			   stop IPv6 on this interface.
+			 */
+			if (dev->mtu < IPV6_MIN_MTU)
+				addrconf_ifdown(dev, event != NETDEV_DOWN);
+		}
 		break;
 
 	case NETDEV_CHANGEMTU:
-		if (dev->mtu >= IPV6_MIN_MTU) {
-			struct inet6_dev *idev;
-
-			if ((idev = __in6_dev_get(dev)) == NULL)
-				break;
-			idev->cnf.mtu6 = dev->mtu;
+		if ( idev && dev->mtu >= IPV6_MIN_MTU) {
 			rt6_mtu_change(dev, dev->mtu);
+			idev->cnf.mtu6 = dev->mtu;
 			break;
 		}
 
diff -urN linux-2.4.20-pre11/net/ipv6/ip6_fib.c linux-2.4.20-rc1/net/ipv6/ip6_fib.c
--- linux-2.4.20-pre11/net/ipv6/ip6_fib.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/ipv6/ip6_fib.c	Tue Oct 29 08:36:46 2002
@@ -1173,15 +1173,6 @@
 	   only if they are not in use now.
 	 */
 
-	if (rt->rt6i_flags & RTF_CACHE) {
-		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
-		    (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
-			RT6_TRACE("aging clone %p\n", rt);
-			return -1;
-		}
-		gc_args.more++;
-	}
-
 	/*
 	 *	check addrconf expiration here.
 	 *	They are expired even if they are in use.
@@ -1193,6 +1184,13 @@
 			return -1;
 		}
 		gc_args.more++;
+	} else if (rt->rt6i_flags & RTF_CACHE) {
+		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
+		    (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
+			RT6_TRACE("aging clone %p\n", rt);
+			return -1;
+		}
+		gc_args.more++;
 	}
 
 	return 0;
diff -urN linux-2.4.20-pre11/net/ipv6/ndisc.c linux-2.4.20-rc1/net/ipv6/ndisc.c
--- linux-2.4.20-pre11/net/ipv6/ndisc.c	Tue Oct 29 08:34:27 2002
+++ linux-2.4.20-rc1/net/ipv6/ndisc.c	Tue Oct 29 08:36:46 2002
@@ -1235,9 +1235,6 @@
 					struct rt6_info *rt;
 					rt = rt6_get_dflt_router(saddr, skb->dev);
 					if (rt) {
-						/* It is safe only because
-						   we aer in BH */
-						dst_release(&rt->u.dst);
 						ip6_del_rt(rt);
 					}
 				}
diff -urN linux-2.4.20-pre11/net/ipv6/route.c linux-2.4.20-rc1/net/ipv6/route.c
--- linux-2.4.20-pre11/net/ipv6/route.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.20-rc1/net/ipv6/route.c	Tue Oct 29 08:36:46 2002
@@ -976,7 +976,11 @@
 		if (net_ratelimit())
 			printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
 			       pmtu);
-		return;
+		/* According to RFC1981, the PMTU is set to the IPv6 minimum
+		   link MTU if the node receives a Packet Too Big message
+		   reporting next-hop MTU that is less than the IPv6 minimum MTU.
+		 */	
+		pmtu = IPV6_MIN_MTU;
 	}
 
 	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
@@ -1014,7 +1018,13 @@
 		nrt = rt6_cow(rt, daddr, saddr);
 		if (!nrt->u.dst.error) {
 			nrt->u.dst.pmtu = pmtu;
-			dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+			/* According to RFC 1981, detecting PMTU increase shouldn't be
+			   happened within 5 mins, the recommended timer is 10 mins.
+			   Here this route expiration time is set to ip6_rt_mtu_expires 
+			   which is 10 mins. After 10 mins the decreased pmtu is expired
+			   and detecting PMTU increase will be automatically happened.
+			 */
+			dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 			nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
 			dst_release(&nrt->u.dst);
 		}
@@ -1026,7 +1036,7 @@
 		nrt->rt6i_dst.plen = 128;
 		nrt->u.dst.flags |= DST_HOST;
 		nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
-		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
 		nrt->u.dst.pmtu = pmtu;
 		rt6_ins(nrt);
@@ -1380,15 +1390,32 @@
 static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
 {
 	struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
-
+	struct inet6_dev *idev;
 	/* In IPv6 pmtu discovery is not optional,
 	   so that RTAX_MTU lock cannot disable it.
 	   We still use this lock to block changes
 	   caused by addrconf/ndisc.
 	*/
+	idev = __in6_dev_get(arg->dev);
+	/* For administrative MTU increase, there is no way to discover 
+	   IPv6 PMTU increase, so PMTU increase should be updated here.
+	   Since RFC 1981 doesn't include administrative MTU increase
+	   update PMTU increase is a MUST. (i.e. jumbo frame)
+	 */
+	/*
+	   If new MTU is less than route PMTU, this new MTU will be the 
+	   lowest MTU in the path, update the route PMTU to refect PMTU 
+	   decreases; if new MTU is greater than route PMTU, and the 
+	   old MTU is the lowest MTU in the path, update the route PMTU 
+	   to refect the increase. In this case if the other nodes' MTU
+	   also have the lowest MTU, TOO BIG MESSAGE will be lead to 
+	   PMTU discouvery. 
+	 */
 	if (rt->rt6i_dev == arg->dev &&
-	    rt->u.dst.pmtu > arg->mtu &&
-	    !(rt->u.dst.mxlock&(1<<RTAX_MTU)))
+	    !(rt->u.dst.mxlock&(1<<RTAX_MTU)) &&
+	      (rt->u.dst.pmtu > arg->mtu ||
+	       (rt->u.dst.pmtu < arg->mtu &&
+		rt->u.dst.pmtu == idev->cnf.mtu6)))
 		rt->u.dst.pmtu = arg->mtu;
 	rt->u.dst.advmss = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss);
 	if (rt->u.dst.advmss > 65535-20)
