## Automatically generated incremental diff
## From:   linux-2.5.2-pre11
## To:     linux-2.5.2
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.5.2-pre11/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.5.2-pre11/Documentation/Configure.help	Mon Jan 14 18:28:21 2002
+++ linux/Documentation/Configure.help	Mon Jan 14 18:28:26 2002
@@ -6301,6 +6301,18 @@
   boards supported by this driver, and for further information
   on the use of this driver.
 
+SCSI tape drive support for Smart Array 5xxx
+CONFIG_CISS_SCSI_TAPE
+  When enabled (Y), this option allows SCSI tape drives and SCSI medium
+  changers (tape robots) to be accessed via a Compaq 5xxx array 
+  controller.  (See Documentation/cciss.txt for more details.)
+
+  "SCSI support" and "SCSI tape support" must also be enabled for this 
+  option to work.
+
+  When this option is disabled (N), the SCSI portion of the driver 
+  is not compiled.
+
 QuickNet Internet LineJack/PhoneJack support
 CONFIG_PHONE_IXJ
   Say M if you have a telephony card manufactured by Quicknet
@@ -24028,6 +24040,13 @@
   If you are using GDB for remote debugging over a serial port and
   would like kernel messages to be formatted into GDB $O packets so
   that GDB prints them as program output, say 'Y'.
+
+CRC32 functions
+CONFIG_CRC32
+  This option is provided for the case where no in-kernel-tree
+  modules require CRC32 functions, but a module built outside the
+  kernel tree does. Such modules that use library CRC32 functions
+  require M here.
 
 #
 # A couple of things I keep forgetting:
diff -urN linux-2.5.2-pre11/Documentation/block/request.txt linux/Documentation/block/request.txt
--- linux-2.5.2-pre11/Documentation/block/request.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/block/request.txt	Mon Jan 14 18:28:26 2002
@@ -0,0 +1,86 @@
+
+struct request documentation
+
+Jens Axboe <axboe@suse.de> 070102
+
+1.0
+Index
+
+2.0 Struct request members classification
+
+	2.1 struct request members explanation
+
+3.0
+
+
+2.0
+Short explanation of request members
+
+Classification flags:
+
+	D	driver member
+	B	block layer member
+	I	I/O scheduler member
+
+Unless an entry contains a D classification, a device driver must not access
+this member. Some members may contain D classifications, but should only be
+access through certain macros or functions (eg ->flags).
+
+<linux/blkdev.h>
+
+2.1
+Member				Flag	Comment
+------				----	-------
+
+struct list_head queuelist	BI	Organization on various internal
+					queues
+
+void *elevator_private		I	I/O scheduler private data
+
+unsigned char cmd[16]		D	Driver can use this for setting up
+					a cdb before execution, see
+					blk_queue_prep_rq
+
+unsigned long flags		DBI	Contains info about data direction,
+					request type, etc.
+
+int rq_status			D	Request status bits
+
+kdev_t rq_dev			DBI	Target device
+
+int errors			DB	Error counts
+
+sector_t sector			DBI	Target location
+
+unsigned long hard_nr_sectors	B	Used to keep sector sane
+
+unsigned long nr_sectors	DBI	Total number of sectors in request
+
+unsigned long hard_nr_sectors	B	Used to keep nr_sectors sane
+
+unsigned short nr_phys_segments	DB	Number of physical scatter gather
+					segments in a request
+
+unsigned short nr_hw_segments	DB	Number of hardware scatter gather
+					segments in a request
+
+unsigned int current_nr_sectors	DB	Number of sectors in first segment
+					of request
+
+unsigned int hard_cur_sectors	B	Used to keep current_nr_sectors sane
+
+void *special			D	Free to be used by driver
+
+char *buffer			D	Map of first segment, also see
+					section on bouncing SECTION
+
+struct completion *waiting	D	Can be used by driver to get signalled
+					on request completion
+
+struct bio *bio			DBI	First bio in request
+
+struct bio *biotail		DBI	Last bio in request
+
+request_queue_t *q		DB	Request queue this request belongs to
+
+struct request_list *rl		B	Request list this request came from
diff -urN linux-2.5.2-pre11/Documentation/cciss.txt linux/Documentation/cciss.txt
--- linux-2.5.2-pre11/Documentation/cciss.txt	Thu Oct 11 09:04:57 2001
+++ linux/Documentation/cciss.txt	Mon Jan 14 18:28:26 2002
@@ -100,7 +100,7 @@
 can be informed of changes to the virtual SCSI bus which the driver 
 presents to it in the usual way. For example: 
 
-	echo add-single-device 3 2 1 0 > /proc/scsi/scsi
+	echo scsi add-single-device 3 2 1 0 > /proc/scsi/scsi
  
 to add a device on controller 3, bus 2, target 1, lun 0.   Note that
 the driver makes an effort to preserve the devices positions
diff -urN linux-2.5.2-pre11/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- linux-2.5.2-pre11/Documentation/filesystems/devfs/ChangeLog	Mon Jan 14 18:28:21 2002
+++ linux/Documentation/filesystems/devfs/ChangeLog	Mon Jan 14 18:28:26 2002
@@ -1863,3 +1863,9 @@
 - Defined macros for error and debug messages
 
 - Updated README from master HTML file
+===============================================================================
+Changes for patch v206
+
+- Added support for multiple Compaq cpqarray controllers
+
+- Fixed (rare, old) race in <devfs_lookup>
diff -urN linux-2.5.2-pre11/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- linux-2.5.2-pre11/Documentation/networking/ip-sysctl.txt	Wed May 16 10:21:45 2001
+++ linux/Documentation/networking/ip-sysctl.txt	Mon Jan 14 18:28:27 2002
@@ -309,13 +309,20 @@
 	ICMP ECHO requests sent to it or just those to broadcast/multicast
 	addresses, respectively.
 
-icmp_destunreach_rate - INTEGER
-icmp_paramprob_rate - INTEGER
-icmp_timeexceed_rate - INTEGER
-icmp_echoreply_rate - INTEGER (not enabled per default)
-	Limit the maximal rates for sending ICMP packets to specific targets.
+icmp_ratelimit - INTEGER
+	Limit the maximal rates for sending ICMP packets whose type matches
+	icmp_ratemask (see below) to specific targets.
 	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-	See the source for more information.
+	Default: 1
+
+icmp_ratemask - INTEGER
+	Mask made of ICMP types for which rates are being limited.
+	Default: 6168
+	Note: 6168 = 0x1818 = 1<<ICMP_DEST_UNREACH + 1<<ICMP_SOURCE_QUENCH +
+	      1<<ICMP_TIME_EXCEEDED + 1<<ICMP_PARAMETERPROB, which means
+	      dest unreachable (3), source quench (4), time exceeded (11)
+	      and parameter problem (12) ICMP packets are rate limited
+	      (check values in icmp.h)
 
 icmp_ignore_bogus_error_responses - BOOLEAN
 	Some routers violate RFC 1122 by sending bogus responses to broadcast
@@ -511,4 +518,4 @@
 Pekka Savola
 pekkas@netcore.fi
 
-$Id: ip-sysctl.txt,v 1.19 2001/05/16 17:11:04 davem Exp $
+$Id: ip-sysctl.txt,v 1.20 2001/12/13 09:00:18 davem Exp $
diff -urN linux-2.5.2-pre11/Makefile linux/Makefile
--- linux-2.5.2-pre11/Makefile	Mon Jan 14 18:28:21 2002
+++ linux/Makefile	Mon Jan 14 18:28:27 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 2
-EXTRAVERSION =-pre11
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -122,7 +122,7 @@
 NETWORKS	=net/network.o
 
 LIBS		=$(TOPDIR)/lib/lib.a
-SUBDIRS		=kernel drivers mm fs net ipc lib
+SUBDIRS		=kernel lib drivers mm fs net ipc
 
 DRIVERS-n :=
 DRIVERS-y :=
@@ -261,9 +261,9 @@
 	$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
 		--start-group \
 		$(CORE_FILES) \
+		$(LIBS) \
 		$(DRIVERS) \
 		$(NETWORKS) \
-		$(LIBS) \
 		--end-group \
 		-o vmlinux
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
diff -urN linux-2.5.2-pre11/arch/alpha/config.in linux/arch/alpha/config.in
--- linux-2.5.2-pre11/arch/alpha/config.in	Tue Nov 20 15:49:31 2001
+++ linux/arch/alpha/config.in	Mon Jan 14 18:28:27 2002
@@ -393,3 +393,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/arm/config.in linux/arch/arm/config.in
--- linux-2.5.2-pre11/arch/arm/config.in	Mon Jan 14 18:28:21 2002
+++ linux/arch/arm/config.in	Mon Jan 14 18:28:27 2002
@@ -709,3 +709,5 @@
 dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
 dep_bool '    Kernel low-level debugging messages via SA1100 Ser3 (otherwise Ser1)' CONFIG_DEBUG_LL_SER3 $CONFIG_DEBUG_LL $CONFIG_ARCH_SA1100
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/cris/config.in linux/arch/cris/config.in
--- linux-2.5.2-pre11/arch/cris/config.in	Mon Oct 15 13:42:14 2001
+++ linux/arch/cris/config.in	Mon Jan 14 18:28:27 2002
@@ -251,3 +251,5 @@
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.5.2-pre11/arch/i386/config.in	Mon Jan 14 18:28:22 2002
+++ linux/arch/i386/config.in	Mon Jan 14 18:28:27 2002
@@ -419,3 +419,5 @@
 fi
 
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.5.2-pre11/arch/i386/defconfig	Mon Jan 14 18:28:22 2002
+++ linux/arch/i386/defconfig	Mon Jan 14 18:28:27 2002
@@ -130,6 +130,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -831,3 +832,8 @@
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -urN linux-2.5.2-pre11/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.5.2-pre11/arch/i386/kernel/setup.c	Mon Jan 14 18:28:22 2002
+++ linux/arch/i386/kernel/setup.c	Mon Jan 14 18:28:27 2002
@@ -748,6 +748,7 @@
 			printk(KERN_WARNING "Use a PAE enabled kernel.\n");
 		else
 			printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+		max_pfn = MAXMEM_PFN;
 #else /* !CONFIG_HIGHMEM */
 #ifndef CONFIG_X86_PAE
 		if (max_pfn > MAX_NONPAE_PFN) {
diff -urN linux-2.5.2-pre11/arch/ia64/config.in linux/arch/ia64/config.in
--- linux-2.5.2-pre11/arch/ia64/config.in	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/config.in	Mon Jan 14 18:28:27 2002
@@ -234,6 +234,8 @@
 
 source drivers/usb/Config.in
 
+source lib/Config.in
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    source net/bluetooth/Config.in
 fi
diff -urN linux-2.5.2-pre11/arch/m68k/config.in linux/arch/m68k/config.in
--- linux-2.5.2-pre11/arch/m68k/config.in	Mon Jun 11 19:15:27 2001
+++ linux/arch/m68k/config.in	Mon Jan 14 18:28:27 2002
@@ -546,3 +546,5 @@
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/mips/config.in linux/arch/mips/config.in
--- linux-2.5.2-pre11/arch/mips/config.in	Mon Oct 15 13:41:34 2001
+++ linux/arch/mips/config.in	Mon Jan 14 18:28:27 2002
@@ -520,3 +520,5 @@
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/mips64/config.in linux/arch/mips64/config.in
--- linux-2.5.2-pre11/arch/mips64/config.in	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/config.in	Mon Jan 14 18:28:28 2002
@@ -276,3 +276,5 @@
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/parisc/config.in linux/arch/parisc/config.in
--- linux-2.5.2-pre11/arch/parisc/config.in	Tue Apr 17 17:19:25 2001
+++ linux/arch/parisc/config.in	Mon Jan 14 18:28:28 2002
@@ -208,3 +208,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.5.2-pre11/arch/ppc/config.in	Fri Nov 16 10:10:08 2001
+++ linux/arch/ppc/config.in	Mon Jan 14 18:28:28 2002
@@ -393,3 +393,5 @@
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 bool 'Include xmon kernel debugger' CONFIG_XMON
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/s390/config.in linux/arch/s390/config.in
--- linux-2.5.2-pre11/arch/s390/config.in	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390/config.in	Mon Jan 14 18:28:28 2002
@@ -73,3 +73,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/s390x/config.in linux/arch/s390x/config.in
--- linux-2.5.2-pre11/arch/s390x/config.in	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390x/config.in	Mon Jan 14 18:28:28 2002
@@ -77,3 +77,4 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/sh/config.in linux/arch/sh/config.in
--- linux-2.5.2-pre11/arch/sh/config.in	Tue Dec 11 10:10:18 2001
+++ linux/arch/sh/config.in	Mon Jan 14 18:28:28 2002
@@ -386,3 +386,5 @@
    bool 'Early printk support' CONFIG_SH_EARLY_PRINTK
 fi
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/sparc/config.in linux/arch/sparc/config.in
--- linux-2.5.2-pre11/arch/sparc/config.in	Mon Jun 11 19:15:27 2001
+++ linux/arch/sparc/config.in	Mon Jan 14 18:28:28 2002
@@ -266,3 +266,5 @@
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/check_asm.sh linux/arch/sparc/kernel/check_asm.sh
--- linux-2.5.2-pre11/arch/sparc/kernel/check_asm.sh	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc/kernel/check_asm.sh	Mon Jan 14 18:28:28 2002
@@ -1,12 +1,12 @@
 #!/bin/sh
 case $1 in
   -printf)
-    sed -n -e '/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
+    sed -n -e '/^#/d;/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
 /g' | sed 's/^[ 	*]*//;s/[ 	]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0	0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0	0x%08x\\n", check_asm_data[i++]);/' >> $4
     echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4
   ;;
   -data)
-    sed -n -e '/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
+    sed -n -e '/^#/d;/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
 /g' | sed 's/^[ 	*]*//;s/[ 	]*$//;s/^.*$/	((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)),	sizeof(((struct '$2'_struct *)0)->\0),/' >> $4
     echo "	sizeof(struct $2_struct)," >> $4
   ;;
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c
--- linux-2.5.2-pre11/arch/sparc/kernel/devices.c	Tue Aug 31 11:23:29 1999
+++ linux/arch/sparc/kernel/devices.c	Mon Jan 14 18:28:28 2002
@@ -4,9 +4,10 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/threads.h>
-#include <linux/config.h>
+#include <linux/string.h>
 #include <linux/init.h>
 
 #include <asm/page.h>
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c
--- linux-2.5.2-pre11/arch/sparc/kernel/ebus.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/kernel/ebus.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.18 2001/11/08 04:41:33 davem Exp $
+/* $Id: ebus.c,v 1.20 2002/01/05 01:13:43 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- linux-2.5.2-pre11/arch/sparc/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/sparc/kernel/init_task.c	Mon Jan 14 18:28:28 2002
@@ -14,6 +14,6 @@
  * If this is not aligned on a 8k boundry, then you should change code
  * in etrap.S which assumes it.
  */
-union task_union init_task_union
-	__attribute__((__section__(".text"))) =
+__asm__(".section \".text\",#alloc\n");
+union task_union init_task_union =
 		{ INIT_TASK(init_task_union.task) };
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- linux-2.5.2-pre11/arch/sparc/kernel/irq.c	Wed Nov 28 13:22:26 2001
+++ linux/arch/sparc/kernel/irq.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.113 2001/07/17 16:17:33 anton Exp $
+/*  $Id: irq.c,v 1.114 2001/12/11 04:55:51 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- linux-2.5.2-pre11/arch/sparc/kernel/process.c	Mon Jan 14 18:28:22 2002
+++ linux/arch/sparc/kernel/process.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.157 2001/11/13 00:57:05 davem Exp $
+/*  $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -60,9 +60,6 @@
 		goto out;
 
 	/* endless idle loop with no priority at all */
-	current->nice = 20;
-	init_idle();
-
 	for (;;) {
 		if (ARCH_SUN4C_SUN4) {
 			static int count = HZ;
@@ -108,9 +105,6 @@
 int cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
-	current->nice = 20;
-	init_idle();
-
 	while(1) {
 		if(current->need_resched) {
 			schedule();
@@ -283,37 +277,29 @@
 	show_regwindow((struct reg_window *)regs->u_regs[14]);
 }
 
-#if NOTUSED
-void show_thread(struct thread_struct *thread)
+void show_trace_task(struct task_struct *tsk)
 {
-	int i;
-
-	printk("uwinmask:          0x%08lx  kregs:             0x%08lx\n", thread->uwinmask, (unsigned long)thread->kregs);
-	show_regs(thread->kregs);
-	printk("ksp:               0x%08lx  kpc:               0x%08lx\n", thread->ksp, thread->kpc);
-	printk("kpsr:              0x%08lx  kwim:              0x%08lx\n", thread->kpsr, thread->kwim);
-	printk("fork_kpsr:         0x%08lx  fork_kwim:         0x%08lx\n", thread->fork_kpsr, thread->fork_kwim);
-
-	for (i = 0; i < NSWINS; i++) {
-		if (!thread->rwbuf_stkptrs[i])
-			continue;
-		printk("reg_window[%d]:\n", i);
-		printk("stack ptr:         0x%08lx\n", thread->rwbuf_stkptrs[i]);
-		show_regwindow(&thread->reg_window[i]);
-	}
-	printk("w_saved:           0x%08lx\n", thread->w_saved);
-
-	/* XXX missing: float_regs */
-	printk("fsr:               0x%08lx  fpqdepth:          0x%08lx\n", thread->fsr, thread->fpqdepth);
-	/* XXX missing: fpqueue */
+	unsigned long pc, fp;
+	unsigned long task_base = (unsigned long) tsk;
+	struct reg_window *rw;
+	int count = 0;
 
-	printk("flags:             0x%08lx  current_ds:        0x%08lx\n", thread->flags, thread->current_ds.seg);
-	
-	show_regwindow((struct reg_window *)thread->ksp);
+	if (!tsk)
+		return;
 
-	/* XXX missing: core_exec */
+	fp = tsk->thread.ksp;
+	do {
+		/* Bogus frame pointer? */
+		if (fp < (task_base + sizeof(struct task_struct)) ||
+		    fp >= (task_base + (PAGE_SIZE << 1)))
+			break;
+		rw = (struct reg_window *) fp;
+		pc = rw->ins[7];
+		printk("[%08lx] ", pc);
+		fp = rw->ins[6];
+	} while (++count < 16);
+	printk("\n");
 }
-#endif
 
 /*
  * Free current thread data structures etc..
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- linux-2.5.2-pre11/arch/sparc/kernel/signal.c	Wed Jan 24 15:18:06 2001
+++ linux/arch/sparc/kernel/signal.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.108 2001/01/24 21:05:12 davem Exp $
+/*  $Id: signal.c,v 1.109 2001/12/21 01:22:31 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/tty.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c
--- linux-2.5.2-pre11/arch/sparc/kernel/sun4d_irq.c	Wed Nov 28 13:22:26 2001
+++ linux/arch/sparc/kernel/sun4d_irq.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: sun4d_irq.c,v 1.28 2001/07/17 16:17:33 anton Exp $
+/*  $Id: sun4d_irq.c,v 1.29 2001/12/11 04:55:51 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *			SS1000/SC2000 interrupt handling.
  *
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- linux-2.5.2-pre11/arch/sparc/kernel/sun4d_smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/sparc/kernel/sun4d_smp.c	Mon Jan 14 18:28:28 2002
@@ -127,7 +127,7 @@
 	while((unsigned long)current_set[cpuid] < PAGE_OFFSET)
 		barrier();
 		
-	while(current_set[cpuid]->processor != cpuid)
+	while(current_set[cpuid]->cpu != cpuid)
 		barrier();
 		
 	/* Fix idle thread fields. */
@@ -197,10 +197,9 @@
 		mid_xlate[i] = i;
 	__cpu_number_map[boot_cpu_id] = 0;
 	__cpu_logical_map[0] = boot_cpu_id;
-	current->processor = boot_cpu_id;
+	current->cpu = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
 	smp_setup_percpu_timer();
-	init_idle();
 	local_flush_cache_all();
 	if(linux_num_cpus == 1)
 		return;  /* Not an MP box. */
@@ -222,14 +221,11 @@
 			cpucount++;
 
 			p = init_task.prev_task;
-			init_tasks[i] = p;
 
-			p->processor = i;
-			p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+			p->cpu = i;
 
 			current_set[i] = p;
 
-			del_from_runqueue(p);
 			unhash_process(p);
 
 			for (no = 0; no < linux_num_cpus; no++)
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- linux-2.5.2-pre11/arch/sparc/kernel/sun4m_smp.c	Wed Nov 21 10:31:09 2001
+++ linux/arch/sparc/kernel/sun4m_smp.c	Mon Jan 14 18:28:28 2002
@@ -170,12 +170,11 @@
 	mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
 	__cpu_number_map[boot_cpu_id] = 0;
 	__cpu_logical_map[0] = boot_cpu_id;
-	current->processor = boot_cpu_id;
+	current->cpu = boot_cpu_id;
 
 	smp_store_cpu_info(boot_cpu_id);
 	set_irq_udt(mid_xlate[boot_cpu_id]);
 	smp_setup_percpu_timer();
-	init_idle();
 	local_flush_cache_all();
 	if(linux_num_cpus == 1)
 		return;  /* Not an MP box. */
@@ -195,14 +194,11 @@
 			cpucount++;
 
 			p = init_task.prev_task;
-			init_tasks[i] = p;
 
-			p->processor = i;
-			p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+			p->cpu = i;
 
 			current_set[i] = p;
 
-			del_from_runqueue(p);
 			unhash_process(p);
 
 			/* See trampoline.S for details... */
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- linux-2.5.2-pre11/arch/sparc/kernel/sys_sunos.c	Tue Aug 14 19:57:28 2001
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.135 2001/08/13 14:40:10 davem Exp $
+/* $Id: sys_sunos.c,v 1.136 2002/01/08 16:00:14 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -90,8 +90,8 @@
 	 * SunOS is so stupid some times... hmph!
 	 */
 	if (file) {
-		if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
-		   MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
+		if(major(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
+		   minor(file->f_dentry->d_inode->i_rdev) == 5) {
 			flags |= MAP_ANONYMOUS;
 			fput(file);
 			file = 0;
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S
--- linux-2.5.2-pre11/arch/sparc/kernel/trampoline.S	Wed Aug  4 16:36:41 1999
+++ linux/arch/sparc/kernel/trampoline.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.13 1999/08/04 03:19:15 davem Exp $
+/* $Id: trampoline.S,v 1.14 2002/01/11 08:45:38 davem Exp $
  * trampoline.S: SMP cpu boot-up trampoline code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -88,6 +88,8 @@
 	.align	4
 
 smp_do_cpu_idle:
+	call	C_LABEL(init_idle)
+	 nop
 	call	C_LABEL(cpu_idle)
 	 mov	0, %o0
 
diff -urN linux-2.5.2-pre11/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c
--- linux-2.5.2-pre11/arch/sparc/kernel/unaligned.c	Wed May  3 01:47:57 2000
+++ linux/arch/sparc/kernel/unaligned.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.22 2000/04/29 08:05:21 anton Exp $
+/* $Id: unaligned.c,v 1.23 2001/12/21 00:54:31 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -224,7 +224,7 @@
 	"or	%%l1, %%g7, %%g7\n\t"						\
 	"st	%%g7, [%0 + 4]\n"						\
 "0:\n\n\t"									\
-	".section __ex_table\n\t"						\
+	".section __ex_table,#alloc\n\t"					\
 	".word	4b, " #errh "\n\t"						\
 	".word	5b, " #errh "\n\t"						\
 	".word	6b, " #errh "\n\t"						\
@@ -277,7 +277,7 @@
 "16:\t"	"stb	%%l2, [%0]\n"							\
 "17:\t"	"stb	%%l1, [%0 + 1]\n"						\
 "0:\n\n\t"									\
-	".section __ex_table\n\t"						\
+	".section __ex_table,#alloc\n\t"					\
 	".word	4b, " #errh "\n\t"						\
 	".word	5b, " #errh "\n\t"						\
 	".word	6b, " #errh "\n\t"						\
diff -urN linux-2.5.2-pre11/arch/sparc/mm/extable.c linux/arch/sparc/mm/extable.c
--- linux-2.5.2-pre11/arch/sparc/mm/extable.c	Sun Aug 12 11:23:32 2001
+++ linux/arch/sparc/mm/extable.c	Mon Jan 14 18:28:28 2002
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -urN linux-2.5.2-pre11/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- linux-2.5.2-pre11/arch/sparc/mm/fault.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc/mm/fault.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.121 2001/10/30 04:54:22 davem Exp $
+/* $Id: fault.c,v 1.122 2001/11/17 07:19:26 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -155,34 +155,47 @@
 asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
 			    unsigned long address)
 {
+	struct pt_regs regs;
 	unsigned long g2;
+	unsigned int insn;
 	int i;
-	unsigned insn;
-	struct pt_regs regs;
 	
-	i = search_exception_table (ret_pc, &g2);
+	i = search_exception_table(ret_pc, &g2);
 	switch (i) {
-	/* load & store will be handled by fixup */
-	case 3: return 3;
-	/* store will be handled by fixup, load will bump out */
-	/* for _to_ macros */
-	case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break;
-	/* load will be handled by fixup, store will bump out */
-	/* for _from_ macros */
-	case 2: insn = (unsigned)pc; 
-		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
+	case 3:
+		/* load & store will be handled by fixup */
+		return 3;
+
+	case 1:
+		/* store will be handled by fixup, load will bump out */
+		/* for _to_ macros */
+		insn = *((unsigned int *) pc);
+		if ((insn >> 21) & 1)
+			return 1;
+		break;
+
+	case 2:
+		/* load will be handled by fixup, store will bump out */
+		/* for _from_ macros */
+		insn = *((unsigned int *) pc);
+		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
+			return 2; 
 		break; 
-	default: break;
-	}
-	memset (&regs, 0, sizeof (regs));
+
+	default:
+		break;
+	};
+
+	memset(&regs, 0, sizeof (regs));
 	regs.pc = pc;
 	regs.npc = pc + 4;
-	__asm__ __volatile__ (
+	__asm__ __volatile__(
 		"rd %%psr, %0\n\t"
 		"nop\n\t"
 		"nop\n\t"
 		"nop\n" : "=r" (regs.psr));
-	unhandled_fault (address, current, &regs);
+	unhandled_fault(address, current, &regs);
+
 	/* Not reached */
 	return 0;
 }
diff -urN linux-2.5.2-pre11/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- linux-2.5.2-pre11/arch/sparc/mm/init.c	Mon Oct  1 09:19:56 2001
+++ linux/arch/sparc/mm/init.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.100 2001/09/21 22:51:47 davem Exp $
+/*  $Id: init.c,v 1.103 2001/11/19 19:03:08 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -410,9 +410,6 @@
 	int datapages = 0;
 	int initpages = 0; 
 	int i;
-#ifdef CONFIG_BLK_DEV_INITRD
-	unsigned long addr, last;
-#endif
 
 	highmem_start_page = mem_map + highstart_pfn;
 
diff -urN linux-2.5.2-pre11/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c
--- linux-2.5.2-pre11/arch/sparc/mm/io-unit.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc/mm/io-unit.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.23 2001/02/13 01:16:43 davem Exp $
+/* $Id: io-unit.c,v 1.24 2001/12/17 07:05:09 davem Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
@@ -131,7 +131,7 @@
 	/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
 	spin_lock_irqsave(&iounit->lock, flags);
 	for (; sz >= 0; sz--) {
-		sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length);
+		sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)page_address(sg[sz].page) + sg[sz].offset, sg[sz].length);
 		sg[sz].dvma_length = sg[sz].length;
 	}
 	spin_unlock_irqrestore(&iounit->lock, flags);
diff -urN linux-2.5.2-pre11/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c
--- linux-2.5.2-pre11/arch/sparc/mm/iommu.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc/mm/iommu.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.21 2001/02/13 01:16:43 davem Exp $
+/* $Id: iommu.c,v 1.22 2001/12/17 07:05:09 davem Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -168,7 +168,7 @@
 static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
 	for (; sz >= 0; sz--) {
-		sg[sz].dvma_address = (__u32) (sg[sz].address);
+		sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
 	}
 }
@@ -177,7 +177,7 @@
 {
 	flush_page_for_dma(0);
 	for (; sz >= 0; sz--) {
-		sg[sz].dvma_address = (__u32) (sg[sz].address);
+		sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
 	}
 }
@@ -187,14 +187,14 @@
 	unsigned long page, oldpage = 0;
 
 	while(sz >= 0) {
-		page = ((unsigned long) sg[sz].address) & PAGE_MASK;
+		page = ((unsigned long) sg[sz].offset) & PAGE_MASK;
 		if (oldpage == page)
 			page += PAGE_SIZE; /* We flushed that page already */
-		while(page < (unsigned long)(sg[sz].address + sg[sz].length)) {
+		while(page < (unsigned long)(page_address(sg[sz].page) + sg[sz].offset + sg[sz].length)) {
 			flush_page_for_dma(page);
 			page += PAGE_SIZE;
 		}
-		sg[sz].dvma_address = (__u32) (sg[sz].address);
+		sg[sz].dvma_address = (__u32) (page_address(sg[sz].page) + sg[sz].offset);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
 		sz--;
 		oldpage = page - PAGE_SIZE;
diff -urN linux-2.5.2-pre11/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c
--- linux-2.5.2-pre11/arch/sparc/prom/ranges.c	Mon Dec 20 22:05:52 1999
+++ linux/arch/sparc/prom/ranges.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.14 1999/10/06 19:28:54 zaitcev Exp $
+/* $Id: ranges.c,v 1.15 2001/12/19 00:29:51 davem Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -16,26 +16,25 @@
 int num_obio_ranges;
 
 /* Adjust register values based upon the ranges parameters. */
-void
+static void
 prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
 		 struct linux_prom_ranges *rangep, int nranges)
 {
 	int regc, rngc;
 
-	for(regc=0; regc < nregs; regc++) {
-		for(rngc=0; rngc < nranges; rngc++)
-			if(regp[regc].which_io == rangep[rngc].ot_child_space &&
-			   regp[regc].phys_addr >= rangep[rngc].ot_child_base &&
-			   regp[regc].phys_addr + regp[regc].reg_size <= rangep[rngc].ot_child_base + rangep[rngc].or_size)
+	for (regc = 0; regc < nregs; regc++) {
+		for (rngc = 0; rngc < nranges; rngc++)
+			if (regp[regc].which_io == rangep[rngc].ot_child_space)
 				break; /* Fount it */
-		if(rngc==nranges) /* oops */
+		if (rngc == nranges) /* oops */
 			prom_printf("adjust_regs: Could not find range with matching bus type...\n");
 		regp[regc].which_io = rangep[rngc].ot_parent_space;
+		regp[regc].phys_addr -= rangep[rngc].ot_child_base;
 		regp[regc].phys_addr += rangep[rngc].ot_parent_base;
 	}
 }
 
-void
+static void
 prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
 		   struct linux_prom_ranges *ranges2, int nranges2)
 {
diff -urN linux-2.5.2-pre11/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- linux-2.5.2-pre11/arch/sparc64/Makefile	Sun Oct 21 10:36:54 2001
+++ linux/arch/sparc64/Makefile	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.49 2001/10/17 18:26:58 davem Exp $
+# $Id: Makefile,v 1.51 2001/11/17 00:15:27 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -38,11 +38,6 @@
 AS		:= $(AS) --undeclared-regs
 endif
 
-#
-# Uncomment the first CFLAGS if you are doing kgdb source level
-# debugging of the kernel to get the proper debugging information.
-
-#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 
 ifneq ($(NEW_GCC),y)
   CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
@@ -51,25 +46,6 @@
 	    -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \
 	    $(CC_UNDECL)
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
-endif
-
-# Uncomment this to get spinlock/rwlock debugging on SMP.
-# DEBUG_SPINLOCK = 1
-
-ifdef CONFIG_SMP
-  ifdef DEBUG_SPINLOCK
-    CFLAGS += -DSPIN_LOCK_DEBUG
-    AFLAGS += -DSPIN_LOCK_DEBUG
-  endif
-endif
-
-# Uncomment this to keep track of how often flush_dcache_page
-# actually flushes the caches, output via /proc/cpuinfo
-#
-# DEBUG_DCACHE_FLUSH = 1
-ifdef DEBUG_DCACHE_FLUSH
-  CFLAGS += -DDCFLUSH_DEBUG
-  AFLAGS += -DDCFLUSH_DEBUG
 endif
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
diff -urN linux-2.5.2-pre11/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.5.2-pre11/arch/sparc64/config.in	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc64/config.in	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.152 2001/11/12 10:20:47 davem Exp $
+# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -31,6 +31,8 @@
 # Identify this as a Sparc64 build
 define_bool CONFIG_SPARC64 y
 
+bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+
 # Global things across all Sun machines.
 define_bool CONFIG_HAVE_DEC_LOCK y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
@@ -89,7 +91,6 @@
 mainmenu_option next_comment
 comment 'Console drivers'
 bool 'PROM console' CONFIG_PROM_CONSOLE
-bool 'Support Frame buffer devices' CONFIG_FB
 source drivers/video/Config.in
 endmenu
 
@@ -191,21 +192,21 @@
       if [ "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then
          dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
          dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
-      fi
-      if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	 int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
-	 int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
-	 int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
-	 bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
-         if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
-	    bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+         if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+            int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
+            int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
+            int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
+            bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
+            if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
+	       bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+            fi
+            if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
+               bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+            fi
+            if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+               bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+            fi
          fi
-	 if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
-	    bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-	 fi
-	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '  assume boards are SYMBIOS compatible (EXPERIMENTAL)' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
-	 fi
       fi
       dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
       dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
@@ -295,6 +296,15 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+   bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE
+   bool '  D-cache flush debugging' CONFIG_DEBUG_DCFLUSH
+fi
+
 endmenu
+
+source lib/Config.in
diff -urN linux-2.5.2-pre11/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.5.2-pre11/arch/sparc64/defconfig	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc64/defconfig	Mon Jan 14 18:28:28 2002
@@ -22,6 +22,7 @@
 CONFIG_VT_CONSOLE=y
 CONFIG_SMP=y
 CONFIG_SPARC64=y
+CONFIG_HOTPLUG=y
 CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -84,7 +85,6 @@
 # Console drivers
 #
 CONFIG_PROM_CONSOLE=y
-CONFIG_FB=y
 
 #
 # Frame-buffer support
@@ -158,11 +158,11 @@
 #
 # Multi-device support (RAID and LVM)
 #
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
 # CONFIG_MD_RAID5 is not set
 # CONFIG_MD_MULTIPATH is not set
 # CONFIG_BLK_DEV_LVM is not set
@@ -174,8 +174,6 @@
 #
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
 CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -266,8 +264,8 @@
 # CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_BLK_DEV_IDETAPE=m
-CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 
 #
@@ -313,9 +311,9 @@
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
 CONFIG_BLK_DEV_IDE_MODES=y
-CONFIG_BLK_DEV_ATARAID=m
-CONFIG_BLK_DEV_ATARAID_PDC=m
-CONFIG_BLK_DEV_ATARAID_HPT=m
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
 
 #
 # SCSI support
@@ -354,15 +352,11 @@
 CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=m
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 CONFIG_SCSI_QLOGIC_ISP=m
 CONFIG_SCSI_QLOGIC_FC=y
 CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
@@ -470,6 +464,7 @@
 CONFIG_ADAPTEC_STARFIRE=m
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+CONFIG_DE2104X=m
 CONFIG_TULIP=m
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
@@ -493,6 +488,7 @@
 CONFIG_SUNDANCE=m
 # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
 CONFIG_WINBOND_840=m
 # CONFIG_NET_POCKET is not set
 
@@ -539,7 +535,7 @@
 CONFIG_NET_FC=y
 # CONFIG_IPHASE5526 is not set
 # CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+CONFIG_SHAPER=m
 
 #
 # Wan interfaces
@@ -603,7 +599,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-CONFIG_RAMFS=m
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
@@ -743,8 +739,9 @@
 # CONFIG_USB_LONG_TIMEOUT is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+CONFIG_USB_EHCI_HCD=m
 CONFIG_USB_UHCI=y
 # CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
@@ -789,6 +786,8 @@
 CONFIG_USB_OV511=m
 CONFIG_USB_PWC=m
 CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
 CONFIG_USB_DSBR=m
 CONFIG_USB_DABUSB=m
 
@@ -817,6 +816,7 @@
 CONFIG_USB_SERIAL_EMPEG=m
 CONFIG_USB_SERIAL_FTDI_SIO=m
 CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
 # CONFIG_USB_SERIAL_IR is not set
 CONFIG_USB_SERIAL_EDGEPORT=m
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
@@ -830,6 +830,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_KLSI=m
 CONFIG_USB_SERIAL_PL2303=m
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
@@ -839,6 +840,7 @@
 # USB Miscellaneous drivers
 #
 CONFIG_USB_RIO500=m
+CONFIG_USB_AUERSWALD=m
 
 #
 # Bluetooth support
@@ -861,4 +863,9 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- linux-2.5.2-pre11/arch/sparc64/kernel/Makefile	Wed May 16 10:31:27 2001
+++ linux/arch/sparc64/kernel/Makefile	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.67 2001/05/11 04:31:55 davem Exp $
+# $Id: Makefile,v 1.69 2001/11/19 04:09:53 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -68,7 +68,7 @@
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -95,12 +95,12 @@
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
 	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h
+	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -127,9 +127,9 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
-	$(CPP) $(CPPFLAGS) -DSPIN_LOCK_DEBUG tmp.c -o tmp.i
+	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
 	@echo "#include <linux/config.h>" >> check_asm_data.c
 	@echo "#undef CONFIG_SMP" >> check_asm_data.c
@@ -140,7 +140,7 @@
 	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
 	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
 	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
+	$(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
 	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
 	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
@@ -156,7 +156,7 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
 	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/central.c linux/arch/sparc64/kernel/central.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/central.c	Tue Oct  3 09:24:41 2000
+++ linux/arch/sparc64/kernel/central.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: central.c,v 1.14 2000/09/21 06:25:14 anton Exp $
+/* $Id: central.c,v 1.15 2001/12/19 00:29:51 davem Exp $
  * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  *
  * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
@@ -67,6 +67,7 @@
 		if (rngc == nranges) /* oops */
 			prom_printf("adjust_regs: Could not find range with matching bus type...\n");
 		regp[regc].which_io = rangep[rngc].ot_parent_space;
+		regp[regc].phys_addr -= rangep[rngc].ot_child_base;
 		regp[regc].phys_addr += rangep[rngc].ot_parent_base;
 	}
 }
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/check_asm.sh linux/arch/sparc64/kernel/check_asm.sh
--- linux-2.5.2-pre11/arch/sparc64/kernel/check_asm.sh	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/check_asm.sh	Mon Jan 14 18:28:28 2002
@@ -1,12 +1,12 @@
 #!/bin/sh
 case $1 in
   -printf)
-    sed -n -e '/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
+    sed -n -e '/^#/d;/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
 /g' | sed 's/^[ 	*]*//;s/[ 	]*$//;s/^.*$/printf ("#define AOFF_'$2'_\0	0x%08x\\n", check_asm_data[i++]); printf("#define ASIZ_'$2'_\0	0x%08x\\n", check_asm_data[i++]);/' >> $4
     echo "printf (\"#define ASIZ_$2\\t0x%08x\\n\", check_asm_data[i++]);" >> $4
   ;;
   -data)
-    sed -n -e '/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
+    sed -n -e '/^#/d;/struct[ 	]*'$2'_struct[ 	]*{/,/};/p' < $3 | sed '/struct[ 	]*'$2'_struct[ 	]*{/d;/:[0-9]*[ 	]*;/d;/^[ 	]*$/d;/};/d;s/^[ 	]*//;s/volatile[ 	]*//;s/\(unsigned\|signed\|struct\)[ 	]*//;s/\(\[\|__attribute__\).*;[ 	]*$//;s/(\*//;s/)(.*)//;s/;[ 	]*$//;s/^[^ 	]*[ 	]*//;s/,/\
 /g' | sed 's/^[ 	*]*//;s/[ 	]*$//;s/^.*$/	((char *)\&((struct '$2'_struct *)0)->\0) - ((char *)((struct '$2'_struct *)0)),	sizeof(((struct '$2'_struct *)0)->\0),/' >> $4
     echo "	sizeof(struct $2_struct)," >> $4
   ;;
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/chmc.c linux/arch/sparc64/kernel/chmc.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/chmc.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/kernel/chmc.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $
+/* $Id: chmc.c,v 1.4 2002/01/08 16:00:14 davem Exp $
  * memctrlr.c: Driver for UltraSPARC-III memory controller.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -9,6 +9,10 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
 #include <linux/init.h>
 #include <asm/spitfire.h>
 #include <asm/chmctrl.h>
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- linux-2.5.2-pre11/arch/sparc64/kernel/entry.S	Sun Oct 21 10:36:54 2001
+++ linux/arch/sparc64/kernel/entry.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.137 2001/10/18 09:06:36 davem Exp $
+/* $Id: entry.S,v 1.141 2001/12/05 23:56:32 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -483,7 +483,11 @@
 	ldxa		[%g7 + %g0] ASI_INTR_R, %g7
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
-	jmpl		%g3, %g0
+	ba,pt		%xcc, 1f
+	 nop
+
+	.align		32
+1:	jmpl		%g3, %g0
 	 nop
 
 do_ivec_spurious:
@@ -657,15 +661,15 @@
 	stx		%g5, [%g1 + %lo(pdma_size)]
 	sethi		%hi(auxio_register), %g1
 	ldx		[%g1 + %lo(auxio_register)], %g7
-	ldub		[%g7], %g5
+	lduba		[%g7] ASI_PHYS_BYPASS_EC_E, %g5
 	or		%g5, 0xc2, %g5
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	andn		%g5, 0x02, %g5
 
 	nop; nop;  nop; nop;  nop; nop;
 	nop; nop;  nop; nop;  nop; nop;
 
-	stb		%g5, [%g7]
+	stba		%g5, [%g7] ASI_PHYS_BYPASS_EC_E
 	sethi		%hi(doing_pdma), %g1
 	b,pt		%xcc, floppy_dosoftint
 	 st		%g0, [%g1 + %lo(doing_pdma)]
@@ -678,7 +682,12 @@
 	sethi		%hi(irq_action), %g1
 	or		%g1, %lo(irq_action), %g1
 	ldx		[%g1 + (11 << 3)], %g3		! irqaction[floppy_irq]
-	ldx		[%g3 + 0x10], %g4		! action->mask == ino_bucket ptr
+	ldx		[%g3 + 0x08], %g4		! action->flags>>48==ino
+	sethi		%hi(ivector_table), %g3
+	srlx		%g4, 48, %g4
+	or		%g3, %lo(ivector_table), %g3
+	sllx		%g4, 5, %g4
+	ldx		[%g3 + %g4], %g4		! &ivector_table[ino]
 	ldx		[%g4 + 0x10], %g4		! bucket->iclr
 	stwa		%g0, [%g4] ASI_PHYS_BYPASS_EC_E	! ICLR_IDLE
 	membar		#Sync				! probably not needed...
@@ -1615,6 +1624,11 @@
 	 *
 	 * Note with time_t changes to the timeval type, I must now use
 	 * nucleus atomic quad 128-bit loads.
+	 *
+	 * If xtime was stored recently, I've seen crap from the
+	 * quad load on Cheetah.  Putting a membar SYNC before
+	 * the quad load seems to make the problem go away. -DaveM
+	 * (we should nop out workarounds like this on spitfire)
 	 */
 	sethi	%hi(timer_tick_offset), %g3
 	sethi	%hi(xtime), %g2
@@ -1626,6 +1640,7 @@
 	sethi	%hi(0x003e0014), %o1
 	srlx	%o2, 32, %o2
 	or	%o1, %lo(0x003e0014), %o1
+	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
 	cmp	%o2, %o1
 	bne,pt	%xcc, 2f
@@ -1634,6 +1649,7 @@
 	 rd	%asr24, %o1
 2:	rd	%tick, %o1
 3:	ldx	[%g1], %g7
+	membar	#Sync
 	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o2
 	xor	%o4, %o2, %o2
 	xor	%o5, %o3, %o3
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/ioctl32.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.132 2001/11/07 05:56:19 davem Exp $
+/* $Id: ioctl32.c,v 1.135 2002/01/11 08:45:38 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -472,6 +472,7 @@
 		return -ENODEV;
 
 	strcpy(ifr32.ifr_name, dev->name);
+	dev_put(dev);
 
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
@@ -2421,6 +2422,7 @@
 	u32 pv[ABS_MAX_PV + 1];
 	u32 lv[ABS_MAX_LV + 1];
     	uint8_t vg_uuid[UUID_LEN+1];	/* volume group UUID */
+	uint8_t dummy1[200];
 } vg32_t;
 
 typedef struct {
@@ -2462,7 +2464,7 @@
 } lv_status_byindex_req32_t;
 
 typedef struct {
-	dev_t dev;
+	__kernel_dev_t32 dev;
 	u32   lv;
 } lv_status_bydev_req32_t;
 
@@ -2535,7 +2537,8 @@
 	lv_block_exception32_t *lbe32;
 	lv_block_exception_t *lbe;
 	lv32_t *ul = (lv32_t *)A(p);
-	lv_t *l = (lv_t *)kmalloc(sizeof(lv_t), GFP_KERNEL);
+	lv_t *l = (lv_t *) kmalloc(sizeof(lv_t), GFP_KERNEL);
+
 	if (!l) {
 		*errp = -ENOMEM;
 		return NULL;
@@ -2565,12 +2568,11 @@
 		if (l->lv_block_exception) {
 			lbe32 = (lv_block_exception32_t *)A(ptr2);
 			memset(lbe, 0, size);
-                       for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
-                               err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
-                               err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
-                               err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
-                               err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
-
+			for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+				err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+				err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+				err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+				err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
 			}
 		}
 	}
@@ -2608,7 +2610,7 @@
 
 static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	vg_t *v;
+	vg_t *v = NULL;
 	union {
 		lv_req_t lv_req;
 		le_remap_req_t le_remap;
@@ -2626,17 +2628,22 @@
 	switch (cmd) {
 	case VG_STATUS:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
+		if (!v)
+			return -ENOMEM;
 		karg = v;
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
 		v = kmalloc(sizeof(vg_t), GFP_KERNEL);
-		if (!v) return -ENOMEM;
-		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc) ||
-		    __get_user(v->proc, &((vg32_t *)arg)->proc)) {
+		if (!v)
+			return -ENOMEM;
+		if (copy_from_user(v, (void *)arg, (long)&((vg32_t *)0)->proc)) {
 			kfree(v);
 			return -EFAULT;
 		}
+		/* 'proc' field is unused, just NULL it out. */
+		v->proc = NULL;
 		if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
 			kfree(v);
 			return -EFAULT;
@@ -2648,39 +2655,46 @@
 			return -EPERM;
 		for (i = 0; i < v->pv_max; i++) {
 			err = __get_user(ptr, &((vg32_t *)arg)->pv[i]);
-			if (err) break;
+			if (err)
+				break;
 			if (ptr) {
 				v->pv[i] = kmalloc(sizeof(pv_t), GFP_KERNEL);
 				if (!v->pv[i]) {
 					err = -ENOMEM;
 					break;
 				}
-				err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
+				err = copy_from_user(v->pv[i], (void *)A(ptr),
+						     sizeof(pv32_t) - 8 - UUID_LEN+1);
 				if (err) {
 					err = -EFAULT;
 					break;
 				}
-				err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+				err = copy_from_user(v->pv[i]->pv_uuid,
+						     ((pv32_t *)A(ptr))->pv_uuid,
+						     UUID_LEN+1);
 				if (err) {
 				        err = -EFAULT;
 					break;
 				}
 
-				
-				v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
+				v->pv[i]->pe = NULL;
+				v->pv[i]->bd = NULL;
 			}
 		}
 		if (!err) {
 			for (i = 0; i < v->lv_max; i++) {
 				err = __get_user(ptr, &((vg32_t *)arg)->lv[i]);
-				if (err) break;
+				if (err)
+					break;
 				if (ptr) {
 					v->lv[i] = get_lv_t(ptr, &err);
-					if (err) break;
+					if (err)
+						break;
 				}
 			}
 		}
 		break;
+
 	case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
@@ -2688,54 +2702,70 @@
 	case LV_RENAME:
 	case LV_STATUS_BYNAME:
 	        err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		if (cmd != LV_REMOVE) {
 			err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
-			if (err) return err;
+			if (err)
+				return err;
 			u.lv_req.lv = get_lv_t(ptr, &err);
 		} else
 			u.lv_req.lv = NULL;
 		break;
 
-
 	case LV_STATUS_BYINDEX:
-		err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
+		err = get_user(u.lv_byindex.lv_index,
+			       &((lv_status_byindex_req32_t *)arg)->lv_index);
 		err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.lv_byindex.lv = get_lv_t(ptr, &err);
 		break;
+
 	case LV_STATUS_BYDEV:
 	        err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+		err |= __get_user(ptr, &((lv_status_bydev_req32_t *)arg)->lv);
+		if (err)
+			return err;
 		u.lv_bydev.lv = get_lv_t(ptr, &err);
-		if (err) return err;
-		u.lv_bydev.lv = &p;
-		p.pe = NULL; p.inode = NULL;		
-		break;		
+		break;
+
 	case VG_EXTEND:
 		err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
-		if (err) return -EFAULT;
-		p.pe = NULL; p.inode = NULL;
+		if (err)
+			return -EFAULT;
+		p.pe = NULL;
+		p.bd = NULL;
 		karg = &p;
 		break;
+
 	case PV_CHANGE:
 	case PV_STATUS:
 		err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
-		if (err) return -EFAULT;
+		if (err)
+			return -EFAULT;
 		err = __get_user(ptr, &((pv_status_req32_t *)arg)->pv);
-		if (err) return err;
+		if (err)
+			return err;
 		u.pv_status.pv = &p;
 		if (cmd == PV_CHANGE) {
-			err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
-			p.pe = NULL; p.inode = NULL;
+			err = copy_from_user(&p, (void *)A(ptr),
+					     sizeof(pv32_t) - 8 - UUID_LEN+1);
+			if (err)
+				return -EFAULT;
+			p.pe = NULL;
+			p.bd = NULL;
 		}
 		break;
-	}
+	};
+
         old_fs = get_fs(); set_fs (KERNEL_DS);
         err = sys_ioctl (fd, cmd, (unsigned long)karg);
         set_fs (old_fs);
+
 	switch (cmd) {
 	case VG_STATUS:
 		if (!err) {
@@ -2748,42 +2778,60 @@
 		}
 		kfree(v);
 		break;
+
+	case VG_CREATE_OLD:
 	case VG_CREATE:
-		for (i = 0; i < v->pv_max; i++)
-			if (v->pv[i]) kfree(v->pv[i]);
-		for (i = 0; i < v->lv_max; i++)
-			if (v->lv[i]) put_lv_t(v->lv[i]);
+		for (i = 0; i < v->pv_max; i++) {
+			if (v->pv[i])
+				kfree(v->pv[i]);
+		}
+		for (i = 0; i < v->lv_max; i++) {
+			if (v->lv[i])
+				put_lv_t(v->lv[i]);
+		}
 		kfree(v);
 		break;
+
 	case LV_STATUS_BYNAME:
-		if (!err && u.lv_req.lv) err = copy_lv_t(ptr, u.lv_req.lv);
+		if (!err && u.lv_req.lv)
+			err = copy_lv_t(ptr, u.lv_req.lv);
 		/* Fall through */
+
         case LV_CREATE:
 	case LV_EXTEND:
 	case LV_REDUCE:
-		if (u.lv_req.lv) put_lv_t(u.lv_req.lv);
+		if (u.lv_req.lv)
+			put_lv_t(u.lv_req.lv);
 		break;
+
 	case LV_STATUS_BYINDEX:
 		if (u.lv_byindex.lv) {
-			if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_byindex.lv);
 			put_lv_t(u.lv_byindex.lv);
 		}
 		break;
+
+	case LV_STATUS_BYDEV:
+	        if (u.lv_bydev.lv) {
+			if (!err)
+				err = copy_lv_t(ptr, u.lv_bydev.lv);
+			put_lv_t(u.lv_byindex.lv);
+	        }
+	        break;
+
 	case PV_STATUS:
 		if (!err) {
 			err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 			err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
-			if (err) return -EFAULT;
+			if (err)
+				return -EFAULT;
 		}
 		break;
-	case LV_STATUS_BYDEV:
-	        if (!err) {
-			if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv);
-			put_lv_t(u.lv_byindex.lv);
-	        }
-	        break;
-	}
+	};
+
 	return err;
 }
 #endif
@@ -3379,11 +3427,11 @@
 }
 
 struct usbdevfs_ctrltransfer32 {
-	__u8 requesttype;
-	__u8 request;
-	__u16 value;
-	__u16 index;
-	__u16 length;
+	__u8 bRequestType;
+	__u8 bRequest;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
 	__u32 timeout;  /* in milliseconds */
 	__u32 data;
 };
@@ -3413,14 +3461,14 @@
 	/* In usbdevice_fs, it limits the control buffer to a page,
 	 * for simplicity so do we.
 	 */
-	if (!uptr || kctrl.length > PAGE_SIZE)
+	if (!uptr || kctrl.wLength > PAGE_SIZE)
 		return -EINVAL;
 
 	kptr = (void *)__get_free_page(GFP_KERNEL);
 
-	if ((kctrl.requesttype & 0x80) == 0) {
+	if ((kctrl.bRequestType & 0x80) == 0) {
 		err = -EFAULT;
-		if (copy_from_user(kptr, uptr, kctrl.length))
+		if (copy_from_user(kptr, uptr, kctrl.wLength))
 			goto out;
 	}
 
@@ -3432,8 +3480,8 @@
 	set_fs(old_fs);
 
 	if (err >= 0 &&
-	    ((kctrl.requesttype & 0x80) != 0)) {
-		if (copy_to_user(uptr, kptr, kctrl.length))
+	    ((kctrl.bRequestType & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.wLength))
 			err = -EFAULT;
 	}
 
@@ -4666,6 +4714,7 @@
 HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
 HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl)
 HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl)
 HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
@@ -4675,6 +4724,7 @@
 HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
 #endif /* LVM */
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/iommu_common.c	Sun Dec 16 12:20:20 2001
+++ linux/arch/sparc64/kernel/iommu_common.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.c,v 1.8 2001/12/11 11:13:06 davem Exp $
+/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $
  * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -66,9 +66,7 @@
 
 	daddr = dma_sg->dma_address;
 	sglen = sg->length;
-	sgaddr = (unsigned long) (sg->address ?
-				  sg->address :
-				  page_address(sg->page) + sg->offset);
+	sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
 	while (dlen > 0) {
 		unsigned long paddr;
 
@@ -118,9 +116,7 @@
 		sg++;
 		if (--nents <= 0)
 			break;
-		sgaddr = (unsigned long) (sg->address ?
-					  sg->address :
-					  page_address(sg->page) + sg->offset);
+		sgaddr = (unsigned long) (page_address(sg->page) + sg->offset);
 		sglen = sg->length;
 	}
 	if (dlen < 0) {
@@ -183,10 +179,11 @@
 		printk("%016lx.\n", sg->dma_address & IO_PAGE_MASK);
 
 		for (i = 0; i < nents; i++) {
-			printk("sg(%d): address(%p) length(%x) "
+			printk("sg(%d): page_addr(%p) off(%x) length(%x) "
 			       "dma_address[%016lx] dma_length[%016lx]\n",
 			       i,
-			       sg[i].address, sg[i].length,
+			       page_address(sg[i].page), sg[i].offset,
+			       sg[i].length,
 			       sg[i].dma_address, sg[i].dma_length);
 		}
 	}
@@ -201,21 +198,15 @@
 	unsigned long prev;
 	u32 dent_addr, dent_len;
 
-	prev  = (unsigned long) (sg->address ?
-				 sg->address :
-				 page_address(sg->page) + sg->offset);
+	prev  = (unsigned long) (page_address(sg->page) + sg->offset);
 	prev += (unsigned long) (dent_len = sg->length);
-	dent_addr = (u32) ((unsigned long)(sg->address ?
-					   sg->address :
-					   page_address(sg->page) + sg->offset)
+	dent_addr = (u32) ((unsigned long)(page_address(sg->page) + sg->offset)
 			   & (IO_PAGE_SIZE - 1UL));
 	while (--nents) {
 		unsigned long addr;
 
 		sg++;
-		addr = (unsigned long) (sg->address ?
-					sg->address :
-					page_address(sg->page) + sg->offset);
+		addr = (unsigned long) (page_address(sg->page) + sg->offset);
 		if (! VCONTIG(prev, addr)) {
 			dma_sg->dma_address = dent_addr;
 			dma_sg->dma_length = dent_len;
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/irq.c	Wed Nov 28 13:22:26 2001
+++ linux/arch/sparc64/kernel/irq.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.109 2001/11/12 22:22:37 davem Exp $
+/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -35,6 +36,7 @@
 #include <asm/softirq.h>
 #include <asm/starfire.h>
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -53,10 +55,10 @@
  * at the same time.
  */
 
-struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
+struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 #ifndef CONFIG_SMP
-unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
+unsigned int __up_workvec[16] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 #define irq_work(__cpu, __pil)	&(__up_workvec[(void)(__cpu), (__pil)])
 #else
 #define irq_work(__cpu, __pil)	&(cpu_data[(__cpu)].irq_worklists[(__pil)])
@@ -116,19 +118,19 @@
 	for(i = 0; i < (NR_IRQS + 1); i++) {
 		if(!(action = *(i + irq_action)))
 			continue;
-		seq_print(p, "%3d: ", i);
+		seq_printf(p, "%3d: ", i);
 #ifndef CONFIG_SMP
-		seq_print(p, "%10u ", kstat_irqs(i));
+		seq_printf(p, "%10u ", kstat_irqs(i));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
-			seq_print(p, "%10u ",
-				       kstat.irqs[cpu_logical_map(j)][i]);
+			seq_printf(p, "%10u ",
+				   kstat.irqs[cpu_logical_map(j)][i]);
 #endif
-		seq_print(p, " %s:%lx", action->name,
-						get_ino_in_irqaction(action));
+		seq_printf(p, " %s:%lx", action->name,
+			   get_ino_in_irqaction(action));
 		for(action = action->next; action; action = action->next) {
-			seq_print(p, ", %s:%lx", action->name,
-						get_ino_in_irqaction(action));
+			seq_printf(p, ", %s:%lx", action->name,
+				   get_ino_in_irqaction(action));
 		}
 		seq_putc(p, '\n');
 	}
@@ -161,7 +163,7 @@
 		tid = ((tid & UPA_CONFIG_MID) << 9);
 		tid &= IMAP_TID_UPA;
 	} else {
-		tid = (starfire_translate(imap, current->processor) << 26);
+		tid = (starfire_translate(imap, smp_processor_id()) << 26);
 		tid &= IMAP_TID_UPA;
 	}
 
@@ -823,6 +825,11 @@
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
 
+#ifdef CONFIG_PCI
+	if (irq == 9)
+		kbd_pt_regs = regs;
+#endif
+
 	/* Sliiiick... */
 #ifndef CONFIG_SMP
 	bp = ((irq != 0) ?
@@ -1246,19 +1253,15 @@
 	prom_timers->count0 = 0;
 }
 
+/* Only invoked on boot processor. */
 void __init init_IRQ(void)
 {
-	static int called = 0;
-
-	if (called == 0) {
-		called = 1;
-		map_prom_timers();
-		kill_prom_timer();
-		memset(&ivector_table[0], 0, sizeof(ivector_table));
+	map_prom_timers();
+	kill_prom_timer();
+	memset(&ivector_table[0], 0, sizeof(ivector_table));
 #ifndef CONFIG_SMP
-		memset(&__up_workvec[0], 0, sizeof(__up_workvec));
+	memset(&__up_workvec[0], 0, sizeof(__up_workvec));
 #endif
-	}
 
 	/* We need to clear any IRQ's pending in the soft interrupt
 	 * registers, a spurious one could be left around from the
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/pci_iommu.c	Fri Oct 12 15:35:53 2001
+++ linux/arch/sparc64/kernel/pci_iommu.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.16 2001/10/09 02:24:33 davem Exp $
+/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $
  * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -425,9 +425,7 @@
 }
 
 #define SG_ENT_PHYS_ADDRESS(SG)	\
-	((SG)->address ? \
-	 __pa((SG)->address) : \
-	 (__pa(page_address((SG)->page)) + (SG)->offset))
+	(__pa(page_address((SG)->page)) + (SG)->offset)
 
 static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
 			   int nused, int nelems, unsigned long iopte_protection)
@@ -522,9 +520,7 @@
 	if (nelems == 1) {
 		sglist->dma_address =
 			pci_map_single(pdev,
-				       (sglist->address ?
-					sglist->address :
-					(page_address(sglist->page) + sglist->offset)),
+				       (page_address(sglist->page) + sglist->offset),
 				       sglist->length, direction);
 		sglist->dma_length = sglist->length;
 		return 1;
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/pci_psycho.c	Fri Oct 12 15:35:53 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.29 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 
 #include <asm/pbm.h>
+#include <asm/fhc.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/starfire.h>
@@ -371,6 +372,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
@@ -1479,8 +1481,7 @@
 {
 	unsigned int busrange[2];
 	struct pci_pbm_info *pbm;
-	char namebuf[64];
-	int err, len;
+	int err;
 
 	if (is_pbm_a) {
 		pbm = &p->pbm_A;
@@ -1489,13 +1490,9 @@
 		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A;
 	} else {
 		pbm = &p->pbm_B;
-		pbm->pci_first_slot = 1;
-		len = prom_getproperty(prom_root_node, "name",
-				       namebuf, sizeof(namebuf));
-		if (len > 0) {
-			if (!strcmp(namebuf, "SUNW,Ultra-1-Engine"))
-				pbm->pci_first_slot = 2;
-		}
+		pbm->pci_first_slot = 2;
+		if (central_bus != NULL)
+			pbm->pci_first_slot = 1;
 		pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B;
 		pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B;
 	}
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/pci_sabre.c	Fri Oct 12 15:35:53 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.40 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -589,6 +589,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = sabre_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -609,6 +614,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/pci_schizo.c	Fri Oct 12 15:35:53 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.22 2001/10/11 00:44:38 davem Exp $
+/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -337,6 +337,11 @@
 {
 	int ret;
 
+	if (pdev &&
+	    pdev->vendor == PCI_VENDOR_ID_SUN &&
+	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
+		return 9;
+
 	ret = schizo_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
 		ret = 1;
@@ -357,6 +362,7 @@
 		case PCI_BASE_CLASS_MULTIMEDIA:
 		case PCI_BASE_CLASS_MEMORY:
 		case PCI_BASE_CLASS_BRIDGE:
+		case PCI_BASE_CLASS_SERIAL:
 			ret = 10;
 			break;
 
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/power.c	Tue Jun 12 11:08:46 2001
+++ linux/arch/sparc64/kernel/power.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: power.c,v 1.9 2001/06/08 02:28:22 davem Exp $
+/* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $
  * power.c: Power management driver.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -61,7 +61,7 @@
 	sprintf(current->comm, "powerd");
 
 again:
-	while(button_pressed == 0) {
+	while (button_pressed == 0) {
 		spin_lock_irq(&current->sigmask_lock);
 		flush_signals(current);
 		spin_unlock_irq(&current->sigmask_lock);
@@ -98,16 +98,19 @@
 found:
 	power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
 	printk("power: Control reg at %016lx ... ", power_reg);
-	if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
-		printk("Failed to start power daemon.\n");
-		return;
-	}
-	printk("powerd running.\n");
-	if (edev->irqs[0] != 0) {
+	if (edev->irqs[0] != PCI_IRQ_NONE) {
+		if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
+			printk("Failed to start power daemon.\n");
+			return;
+		}
+		printk("powerd running.\n");
+
 		if (request_irq(edev->irqs[0],
 				power_handler, SA_SHIRQ, "power",
 				(void *) power_reg) < 0)
 			printk("power: Error, cannot register IRQ handler.\n");
+	} else {
+		printk("not using powerd.\n");
 	}
 }
 #endif /* CONFIG_PCI */
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/process.c	Mon Jan 14 18:28:22 2002
+++ linux/arch/sparc64/kernel/process.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.122 2001/10/18 09:06:36 davem Exp $
+/*  $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -53,9 +53,6 @@
 		return -EPERM;
 
 	/* endless idle loop with no priority at all */
-	current->nice = 20;
-	init_idle();
-
 	for (;;) {
 		/* If current->need_resched is zero we should really
 		 * setup for a system wakup event and execute a shutdown
@@ -78,13 +75,10 @@
 /*
  * the idle loop on a UltraMultiPenguin...
  */
-#define idle_me_harder()	(cpu_data[current->processor].idle_volume += 1)
-#define unidle_me()		(cpu_data[current->processor].idle_volume = 0)
+#define idle_me_harder()	(cpu_data[smp_processor_id()].idle_volume += 1)
+#define unidle_me()		(cpu_data[smp_processor_id()].idle_volume = 0)
 int cpu_idle(void)
 {
-	current->nice = 20;
-	init_idle();
-
 	while(1) {
 		if (current->need_resched != 0) {
 			unidle_me();
@@ -274,7 +268,12 @@
 #ifdef CONFIG_SMP
 	unsigned long flags;
 
-	spin_lock_irqsave(&regdump_lock, flags);
+	/* Protect against xcall ipis which might lead to livelock on the lock */
+	__asm__ __volatile__("rdpr      %%pstate, %0\n\t"
+			     "wrpr      %0, %1, %%pstate"
+			     : "=r" (flags)
+			     : "i" (PSTATE_IE));
+	spin_lock(&regdump_lock);
 	printk("CPU[%d]: local_irq_count[%u] irqs_running[%d]\n",
 	       smp_processor_id(),
 	       local_irq_count(smp_processor_id()),
@@ -296,7 +295,9 @@
 	       regs->u_regs[15]);
 	show_regwindow(regs);
 #ifdef CONFIG_SMP
-	spin_unlock_irqrestore(&regdump_lock, flags);
+	spin_unlock(&regdump_lock);
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (flags));
 #endif
 }
 
@@ -462,6 +463,7 @@
 		csp += STACK_BIAS;
 		psp += STACK_BIAS;
 		__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
+		fp += STACK_BIAS;
 	} else
 		__get_user(fp, &(((struct reg_window32 *)psp)->ins[6]));
 
@@ -581,6 +583,11 @@
 {
 	struct thread_struct *t = &p->thread;
 	char *child_trap_frame;
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+	t->smp_lock_count = 0;
+	t->smp_lock_pc = 0;
+#endif
 
 	/* Calculate offset to stack_frame & pt_regs */
 	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- linux-2.5.2-pre11/arch/sparc64/kernel/rtrap.S	Wed Oct 17 14:16:39 2001
+++ linux/arch/sparc64/kernel/rtrap.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.56 2001/10/13 00:14:34 kanoj Exp $
+/* $Id: rtrap.S,v 1.59 2002/01/11 08:45:38 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -18,14 +18,13 @@
 #define		RTRAP_PSTATE_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
 #define		RTRAP_PSTATE_AG_IRQOFF	(PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
 
-#if 0
-#define		RTRAP_CHECK		call rtrap_check;  add %sp, (STACK_BIAS+REGWIN_SZ), %o0;
-#else
-#define		RTRAP_CHECK
-#endif
+		/* Register %l6 keeps track of whether we are returning
+		 * from a system call or not.  It is cleared if we call
+		 * do_signal, and it must not be otherwise modified until
+		 * we fully commit to returning to userspace.
+		 */
 
 		.text
-
 		.align			32
 __handle_softirq:
 		call			do_softirq
@@ -34,42 +33,100 @@
 		 nop
 __handle_preemption:
 		call			schedule
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		ba,pt			%xcc, __handle_preemption_continue
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+
 __handle_user_windows:
-		wrpr			%g0, RTRAP_PSTATE, %pstate
 		call			fault_in_user_windows
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		/* Redo sched+sig checks */
+		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brz,pt			%l0, 1f
 		 nop
-		ba,pt			%xcc, __handle_user_windows_continue
+		call			schedule
+
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		lduw			[%g6 + AOFF_task_sigpending], %l0
+		brz,pt			%l0, __handle_user_windows_continue
 		 nop
+		clr			%o0
+		mov			%l5, %o2
+		mov			%l6, %o3
+
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		call			do_signal
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		clr			%l6
+		/* Signal delivery can modify pt_regs tstate, so we must
+		 * reload it.
+		 */
+		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+		sethi			%hi(0xf << 20), %l4
+		and			%l1, %l4, %l4
+
+		ba,pt			%xcc, __handle_user_windows_continue
+		 andn			%l1, %l4, %l1
 __handle_perfctrs:
-		/* Don't forget to preserve user window invariants. */
-		wrpr			%g0, RTRAP_PSTATE, %pstate
 		call			update_perfctrs
-		 nop
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
-		brz,pt			%o2, __handle_perfctrs_continue
-		 sethi			%hi(TSTATE_PEF), %l6
-		wrpr			%g0, RTRAP_PSTATE, %pstate
+		brz,pt			%o2, 1f
+		 nop
 
+		/* Redo userwin+sched+sig checks */
 		call			fault_in_user_windows
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brz,pt			%l0, 1f
 		 nop
+		call			schedule
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+1:		lduw			[%g6 + AOFF_task_sigpending], %l0
+		brz,pt			%l0, __handle_perfctrs_continue
+		 sethi			%hi(TSTATE_PEF), %o0
+		clr			%o0
+		mov			%l5, %o2
+		mov			%l6, %o3
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+
+		call			do_signal
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
+		clr			%l6
+		/* Signal delivery can modify pt_regs tstate, so we must
+		 * reload it.
+		 */
+		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+		sethi			%hi(0xf << 20), %l4
+		and			%l1, %l4, %l4
+		andn			%l1, %l4, %l1
+
 		ba,pt			%xcc, __handle_perfctrs_continue
-		 nop
+		 sethi			%hi(TSTATE_PEF), %o0
 __handle_userfpu:
 		rd			%fprs, %l5
 		andcc			%l5, FPRS_FEF, %g0
+		sethi			%hi(TSTATE_PEF), %o0
 		be,a,pn			%icc, __handle_userfpu_continue
-		 andn			%l1, %l6, %l1
+		 andn			%l1, %o0, %l1
 		ba,a,pt			%xcc, __handle_userfpu_continue
+
 __handle_signal:
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
+		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
 		call			do_signal
-		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		 wrpr			%g0, RTRAP_PSTATE, %pstate
+		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		clr			%l6
 
 		/* Signal delivery can modify pt_regs tstate, so we must
@@ -84,7 +141,7 @@
 		.align			64
 		.globl			rtrap_clr_l6, rtrap, irqsz_patchme
 rtrap_clr_l6:	clr			%l6
-rtrap:		lduw			[%g6 + AOFF_task_processor], %l0
+rtrap:		lduw			[%g6 + AOFF_task_cpu], %l0
 		sethi			%hi(irq_stat), %l2	! &softirq_active
 		or			%l2, %lo(irq_stat), %l2	! &softirq_active
 irqsz_patchme:	sllx			%l0, 0, %l0
@@ -99,29 +156,43 @@
 		and			%l1, %l4, %l4
 		bne,pn			%icc, to_kernel
 		 andn			%l1, %l4, %l1
-to_user:	ldx			[%g6 + AOFF_task_need_resched], %l0
 
-		brnz,pn			%l0, __handle_preemption
+		/* We must hold IRQs off and atomically test schedule+signal
+		 * state, then hold them off all the way back to userspace.
+		 * If we are returning to kernel, none of this matters.
+		 *
+		 * If we do not do this, there is a window where we would do
+		 * the tests, later the signal/resched event arrives but we do
+		 * not process it since we are still in kernel mode.  It would
+		 * take until the next local IRQ before the signal/resched
+		 * event would be handled.
+		 *
+		 * This also means that if we have to deal with performance
+		 * counters or user windows, we have to redo all of these
+		 * sched+signal checks with IRQs disabled.
+		 */
+to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 __handle_preemption_continue:
+		ldx			[%g6 + AOFF_task_need_resched], %l0
+		brnz,pn			%l0, __handle_preemption
 		 lduw			[%g6 + AOFF_task_sigpending], %l0
 		brnz,pn			%l0, __handle_signal
 		 nop
 __handle_signal_continue:
-check_user_wins:
-		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
 		brnz,pn			%o2, __handle_user_windows
-		 sethi			%hi(TSTATE_PEF), %l6
-
+		 nop
 __handle_user_windows_continue:
-		RTRAP_CHECK
 		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
 		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
+		sethi			%hi(TSTATE_PEF), %o0
 		bne,pn			%xcc, __handle_perfctrs
 __handle_perfctrs_continue:
-		 andcc			%l1, %l6, %g0
+		 andcc			%l1, %o0, %g0
+
+		/* This fpdepth clear is neccessary for non-syscall rtraps only */
 		bne,pn			%xcc, __handle_userfpu
-		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
 __handle_userfpu_continue:
 
 rt_continue:	ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/sbus.c	Fri Oct 12 15:35:53 2001
+++ linux/arch/sparc64/kernel/sbus.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.17 2001/10/09 02:24:33 davem Exp $
+/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -377,9 +377,7 @@
 }
 
 #define SG_ENT_PHYS_ADDRESS(SG)	\
-	((SG)->address ? \
-	 __pa((SG)->address) : \
-	 (__pa(page_address((SG)->page)) + (SG)->offset))
+	(__pa(page_address((SG)->page)) + (SG)->offset)
 
 static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits)
 {
@@ -470,9 +468,7 @@
 	if (nents == 1) {
 		sg->dma_address =
 			sbus_map_single(sdev,
-					(sg->address ?
-					 sg->address :
-					 (page_address(sg->page) + sg->offset)),
+					(page_address(sg->page) + sg->offset),
 					sg->length, dir);
 		sg->dma_length = sg->length;
 		return 1;
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/semaphore.c	Sun May 20 11:32:07 2001
+++ linux/arch/sparc64/kernel/semaphore.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.8 2001/05/18 08:01:35 davem Exp $
+/* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
  * semaphore.c: Sparc64 semaphore implementation.
  *
  * This is basically the PPC semaphore scheme ported to use
@@ -31,7 +31,7 @@
 "	cas	[%3], %0, %1\n"
 "	cmp	%0, %1\n"
 "	bne,pn	%%icc, 1b\n"
-"	 nop\n"
+"	 membar #StoreLoad | #StoreStore\n"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
 	: "cc");
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/signal.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc64/kernel/signal.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.56 2001/03/21 11:46:20 davem Exp $
+/*  $Id: signal.c,v 1.57 2001/12/11 04:55:51 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -17,6 +17,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/tty.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/signal32.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/signal32.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.70 2001/04/24 01:09:12 davem Exp $
+/*  $Id: signal32.c,v 1.71 2001/12/11 04:55:51 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
+#include <linux/tty.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/smp.c	Mon Jan 14 18:28:22 2002
+++ linux/arch/sparc64/kernel/smp.c	Mon Jan 14 18:28:28 2002
@@ -209,23 +209,10 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
-	while (!smp_processors_ready)
+	while (!smp_threads_ready)
 		membar("#LoadLoad");
-}
-
-extern int cpu_idle(void);
-extern void init_IRQ(void);
 
-void initialize_secondary(void)
-{
-}
-
-int start_secondary(void *unused)
-{
-	trap_init();
-	init_IRQ();
-	smp_callin();
-	return cpu_idle();
+	init_idle();
 }
 
 void cpu_panic(void)
@@ -251,7 +238,6 @@
 	printk("Entering UltraSMPenguin Mode...\n");
 	__sti();
 	smp_store_cpu_info(boot_cpu_id);
-	init_idle();
 
 	if (linux_num_cpus == 1)
 		return;
@@ -270,16 +256,13 @@
 			int no;
 
 			prom_printf("Starting CPU %d... ", i);
-			kernel_thread(start_secondary, NULL, CLONE_PID);
+			kernel_thread(NULL, NULL, CLONE_PID);
 			cpucount++;
 
 			p = init_task.prev_task;
-			init_tasks[cpucount] = p;
 
-			p->processor = i;
-			p->cpus_runnable = 1 << i; /* we schedule the first task manually */
+			p->cpu = i;
 
-			del_from_runqueue(p);
 			unhash_process(p);
 
 			callin_flag = 0;
@@ -483,7 +466,7 @@
 		__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
 				     : : "r" (pstate));
 
-		if ((stuck & ~(0x5555555555555555UL)) == 0) {
+		if ((dispatch_stat & ~(0x5555555555555555UL)) == 0) {
 			/* Busy bits will not clear, continue instead
 			 * of freezing up on this cpu.
 			 */
@@ -543,6 +526,9 @@
 	int wait;
 };
 
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static struct call_data_struct *call_data;
+
 extern unsigned long xcall_call_function;
 
 int smp_call_function(void (*func)(void *info), void *info,
@@ -550,6 +536,7 @@
 {
 	struct call_data_struct data;
 	int cpus = smp_num_cpus - 1;
+	long timeout;
 
 	if (!cpus)
 		return 0;
@@ -559,19 +546,36 @@
 	atomic_set(&data.finished, 0);
 	data.wait = wait;
 
-	smp_cross_call(&xcall_call_function,
-		       0, (u64) &data, 0);
+	spin_lock_bh(&call_lock);
+
+	call_data = &data;
+
+	smp_cross_call(&xcall_call_function, 0, 0, 0);
+
 	/* 
 	 * Wait for other cpus to complete function or at
 	 * least snap the call data.
 	 */
-	while (atomic_read(&data.finished) != cpus)
+	timeout = 1000000;
+	while (atomic_read(&data.finished) != cpus) {
+		if (--timeout <= 0)
+			goto out_timeout;
 		barrier();
+		udelay(1);
+	}
+
+	spin_unlock_bh(&call_lock);
 
 	return 0;
+
+out_timeout:
+	spin_unlock_bh(&call_lock);
+	printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n",
+	       smp_num_cpus - 1, atomic_read(&data.finished));
+	return 0;
 }
 
-void smp_call_function_client(struct call_data_struct *call_data)
+void smp_call_function_client(void)
 {
 	void (*func) (void *info) = call_data->func;
 	void *info = call_data->info;
@@ -598,7 +602,7 @@
 extern unsigned long xcall_flush_dcache_page_cheetah;
 extern unsigned long xcall_flush_dcache_page_spitfire;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 extern atomic_t dcpage_flushes;
 extern atomic_t dcpage_flushes_xcall;
 #endif
@@ -621,7 +625,7 @@
 	if (smp_processors_ready) {
 		unsigned long mask = 1UL << cpu;
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 		atomic_inc(&dcpage_flushes);
 #endif
 		if (cpu == smp_processor_id()) {
@@ -643,13 +647,46 @@
 						      __pa(page->virtual),
 						      0, mask);
 			}
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 			atomic_inc(&dcpage_flushes_xcall);
 #endif
 		}
 	}
 }
 
+void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
+{
+	if (smp_processors_ready) {
+		unsigned long mask = cpu_present_map & ~(1UL << smp_processor_id());
+		u64 data0;
+
+#ifdef CONFIG_DEBUG_DCFLUSH
+		atomic_inc(&dcpage_flushes);
+#endif
+		if (mask == 0UL)
+			goto flush_self;
+		if (tlb_type == spitfire) {
+			data0 = ((u64)&xcall_flush_dcache_page_spitfire);
+			if (page->mapping != NULL)
+				data0 |= ((u64)1 << 32);
+			spitfire_xcall_deliver(data0,
+					       __pa(page->virtual),
+					       (u64) page->virtual,
+					       mask);
+		} else {
+			data0 = ((u64)&xcall_flush_dcache_page_cheetah);
+			cheetah_xcall_deliver(data0,
+					      __pa(page->virtual),
+					      0, mask);
+		}
+#ifdef CONFIG_DEBUG_DCFLUSH
+		atomic_inc(&dcpage_flushes_xcall);
+#endif
+	flush_self:
+		__local_flush_dcache_page(page);
+	}
+}
+
 void smp_receive_signal(int cpu)
 {
 	if (smp_processors_ready) {
@@ -1075,7 +1112,6 @@
 	__cpu_number_map[boot_cpu_id] = 0;
 	prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
 	__cpu_logical_map[0] = boot_cpu_id;
-	current->processor = boot_cpu_id;
 	prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
 }
 
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/sparc64_ksyms.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.116 2001/10/26 15:49:21 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.120 2001/12/21 04:56:15 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -98,7 +98,7 @@
 #ifdef CONFIG_SMP
 extern spinlock_t kernel_flag;
 extern int smp_num_cpus;
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 extern void _do_spin_lock (spinlock_t *lock, char *str);
 extern void _do_spin_unlock (spinlock_t *lock);
 extern int _spin_trylock (spinlock_t *lock);
@@ -113,7 +113,7 @@
 
 /* used by various drivers */
 #ifdef CONFIG_SMP
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 /* Out of line rw-locking implementation. */
 EXPORT_SYMBOL(__read_lock);
 EXPORT_SYMBOL(__read_unlock);
@@ -145,7 +145,7 @@
 EXPORT_SYMBOL(__cpu_logical_map);
 
 /* Spinlock debugging library, optional. */
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_DEBUG_SPINLOCK
 EXPORT_SYMBOL(_do_spin_lock);
 EXPORT_SYMBOL(_do_spin_unlock);
 EXPORT_SYMBOL(_spin_trylock);
@@ -319,7 +319,6 @@
 EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(_clear_page);
-EXPORT_SYMBOL(_copy_page);
 EXPORT_SYMBOL(clear_user_page);
 EXPORT_SYMBOL(copy_user_page);
 EXPORT_SYMBOL(__bzero);
@@ -354,4 +353,8 @@
 
 void VISenter(void);
 /* RAID code needs this */
-EXPORT_SYMBOL(VISenter);
+EXPORT_SYMBOL_NOVERS(VISenter);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/sys_sparc.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc64/kernel/sys_sparc.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.54 2001/10/28 20:49:13 davem Exp $
+/* $Id: sys_sparc.c,v 1.56 2001/12/21 04:56:15 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -40,12 +40,15 @@
 	return PAGE_SIZE;
 }
 
-#define COLOUR_ALIGN(addr)	(((addr)+SHMLBA-1)&~(SHMLBA-1))
+#define COLOUR_ALIGN(addr,pgoff)		\
+	((((addr)+SHMLBA-1)&~(SHMLBA-1)) +	\
+	 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
 
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct * vmm;
 	unsigned long task_size = TASK_SIZE;
+	int do_color_align;
 
 	if (flags & MAP_FIXED) {
 		/* We do not accept a shared mapping if it would violate
@@ -63,11 +66,14 @@
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (flags & MAP_SHARED)
-		addr = COLOUR_ALIGN(addr);
+	do_color_align = 0;
+	if (filp || (flags & MAP_SHARED))
+		do_color_align = 1;
+
+	if (do_color_align)
+		addr = COLOUR_ALIGN(addr, pgoff);
 	else
 		addr = PAGE_ALIGN(addr);
-
 	task_size -= len;
 
 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
@@ -81,8 +87,8 @@
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
 		addr = vmm->vm_end;
-		if (flags & MAP_SHARED)
-			addr = COLOUR_ALIGN(addr);
+		if (do_color_align)
+			addr = COLOUR_ALIGN(addr, pgoff);
 	}
 }
 
@@ -255,27 +261,15 @@
 
 asmlinkage int sparc64_personality(unsigned long personality)
 {
-	unsigned long ret, trying, orig_ret;
-
-	trying = ret = personality;
+	int ret;
 
-	if (current->personality == PER_LINUX32 &&
-	    trying == PER_LINUX)
-		trying = ret = PER_LINUX32;
-
-	/* For PER_LINUX32 we want to retain &default_exec_domain.  */
-	if (trying == PER_LINUX32)
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
 		ret = PER_LINUX;
 
-	orig_ret = ret;
-	ret = sys_personality(ret);
-
-	if (orig_ret == PER_LINUX && trying == PER_LINUX32) {
-		current->personality = PER_LINUX32;
-		ret = PER_LINUX;
-	}
-
-	return (int) ret;
+	return ret;
 }
 
 /* Linux version of mmap */
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/sys_sunos32.c	Tue Aug 14 19:57:28 2001
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.61 2001/08/13 14:40:07 davem Exp $
+/* $Id: sys_sunos32.c,v 1.62 2002/01/08 16:00:14 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -68,7 +68,7 @@
 	struct file *file = NULL;
 	unsigned long retval, ret_type;
 
-	if(flags & MAP_NORESERVE) {
+	if (flags & MAP_NORESERVE) {
 		static int cnt;
 		if (cnt++ < 10)
 			printk("%s:  unimplemented SunOS MAP_NORESERVE mmap() flag\n",
@@ -76,15 +76,15 @@
 		flags &= ~MAP_NORESERVE;
 	}
 	retval = -EBADF;
-	if(!(flags & MAP_ANONYMOUS)) {
+	if (!(flags & MAP_ANONYMOUS)) {
 		struct inode * inode;
-		if(fd >= SUNOS_NR_OPEN)
+		if (fd >= SUNOS_NR_OPEN)
 			goto out;
  		file = fget(fd);
 		if (!file)
 			goto out;
 		inode = file->f_dentry->d_inode;
-		if(MAJOR(inode->i_rdev)==MEM_MAJOR && MINOR(inode->i_rdev)==5) {
+		if (minor(inode->i_rdev) == MEM_MAJOR && minor(inode->i_rdev) == 5) {
 			flags |= MAP_ANONYMOUS;
 			fput(file);
 			file = NULL;
@@ -92,7 +92,7 @@
 	}
 
 	retval = -EINVAL;
-	if(!(flags & MAP_FIXED))
+	if (!(flags & MAP_FIXED))
 		addr = 0;
 	else if (len > 0xf0000000 || addr > 0xf0000000 - len)
 		goto out_putf;
@@ -106,7 +106,7 @@
 			 (unsigned long) prot, (unsigned long) flags,
 			 (unsigned long) off);
 	up_write(&current->mm->mmap_sem);
-	if(!ret_type)
+	if (!ret_type)
 		retval = ((retval < 0xf0000000) ? 0 : retval);
 out_putf:
 	if (file)
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/time.c	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/kernel/time.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.40 2001/09/06 02:44:28 davem Exp $
+/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -609,7 +609,6 @@
 	unsigned long clock;
 
 	init_timers(timer_interrupt, &clock);
-	timer_tick_offset = clock / HZ;
 	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
 }
 
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- linux-2.5.2-pre11/arch/sparc64/kernel/trampoline.S	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/kernel/trampoline.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.22 2001/09/07 21:04:40 kanoj Exp $
+/* $Id: trampoline.S,v 1.25 2002/01/11 08:45:38 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -262,7 +262,7 @@
 	wrpr		%o1, PSTATE_IG, %pstate
 
 	/* Get our UPA MID. */
-	lduw		[%o2 + AOFF_task_processor], %g1
+	lduw		[%o2 + AOFF_task_cpu], %g1
 	sethi		%hi(cpu_data), %g5
 	or		%g5, %lo(cpu_data), %g5
 
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- linux-2.5.2-pre11/arch/sparc64/kernel/traps.c	Mon Oct  1 09:19:56 2001
+++ linux/arch/sparc64/kernel/traps.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.79 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: traps.c,v 1.83 2002/01/11 08:45:38 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -38,16 +38,19 @@
 
 void bad_trap (struct pt_regs *regs, long lvl)
 {
+	char buffer[32];
 	siginfo_t info;
 
 	if (lvl < 0x100) {
-		char buffer[24];
-		
-		sprintf (buffer, "Bad hw trap %lx at tl0\n", lvl);
+		sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
+		die_if_kernel(buffer, regs);
+	}
+
+	lvl -= 0x100;
+	if (regs->tstate & TSTATE_PRIV) {
+		sprintf(buffer, "Kernel bad sw trap %lx", lvl);
 		die_if_kernel (buffer, regs);
 	}
-	if (regs->tstate & TSTATE_PRIV)
-		die_if_kernel ("Kernel bad trap", regs);
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
@@ -56,7 +59,7 @@
 	info.si_errno = 0;
 	info.si_code = ILL_ILLTRP;
 	info.si_addr = (void *)regs->tpc;
-	info.si_trapno = lvl - 0x100;
+	info.si_trapno = lvl;
 	force_sig_info(SIGILL, &info, current);
 }
 
@@ -68,6 +71,14 @@
 	die_if_kernel (buffer, regs);
 }
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+	bust_spinlocks(1);
+	printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
 void instruction_access_exception (struct pt_regs *regs,
 				   unsigned long sfsr, unsigned long sfar)
 {
@@ -947,6 +958,7 @@
 	__asm__ __volatile__("ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "casxa	[%2] %3, %%g0, %%g0\n\t"
+			     "membar	#StoreLoad | #StoreStore\n\t"
 			     "ldxa	[%0] %3, %%g0\n\t"
 			     "ldxa	[%1] %3, %%g0\n\t"
 			     "membar	#Sync"
@@ -1648,13 +1660,16 @@
 	}
 }
 
+/* Only invoked on boot processor. */
 void trap_init(void)
 {
-	/* Attach to the address space of init_task. */
+	/* Attach to the address space of init_task.  On SMP we
+	 * do this in smp.c:smp_callin for other cpus.
+	 */
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
-	/* NOTE: Other cpus have this done as they are started
-	 *       up on SMP.
-	 */
+#ifdef CONFIG_SMP
+	current->cpu = hard_smp_processor_id();
+#endif
 }
diff -urN linux-2.5.2-pre11/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- linux-2.5.2-pre11/arch/sparc64/kernel/ttable.S	Mon Oct  1 09:19:56 2001
+++ linux/arch/sparc64/kernel/ttable.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.35 2001/09/21 02:14:39 kanoj Exp $
+/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -15,11 +15,13 @@
 sparc64_ttable_tl0:
 tl0_resv000:	BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
 tl0_resv004:	BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
-tl0_iax:	TRAP_NOSAVE(__do_instruction_access_exception)
+tl0_iax:	membar #Sync
+		TRAP_NOSAVE_7INSNS(__do_instruction_access_exception)
 tl0_resv009:	BTRAP(0x9)
 tl0_iae:	TRAP(do_iae)
 tl0_resv00b:	BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
-tl0_ill:	TRAP(do_illegal_instruction)
+tl0_ill:	membar #Sync
+		TRAP_7INSNS(do_illegal_instruction)
 tl0_privop:	TRAP(do_privop)
 tl0_resv012:	BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17)
 tl0_resv018:	BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
diff -urN linux-2.5.2-pre11/arch/sparc64/lib/atomic.S linux/arch/sparc64/lib/atomic.S
--- linux-2.5.2-pre11/arch/sparc64/lib/atomic.S	Thu Mar 16 11:40:17 2000
+++ linux/arch/sparc64/lib/atomic.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: atomic.S,v 1.3 2000/03/16 16:44:37 davem Exp $
+/* $Id: atomic.S,v 1.4 2001/11/18 00:12:56 davem Exp $
  * atomic.S: These things are too big to do inline.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -19,7 +19,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_add
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 add	%g7, %o0, %o0
 
@@ -30,7 +30,7 @@
 	cas	[%o1], %g5, %g7
 	cmp	%g5, %g7
 	bne,pn	%icc, __atomic_sub
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	retl
 	 sub	%g7, %o0, %o0
 atomic_impl_end:
diff -urN linux-2.5.2-pre11/arch/sparc64/lib/bitops.S linux/arch/sparc64/lib/bitops.S
--- linux-2.5.2-pre11/arch/sparc64/lib/bitops.S	Fri Apr 13 20:15:55 2001
+++ linux/arch/sparc64/lib/bitops.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
+/* $Id: bitops.S,v 1.3 2001/11/18 00:12:56 davem Exp $
  * bitops.S: Sparc64 atomic bit operations.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -28,7 +28,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_bit
 ___test_and_clear_bit:	/* %o0=nr, %o1=addr */
@@ -47,7 +47,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_change_bit
 ___test_and_change_bit:	/* %o0=nr, %o1=addr */
@@ -65,7 +65,7 @@
 	bne,a,pn %xcc, 1b
 	 ldx	[%o1], %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 	nop
 
 	.globl	___test_and_set_le_bit
@@ -85,7 +85,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	___test_and_clear_le_bit
 ___test_and_clear_le_bit:	/* %o0=nr, %o1=addr */
@@ -104,7 +104,7 @@
 	bne,a,pn %icc, 1b
 	 lduwa	[%o1] ASI_PL, %g7
 2:	retl
-	 nop
+	 membar	#StoreLoad | #StoreStore
 
 	.globl	__bitops_end
 __bitops_end:
diff -urN linux-2.5.2-pre11/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- linux-2.5.2-pre11/arch/sparc64/lib/blockops.S	Mon Oct  1 09:19:56 2001
+++ linux/arch/sparc64/lib/blockops.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.36 2001/09/24 21:44:03 davem Exp $
+/* $Id: blockops.S,v 1.41 2001/12/05 06:05:35 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -17,10 +17,9 @@
 	fmovd	%reg4, %f56; 	fmovd	%reg5, %f58;		\
 	fmovd	%reg6, %f60; 	fmovd	%reg7, %f62;
 
-#define	TLBTEMP_BASE	(8 * 1024 * 1024)
 #define	DCACHE_SIZE	(PAGE_SIZE * 2)
-#define TLBTEMP_ENT1	(61 << 3)
-#define TLBTEMP_ENT2	(62 << 3)
+#define TLBTEMP_ENT1	(60 << 3)
+#define TLBTEMP_ENT2	(61 << 3)
 #define TLBTEMP_ENTSZ	(1 << 3)
 
 #if (PAGE_SHIFT == 13) || (PAGE_SHIFT == 19)
@@ -34,64 +33,6 @@
 	.text
 
 	.align		32
-	.globl		_copy_page
-	.type		_copy_page,@function
-_copy_page: /* %o0=dest, %o1=src */
-	VISEntry
-	membar		#LoadStore | #StoreStore | #StoreLoad
-	ldda		[%o1] ASI_BLK_P, %f0
-	add		%o1, 0x40, %o1
-	ldda		[%o1] ASI_BLK_P, %f16
-	add		%o1, 0x40, %o1
-	sethi		%hi(PAGE_SIZE), %o2
-1:	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
-	ldda		[%o1] ASI_BLK_P, %f32
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
-	ldda		[%o1] ASI_BLK_P, %f0
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f32, f34, f36, f38, f40, f42, f44, f46)
-	ldda		[%o1] ASI_BLK_P, %f16
-	stda		%f48, [%o0] ASI_BLK_P
-	sub		%o2, 0x40, %o2
-	add		%o1, 0x40, %o1
-	cmp		%o2, PAGE_SIZE_REM
-	bne,pt		%xcc, 1b
-	 add		%o0, 0x40, %o0
-#if (PAGE_SHIFT == 16) || (PAGE_SHIFT == 22)
-	TOUCH(f0, f2, f4, f6, f8, f10, f12, f14)
-	ldda		[%o1] ASI_BLK_P, %f32
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	TOUCH(f16, f18, f20, f22, f24, f26, f28, f30)
-	ldda		[%o1] ASI_BLK_P, %f0
-	stda		%f48, [%o0] ASI_BLK_P
-	add		%o1, 0x40, %o1
-	sub		%o2, 0x40, %o2
-	add		%o0, 0x40, %o0
-	membar		#Sync
-	stda		%f32, [%o0] ASI_BLK_P
-	add		%o0, 0x40, %o0
-	stda		%f0, [%o0] ASI_BLK_P
-#else
-	membar		#Sync
-	stda		%f0, [%o0] ASI_BLK_P
-	add		%o0, 0x40, %o0
-	stda		%f16, [%o0] ASI_BLK_P
-#endif
-	membar		#Sync
-	VISExit
-	retl
-	 nop
-
 	.globl		copy_user_page
 	.type		copy_user_page,@function
 copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
@@ -110,7 +51,7 @@
 	or		%g2, %g3, %g2
 	add		%o0, %o3, %o0
 	add		%o0, %o1, %o1
-#define FIX_INSN_1	0x96102068 /* mov (13 << 3), %o3 */
+#define FIX_INSN_1	0x96102060 /* mov (12 << 3), %o3 */
 cheetah_patch_1:
 	mov		TLBTEMP_ENT1, %o3
 	rdpr		%pstate, %g3
@@ -134,6 +75,7 @@
 	stxa		%g0, [%o5] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %o5
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
@@ -152,6 +94,7 @@
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o1, [%o2] ASI_DMMU
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
@@ -169,9 +112,10 @@
 	 nop
 
 cheetah_copy_user_page:
-	mov		121, %o2			! A0 Group
+	sethi		%hi((PAGE_SIZE/64)-7), %o2	! A0 Group
 	prefetch	[%o1 + 0x000], #one_read	! MS
-	prefetch	[%o1 + 0x040], #one_read	! MS Group
+	or		%o2, %lo((PAGE_SIZE/64)-7), %o2	! A1 Group
+	prefetch	[%o1 + 0x040], #one_read	! MS
 	prefetch	[%o1 + 0x080], #one_read	! MS Group
 	prefetch	[%o1 + 0x0c0], #one_read	! MS Group
 	ldd		[%o1 + 0x000], %f0		! MS Group
@@ -402,7 +346,7 @@
 	or		%g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
 	or		%g1, %g3, %g1
 	add		%o0, %o3, %o0
-#define FIX_INSN_2	0x96102070 /* mov (14 << 3), %o3 */
+#define FIX_INSN_2	0x96102068 /* mov (13 << 3), %o3 */
 cheetah_patch_2:
 	mov		TLBTEMP_ENT2, %o3
 	rdpr		%pstate, %g3
@@ -420,6 +364,7 @@
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
 
+	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g0
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
@@ -430,8 +375,9 @@
 clear_page_common:
 	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 	fzero		%f0				! FPA	Group
-	mov		PAGE_SIZE/256, %o1		! IEU0
+	sethi		%hi(PAGE_SIZE/256), %o1		! IEU0
 	fzero		%f2				! FPA	Group
+	or		%o1, %lo(PAGE_SIZE/256), %o1	! IEU0
 	faddd		%f0, %f2, %f4			! FPA	Group
 	fmuld		%f0, %f2, %f6			! FPM
 	faddd		%f0, %f2, %f8			! FPA	Group
diff -urN linux-2.5.2-pre11/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- linux-2.5.2-pre11/arch/sparc64/lib/debuglocks.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/lib/debuglocks.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.6 2001/04/24 01:09:12 davem Exp $
+/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -10,10 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/system.h>
 
-#ifdef CONFIG_SMP
-
-/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
-#ifdef SPIN_LOCK_DEBUG
+#if defined(CONFIG_SMP) && defined(CONFIG_DEBUG_SPINLOCK)
 
 #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
 
@@ -56,6 +53,7 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 again:
@@ -67,7 +65,8 @@
 	if (val) {
 		while (lock->lock) {
 			if (!--stuck) {
-				show(str, lock, caller);
+				if (shown++ <= 2)
+					show(str, lock, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -76,6 +75,8 @@
 	}
 	lock->owner_pc = ((unsigned int)caller);
 	lock->owner_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 int _spin_trylock(spinlock_t *lock)
@@ -92,6 +93,8 @@
 	if (!val) {
 		lock->owner_pc = ((unsigned int)caller);
 		lock->owner_cpu = cpu;
+		current->thread.smp_lock_count++;
+		current->thread.smp_lock_pc = ((unsigned int)caller);
 	}
 	return val == 0;
 }
@@ -102,6 +105,7 @@
 	lock->owner_cpu = NO_PROC_ID;
 	membar("#StoreStore | #LoadStore");
 	lock->lock = 0;
+	current->thread.smp_lock_count--;
 }
 
 /* Keep INIT_STUCK the same... */
@@ -111,13 +115,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Wait for any writer to go away.  */
 	while (((long)(rw->lock)) < 0) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -137,6 +143,8 @@
 	if (val)
 		goto wlock_again;
 	rw->reader_pc[cpu] = ((unsigned int)caller);
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_read_unlock (rwlock_t *rw, char *str)
@@ -144,11 +152,13 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_. */
 	rw->reader_pc[cpu] = 0;
+	current->thread.smp_lock_count--;
 runlock_again:
 	/* Spin trying to decrement the counter using casx.  */
 	__asm__ __volatile__(
@@ -162,7 +172,8 @@
 	: "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_read(str, rw, caller);
+			if (shown++ <= 2)
+				show_read(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto runlock_again;
@@ -174,13 +185,15 @@
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
+	int shown = 0;
 
 	GET_CALLER(caller);
 wlock_again:
 	/* Spin while there is another writer. */
 	while (((long)rw->lock) < 0) {
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		membar("#LoadLoad");
@@ -204,7 +217,8 @@
 	if (val) {
 		/* We couldn't get the write bit. */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
@@ -214,7 +228,8 @@
 		 * lock, spin, and try again.
 		 */
 		if (!--stuck) {
-			show_write(str, rw, caller);
+			if (shown++ <= 2)
+				show_write(str, rw, caller);
 			stuck = INIT_STUCK;
 		}
 		__asm__ __volatile__(
@@ -231,7 +246,8 @@
 		: "g3", "g5", "g7", "cc", "memory");
 		while(rw->lock != 0) {
 			if (!--stuck) {
-				show_write(str, rw, caller);
+				if (shown++ <= 2)
+					show_write(str, rw, caller);
 				stuck = INIT_STUCK;
 			}
 			membar("#LoadLoad");
@@ -242,18 +258,22 @@
 	/* We have it, say who we are. */
 	rw->writer_pc = ((unsigned int)caller);
 	rw->writer_cpu = cpu;
+	current->thread.smp_lock_count++;
+	current->thread.smp_lock_pc = ((unsigned int)caller);
 }
 
 void _do_write_unlock(rwlock_t *rw)
 {
 	unsigned long caller, val;
 	int stuck = INIT_STUCK;
+	int shown = 0;
 
 	GET_CALLER(caller);
 
 	/* Drop our identity _first_ */
 	rw->writer_pc = 0;
 	rw->writer_cpu = NO_PROC_ID;
+	current->thread.smp_lock_count--;
 wlock_again:
 	__asm__ __volatile__(
 "	mov	1, %%g3\n"
@@ -268,12 +288,21 @@
 	: "g3", "g5", "g7", "memory");
 	if (val) {
 		if (!--stuck) {
-			show_write("write_unlock", rw, caller);
+			if (shown++ <= 2)
+				show_write("write_unlock", rw, caller);
 			stuck = INIT_STUCK;
 		}
 		goto wlock_again;
 	}
 }
 
-#endif /* SPIN_LOCK_DEBUG */
-#endif /* CONFIG_SMP */
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	spin_unlock(lock);
+	return 0;
+}
+
+#endif /* CONFIG_SMP && CONFIG_DEBUG_SPINLOCK */
diff -urN linux-2.5.2-pre11/arch/sparc64/lib/dec_and_lock.S linux/arch/sparc64/lib/dec_and_lock.S
--- linux-2.5.2-pre11/arch/sparc64/lib/dec_and_lock.S	Sun Aug 13 12:01:54 2000
+++ linux/arch/sparc64/lib/dec_and_lock.S	Mon Jan 14 18:28:28 2002
@@ -1,10 +1,12 @@
-/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $
+/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $
  * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
  *                 using cas and ldstub instructions.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
  */
+#include <linux/config.h>
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 	.text
 	.align	64
 
@@ -34,13 +36,15 @@
 	bne,pn	%icc, loop1
 	 mov	0, %g1
 
-out:	retl
+out:
+	membar	#StoreLoad | #StoreStore
+	retl
 	 mov	%g1, %o0
-to_zero:ldstub	[%o1], %g3
+to_zero:
+	ldstub	[%o1], %g3
 	brnz,pn	%g3, spin_on_lock
 	 membar	#StoreLoad | #StoreStore
 loop2:	cas	[%o0], %g5, %g7		/* ASSERT(g7 == 0) */
-	nop
 	cmp	%g5, %g7
 
 	be,pt	%icc, out
@@ -61,3 +65,5 @@
 	ba,pt	%xcc, to_zero
 	 nop
 	nop
+
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
diff -urN linux-2.5.2-pre11/arch/sparc64/mm/extable.c linux/arch/sparc64/mm/extable.c
--- linux-2.5.2-pre11/arch/sparc64/mm/extable.c	Tue Aug  7 08:30:50 2001
+++ linux/arch/sparc64/mm/extable.c	Mon Jan 14 18:28:28 2002
@@ -11,35 +11,49 @@
 
 static unsigned long
 search_one_table(const struct exception_table_entry *start,
-		 const struct exception_table_entry *last,
+		 const struct exception_table_entry *end,
 		 unsigned long value, unsigned long *g2)
 {
-	const struct exception_table_entry *first = start;
-	const struct exception_table_entry *mid;
-	long diff = 0;
-        while (first <= last) {
-		mid = (last - first) / 2 + first;
-		diff = mid->insn - value;
-                if (diff == 0) {
-                	if (!mid->fixup) {
-                		*g2 = 0;
-                		return (mid + 1)->fixup;
-                	} else
-	                        return mid->fixup;
-                } else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        if (last->insn < value && !last->fixup && last[1].insn > value) {
-        	*g2 = (value - last->insn)/4;
-        	return last[1].fixup;
-        }
-        if (first > start && first[-1].insn < value
-	    && !first[-1].fixup && first->insn < value) {
-        	*g2 = (value - first[-1].insn)/4;
-        	return first->fixup;
-        }
+	const struct exception_table_entry *walk;
+
+	/* Single insn entries are encoded as:
+	 *	word 1:	insn address
+	 *	word 2:	fixup code address
+	 *
+	 * Range entries are encoded as:
+	 *	word 1: first insn address
+	 *	word 2: 0
+	 *	word 3: last insn address + 4 bytes
+	 *	word 4: fixup code address
+	 *
+	 * See asm/uaccess.h for more details.
+	 */
+
+	/* 1. Try to find an exact match. */
+	for (walk = start; walk <= end; walk++) {
+		if (walk->fixup == 0) {
+			/* A range entry, skip both parts. */
+			walk++;
+			continue;
+		}
+
+		if (walk->insn == value)
+			return walk->fixup;
+	}
+
+	/* 2. Try to find a range match. */
+	for (walk = start; walk <= (end - 1); walk++) {
+		if (walk->fixup)
+			continue;
+
+		if (walk[0].insn <= value &&
+		    walk[1].insn > value) {
+			*g2 = (value - walk[0].insn) / 4;
+			return walk[1].fixup;
+		}
+		walk++;
+	}
+
         return 0;
 }
 
diff -urN linux-2.5.2-pre11/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- linux-2.5.2-pre11/arch/sparc64/mm/init.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc64/mm/init.c	Mon Jan 14 18:28:28 2002
@@ -111,7 +111,7 @@
 
 extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 atomic_t dcpage_flushes = ATOMIC_INIT(0);
 #ifdef CONFIG_SMP
 atomic_t dcpage_flushes_xcall = ATOMIC_INIT(0);
@@ -120,7 +120,7 @@
 
 __inline__ void flush_dcache_page_impl(struct page *page)
 {
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	atomic_inc(&dcpage_flushes);
 #endif
 
@@ -152,7 +152,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop"
+			     " membar	#StoreLoad | #StoreStore"
 			     : /* no outputs */
 			     : "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
 			     : "g5", "g7");
@@ -172,7 +172,7 @@
 			     "casx	[%2], %%g7, %%g5\n\t"
 			     "cmp	%%g7, %%g5\n\t"
 			     "bne,pn	%%xcc, 1b\n\t"
-			     " nop\n"
+			     " membar	#StoreLoad | #StoreStore\n"
 			     "2:"
 			     : /* no outputs */
 			     : "r" (cpu), "r" (mask), "r" (&page->flags)
@@ -261,14 +261,14 @@
 	else
 		seq_printf(m, "MMU Type\t: ???\n");
 
-#ifdef DCFLUSH_DEBUG
+#ifdef CONFIG_DEBUG_DCFLUSH
 	seq_printf(m, "DCPageFlushes\t: %d\n",
 		   atomic_read(&dcpage_flushes));
 #ifdef CONFIG_SMP
 	seq_printf(m, "DCPageFlushesXC\t: %d\n",
 		   atomic_read(&dcpage_flushes_xcall));
 #endif /* CONFIG_SMP */
-#endif /* DCFLUSH_DEBUG */
+#endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
 struct linux_prom_translation {
diff -urN linux-2.5.2-pre11/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- linux-2.5.2-pre11/arch/sparc64/mm/ultra.S	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc64/mm/ultra.S	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.68 2001/11/09 14:59:19 davem Exp $
+/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -117,7 +117,7 @@
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
 	/* XXX Spitfire dependency... */
-	mov		(62 << 3), %g2
+	mov		((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
 	mov		0x8, %o4
@@ -642,7 +642,7 @@
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
 
 2:	add		%g2, 1, %g2
-	cmp		%g2, 63
+	cmp		%g2, SPITFIRE_HIGHEST_LOCKED_TLBENT
 	ble,pt		%icc, 1b
 	 sll		%g2, 3, %g3
 	flush		%g6
@@ -679,20 +679,15 @@
 
 	.globl		xcall_call_function
 xcall_call_function:
-	mov		TLB_TAG_ACCESS, %g5		! wheee...
-	stxa		%g1, [%g5] ASI_IMMU		! save call_data here for a bit
-	membar		#Sync
 	rdpr		%pstate, %g2
 	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
-	mov		TLB_TAG_ACCESS, %g2
-	ldxa		[%g2] ASI_IMMU, %g5
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
 	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		smp_call_function_client
-	 mov		%l5, %o0
+	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
 
diff -urN linux-2.5.2-pre11/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- linux-2.5.2-pre11/arch/sparc64/solaris/fs.c	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/solaris/fs.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.25 2001/09/19 00:04:30 davem Exp $
+/* $Id: fs.c,v 1.26 2002/01/08 16:00:21 davem Exp $
  * fs.c: fs related syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -429,7 +429,7 @@
 		    __put_user (s.f_files, &ss->f_files)	||
 		    __put_user (s.f_ffree, &ss->f_ffree)	||
 		    __put_user (s.f_ffree, &ss->f_favail)	||
-		    __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+		    __put_user (R4_DEV(kdev_t_to_nr(inode->i_sb->s_dev)), &ss->f_fsid) ||
 		    __copy_to_user (ss->f_basetype,p,j)		||
 		    __put_user (0, (char *)&ss->f_basetype[j])	||
 		    __put_user (s.f_namelen, &ss->f_namemax)	||
@@ -463,7 +463,7 @@
 		    __put_user (s.f_files, &ss->f_files)	||
 		    __put_user (s.f_ffree, &ss->f_ffree)	||
 		    __put_user (s.f_ffree, &ss->f_favail)	||
-		    __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
+		    __put_user (R4_DEV(kdev_t_to_nr(inode->i_sb->s_dev)), &ss->f_fsid) ||
 		    __copy_to_user (ss->f_basetype,p,j)		||
 		    __put_user (0, (char *)&ss->f_basetype[j])	||
 		    __put_user (s.f_namelen, &ss->f_namemax)	||
diff -urN linux-2.5.2-pre11/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- linux-2.5.2-pre11/arch/sparc64/solaris/misc.c	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/solaris/misc.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.33 2001/09/18 22:29:06 davem Exp $
+/* $Id: misc.c,v 1.35 2002/01/08 16:00:21 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/timex.h>
+#include <linux/major.h>
 
 #include <asm/uaccess.h>
 #include <asm/string.h>
@@ -74,8 +75,8 @@
 			goto out;
 		else {
 			struct inode * inode = file->f_dentry->d_inode;
-			if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
-			   MINOR(inode->i_rdev) == 5) {
+			if(major(inode->i_rdev) == MEM_MAJOR &&
+			   minor(inode->i_rdev) == 5) {
 				flags |= MAP_ANONYMOUS;
 				fput(file);
 				file = NULL;
diff -urN linux-2.5.2-pre11/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c
--- linux-2.5.2-pre11/arch/sparc64/solaris/socksys.c	Fri Nov 30 08:26:04 2001
+++ linux/arch/sparc64/solaris/socksys.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.18 2001/02/13 01:16:44 davem Exp $
+/* $Id: socksys.c,v 1.20 2002/01/08 16:00:21 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -61,14 +61,14 @@
 		(int (*)(int,int,int))SUNOS(97);
         struct sol_socket_struct * sock;
 	
-	family = ((MINOR(inode->i_rdev) >> 4) & 0xf);
+	family = ((minor(inode->i_rdev) >> 4) & 0xf);
 	switch (family) {
 	case AF_UNIX:
 		type = SOCK_STREAM;
 		protocol = 0;
 		break;
 	case AF_INET:
-		protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf];
+		protocol = af_inet_protocols[minor(inode->i_rdev) & 0xf];
 		switch (protocol) {
 		case IPPROTO_TCP: type = SOCK_STREAM; break;
 		case IPPROTO_UDP: type = SOCK_DGRAM; break;
diff -urN linux-2.5.2-pre11/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- linux-2.5.2-pre11/arch/sparc64/solaris/timod.c	Mon Dec 10 13:52:53 2001
+++ linux/arch/sparc64/solaris/timod.c	Mon Jan 14 18:28:28 2002
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.16 2001/09/18 22:29:06 davem Exp $
+/* $Id: timod.c,v 1.18 2002/01/08 16:00:21 davem Exp $
  * timod.c: timod emulation.
  *
  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
@@ -921,7 +921,7 @@
 	if (!ino) goto out;
 
 	if (!ino->i_sock &&
-		(MAJOR(ino->i_rdev) != 30 || MINOR(ino->i_rdev) != 1))
+		(major(ino->i_rdev) != 30 || minor(ino->i_rdev) != 1))
 		goto out;
 
 	ctlptr = (struct strbuf *)A(arg1);
diff -urN linux-2.5.2-pre11/drivers/block/Config.in linux/drivers/block/Config.in
--- linux-2.5.2-pre11/drivers/block/Config.in	Fri Sep 14 14:04:06 2001
+++ linux/drivers/block/Config.in	Mon Jan 14 18:28:28 2002
@@ -35,6 +35,7 @@
 fi
 dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
 dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI 
+dep_mbool '       SCSI tape drive support for Smart Array 5xxx' CONFIG_CISS_SCSI_TAPE $CONFIG_BLK_CPQ_CISS_DA $CONFIG_SCSI
 dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
 
 tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
diff -urN linux-2.5.2-pre11/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux-2.5.2-pre11/drivers/block/cciss.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/cciss.c	Mon Jan 14 18:28:28 2002
@@ -126,6 +126,8 @@
 	revalidate:		frevalidate_logvol,
 };
 
+#include "cciss_scsi.c"		/* For SCSI tape support */
+
 /*
  * Report information about this controller.
  */
@@ -160,6 +162,7 @@
                 h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
         pos += size; len += size;
+	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
 	for(i=0; i<h->num_luns; i++) {
                 drv = &h->drv[i];
                 size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
@@ -179,20 +182,53 @@
         return len;
 }
 
+static int 
+cciss_proc_write(struct file *file, const char *buffer, 
+			unsigned long count, void *data)
+{
+	unsigned char cmd[80];
+	int len;
+#ifdef CONFIG_CISS_SCSI_TAPE
+	ctlr_info_t *h = (ctlr_info_t *) data;
+	int rc;
+#endif
+
+	if (count > sizeof(cmd)-1) return -EINVAL;
+	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	cmd[count] = '\0';
+	len = strlen(cmd);	// above 3 lines ensure safety
+	if (cmd[len-1] == '\n') 
+		cmd[--len] = '\0';
+#	ifdef CONFIG_CISS_SCSI_TAPE
+		if (strcmp("engage scsi", cmd)==0) {
+			rc = cciss_engage_scsi(h->ctlr);
+			if (rc != 0) return -rc;
+			return count;
+		}
+		/* might be nice to have "disengage" too, but it's not 
+		   safely possible. (only 1 module use count, lock issues.) */
+#	endif
+	return -EINVAL;
+}
+
 /*
  * Get us a file in /proc/cciss that says something about each controller.
  * Create /proc/cciss if it doesn't exist yet.
  */
 static void __init cciss_procinit(int i)
 {
+	struct proc_dir_entry *pde;
+
         if (proc_cciss == NULL) {
                 proc_cciss = proc_mkdir("cciss", proc_root_driver);
                 if (!proc_cciss) 
 			return;
         }
 
-        create_proc_read_entry(hba[i]->devname, 0, proc_cciss,
-        		cciss_proc_get_info, hba[i]);
+	pde = create_proc_read_entry(hba[i]->devname, 
+		S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 
+		proc_cciss, cciss_proc_get_info, hba[i]);
+	pde->write_proc = cciss_proc_write;
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -824,9 +860,12 @@
 	int	ctlr,
 	void	*buff,
 	size_t	size,
-	unsigned int use_unit_num,
+	unsigned int use_unit_num, /* 0: address the controller,
+				      1: address logical volume log_unit, 
+				      2: periph device address is scsi3addr */
 	unsigned int log_unit,
-	__u8	page_code )
+	__u8	page_code,
+	unsigned char *scsi3addr)
 {
 	CommandList_struct *c;
 	int i;
@@ -860,15 +899,23 @@
 				to controller so It's a physical command
 				mode = 0 target = 0.
 				So we have nothing to write. 
-				Otherwise 
-				mode = 1  target = LUNID
+				otherwise, if use_unit_num == 1, 
+				mode = 1(volume set addressing) target = LUNID
+				otherwise, if use_unit_num == 2,
+				mode = 0(periph dev addr) target = scsi3addr 
 			*/
-			if(use_unit_num != 0)
+			if(use_unit_num == 1)
 			{
 				c->Header.LUN.LogDev.VolId=
                                 	hba[ctlr]->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
 			}
+			else if (use_unit_num == 2)
+			{
+				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+                        	c->Header.LUN.LogDev.Mode = 0; // phys dev addr 
+			}
+
 			/* are we trying to read a vital product page */
 			if(page_code != 0)
 			{
@@ -884,6 +931,7 @@
 			c->Request.CDB[4] = size  & 0xFF;  
 		break;
 		case CISS_REPORT_LOG:
+		case CISS_REPORT_PHYS:
                         /* Talking to controller so It's a physical command
                                 mode = 00 target = 0.
                                 So we have nothing to write.
@@ -893,7 +941,7 @@
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
                         c->Request.Type.Direction = XFER_READ; // Read
                         c->Request.Timeout = 0; // Don't time out
-                        c->Request.CDB[0] = CISS_REPORT_LOG;
+                        c->Request.CDB[0] = cmd;
                         c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
                         c->Request.CDB[7] = (size >> 16) & 0xFF;
                         c->Request.CDB[8] = (size >> 8) & 0xFF;
@@ -971,6 +1019,7 @@
 				ignore it 
 			*/
 			if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
+			     (c->Request.CDB[0] == CISS_REPORT_PHYS) ||
 			     (c->Request.CDB[0] == CISS_INQUIRY)) &&
 				((c->err_info->CommandStatus == 
 					CMD_DATA_OVERRUN) || 
@@ -1356,6 +1405,10 @@
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					c->cmd_type = CMD_IOCTL_DONE;
 				}
+#				ifdef CONFIG_CISS_SCSI_TAPE
+				else if (c->cmd_type == CMD_SCSI)
+					complete_scsi_command(c, 0, a1);
+#				endif
 				continue;
 			}
 		}
@@ -1592,7 +1645,7 @@
         }
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
-		sizeof(InquiryData_struct), 0, 0 ,0 );
+		sizeof(InquiryData_struct), 0, 0 ,0, NULL );
 	if (return_code == IO_OK)
 	{
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
@@ -1606,7 +1659,7 @@
 	}
 	/* Get the number of logical volumes */ 
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
-			sizeof(ReportLunData_struct), 0, 0, 0 );
+			sizeof(ReportLunData_struct), 0, 0, 0, NULL );
 
 	if( return_code == IO_OK)
 	{
@@ -1652,7 +1705,7 @@
 
 	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
-				sizeof( ReadCapdata_struct), 1, i, 0 );
+				sizeof( ReadCapdata_struct), 1, i, 0, NULL );
 	  	if (return_code == IO_OK)
 		{
 			total_size = (0xff & 
@@ -1684,7 +1737,7 @@
 		/* Execute the command to read the disk geometry */
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
-                	sizeof(InquiryData_struct), 1, i ,0xC1 );
+                	sizeof(InquiryData_struct), 1, i ,0xC1, NULL );
 	  	if (return_code == IO_OK)
 		{
 			if(inq_buff->data_byte[8] == 0xFF)
@@ -1860,6 +1913,8 @@
 
 	cciss_getgeometry(i);
 
+	cciss_find_non_disk_devices(i);	/* find our tape drives, if any */
+
 	/* Turn the interrupts on so we can service requests */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
 
@@ -1901,6 +1956,8 @@
 			MAX_PART, &cciss_fops, 
 			hba[i]->drv[j].nr_blocks);
 
+	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
+
 	return(1);
 }
 
@@ -1927,6 +1984,7 @@
 	free_irq(hba[i]->intr, hba[i]);
 	pci_set_drvdata(pdev, NULL);
 	iounmap((void*)hba[i]->vaddr);
+	cciss_unregister_scsi(i);  /* unhook from SCSI subsystem */
 	unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
 	remove_proc_entry(hba[i]->devname, proc_cciss);	
 	
diff -urN linux-2.5.2-pre11/drivers/block/cciss.h linux/drivers/block/cciss.h
--- linux-2.5.2-pre11/drivers/block/cciss.h	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/cciss.h	Mon Jan 14 18:28:28 2002
@@ -83,6 +83,9 @@
 	struct hd_struct hd[256];
 	int		 sizes[256];
 	int              blocksizes[256];
+#ifdef CONFIG_CISS_SCSI_TAPE
+	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
+#endif
 };
 
 /*  Defining the diffent access_menthods */
diff -urN linux-2.5.2-pre11/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- linux-2.5.2-pre11/drivers/block/cciss_cmd.h	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/cciss_cmd.h	Mon Jan 14 18:28:28 2002
@@ -89,6 +89,7 @@
 //STRUCTURES
 //###########################################################################
 #define CISS_MAX_LUN	16	
+#define CISS_MAX_PHYS_LUN	1024
 // SCSI-3 Cmmands 
 
 #pragma pack(1)	
@@ -101,6 +102,7 @@
 } InquiryData_struct;
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
+#define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
 // Data returned
 typedef struct _ReportLUNdata_struct
 {
@@ -215,6 +217,9 @@
 #define CMD_RWREQ       0x00
 #define CMD_IOCTL_PEND  0x01
 #define CMD_IOCTL_DONE  0x02
+#define CMD_SCSI	0x03
+#define CMD_MSG_DONE	0x04
+#define CMD_MSG_TIMEOUT 0x05
 
 typedef struct _CommandList_struct {
   CommandListHeader_struct Header;
@@ -229,6 +234,9 @@
   struct _CommandList_struct *prev;
   struct _CommandList_struct *next;
   struct request *	   rq;
+#ifdef CONFIG_CISS_SCSI_TAPE
+  void * scsi_cmd;
+#endif
 } CommandList_struct;
 
 //Configuration Table Structure
diff -urN linux-2.5.2-pre11/drivers/block/cciss_scsi.c linux/drivers/block/cciss_scsi.c
--- linux-2.5.2-pre11/drivers/block/cciss_scsi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/cciss_scsi.c	Mon Jan 14 18:28:28 2002
@@ -0,0 +1,1634 @@
+/*
+ *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ *    Copyright 2001 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    
+ *    Author: Stephen M. Cameron
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+
+/* Here we have code to present the driver as a scsi driver 
+   as it is simultaneously presented as a block driver.  The 
+   reason for doing this is to allow access to SCSI tape drives
+   through the array controller.  Note in particular, neither 
+   physical nor logical disks are presented through the scsi layer. */
+
+#include "../scsi/scsi.h" 
+#include "../scsi/hosts.h" 
+#include <asm/atomic.h>
+#include <linux/timer.h>
+
+#include "cciss_scsi.h"
+
+/* some prototypes... */ 
+static int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num, /* 0: address the controller,
+				      1: address logical volume log_unit, 
+				      2: address is in scsi3addr */
+	unsigned int log_unit,
+	__u8	page_code,
+	unsigned char *scsi3addr );
+
+
+int __init cciss_scsi_detect(Scsi_Host_Template *tpnt);
+int cciss_scsi_release(struct Scsi_Host *sh);
+const char *cciss_scsi_info(struct Scsi_Host *sa);
+
+int cciss_scsi_proc_info(
+		char *buffer, /* data buffer */
+		char **start, 	   /* where data in buffer starts */
+		off_t offset,	   /* offset from start of imaginary file */
+		int length, 	   /* length of data in buffer */
+		int hostnum, 	   /* which host adapter (always zero for me) */
+		int func);	   /* 0 == read, 1 == write */
+
+int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *));
+#if 0
+int cciss_scsi_abort(Scsi_Cmnd *cmd);
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+int cciss_scsi_reset(Scsi_Cmnd *cmd, unsigned int reset_flags);
+#else
+int cciss_scsi_reset(Scsi_Cmnd *cmd);
+#endif
+#endif
+
+static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
+	{ name: "cciss0", ndevices: 0 },
+	{ name: "cciss1", ndevices: 0 },
+	{ name: "cciss2", ndevices: 0 },
+	{ name: "cciss3", ndevices: 0 },
+	{ name: "cciss4", ndevices: 0 },
+	{ name: "cciss5", ndevices: 0 },
+	{ name: "cciss6", ndevices: 0 },
+	{ name: "cciss7", ndevices: 0 },
+};
+
+/* We need one Scsi_Host_Template *per controller* instead of 
+   the usual one Scsi_Host_Template per controller *type*. This 
+   is so PCI hot plug could have a remote possibility of still
+   working even with the SCSI system.  It's so 
+   scsi_unregister_host will differentiate the controllers. 
+   When register_scsi_module is called, each host template is 
+   customized (name change) in cciss_register_scsi() 
+   (that's called from cciss.c:cciss_init_one()) */
+
+static 
+Scsi_Host_Template driver_template[MAX_CTLR] =
+{
+	CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+	CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+};
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_elem_t {
+	CommandList_struct cmd;
+	ErrorInfo_struct Err;
+	__u32 busaddr;
+};
+
+#pragma pack()
+
+#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
+		CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
+			// plus two for init time usage
+
+#pragma pack(1)
+struct cciss_scsi_cmd_stack_t {
+	struct cciss_scsi_cmd_stack_elem_t *pool;
+	struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+	dma_addr_t cmd_pool_handle;
+	int top;
+};
+#pragma pack()
+
+struct cciss_scsi_adapter_data_t {
+	struct Scsi_Host *scsi_host;
+	struct cciss_scsi_cmd_stack_t cmd_stack;
+	int registered;
+	spinlock_t lock; // to protect ccissscsi[ctlr]; 
+};
+
+#define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
+	&(((struct cciss_scsi_adapter_data_t *) \
+	hba[ctlr]->scsi_ctlr)->lock), flags);
+#define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
+	&(((struct cciss_scsi_adapter_data_t *) \
+	hba[ctlr]->scsi_ctlr)->lock), flags);
+
+static CommandList_struct *
+scsi_cmd_alloc(ctlr_info_t *h)
+{
+	/* assume only one process in here at a time, locking done by caller. */
+	/* use CCISS_LOCK(ctlr) */
+	/* might be better to rewrite how we allocate scsi commands in a way that */
+	/* needs no locking at all. */
+
+	/* take the top memory chunk off the stack and return it, if any. */
+	struct cciss_scsi_cmd_stack_elem_t *c;
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+	u64bit temp64;
+
+	sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+
+	if (stk->top < 0) 
+		return NULL;
+	c = stk->elem[stk->top]; 	
+	/* memset(c, 0, sizeof(*c)); */
+	memset(&c->cmd, 0, sizeof(c->cmd));
+	memset(&c->Err, 0, sizeof(c->Err));
+	/* set physical addr of cmd and addr of scsi parameters */
+	c->cmd.busaddr = c->busaddr; 
+	/* (__u32) (stk->cmd_pool_handle + 
+		(sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
+
+	temp64.val = (__u64) (c->busaddr + sizeof(CommandList_struct));
+	/* (__u64) (stk->cmd_pool_handle + 
+		(sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top) +
+		 sizeof(CommandList_struct)); */
+	stk->top--;
+	c->cmd.ErrDesc.Addr.lower = temp64.val32.lower;
+	c->cmd.ErrDesc.Addr.upper = temp64.val32.upper;
+	c->cmd.ErrDesc.Len = sizeof(ErrorInfo_struct);
+	
+	c->cmd.ctlr = h->ctlr;
+	c->cmd.err_info = &c->Err;
+
+	return (CommandList_struct *) c;
+}
+
+static void 
+scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
+{
+	/* assume only one process in here at a time, locking done by caller. */
+	/* use CCISS_LOCK(ctlr) */
+	/* drop the free memory chunk on top of the stack. */
+
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+
+	sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+	if (stk->top >= CMD_STACK_SIZE) {
+		printk("cciss: scsi_cmd_free called too many times.\n");
+		BUG();
+	}
+	stk->top++;
+	stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
+}
+
+static int
+scsi_cmd_stack_setup(int ctlr)
+{
+	int i;
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+	size_t size;
+
+	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+	// We use NULL as first arg to pci_alloc_consistent so we can be
+	// sure that we get addresses that will fit through the 32 bit
+	// command register, (our DMA mask says we can do 64 bit DMA, which
+	// we, can, just not for commands.)
+
+	stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
+		pci_alloc_consistent(NULL, size, &stk->cmd_pool_handle);
+
+	if (stk->pool == NULL) {
+		printk("stk->pool is null\n");
+		return -1;
+	}
+
+	for (i=0; i<CMD_STACK_SIZE; i++) {
+		stk->elem[i] = &stk->pool[i];
+		stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + 
+			(sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+	}
+	stk->top = CMD_STACK_SIZE-1;
+	return 0;
+}
+
+static void
+scsi_cmd_stack_free(int ctlr)
+{
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+	size_t size;
+
+	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+	if (stk->top != CMD_STACK_SIZE-1) {
+		printk( "cciss: %d scsi commands are still outstanding.\n",
+			CMD_STACK_SIZE - stk->top);
+		// BUG();
+		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n", 
+			(unsigned int) stk);
+	}
+	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+
+	// About NULL, see note above near pci_alloc_consistent	
+	pci_free_consistent(NULL, size, stk->pool, stk->cmd_pool_handle);
+	stk->pool = NULL;
+}
+
+/* scsi_device_types comes from scsi.h */
+#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
+	"Unknown" : scsi_device_types[n]
+
+#if 0
+static int xmargin=8;
+static int amargin=60;
+
+static void
+print_bytes (unsigned char *c, int len, int hex, int ascii)
+{
+
+	int i;
+	unsigned char *x;
+
+	if (hex)
+	{
+		x = c;
+		for (i=0;i<len;i++)
+		{
+			if ((i % xmargin) == 0 && i>0) printk("\n");
+			if ((i % xmargin) == 0) printk("0x%04x:", i);
+			printk(" %02x", *x);
+			x++;
+		}
+		printk("\n");
+	}
+	if (ascii)
+	{
+		x = c;
+		for (i=0;i<len;i++)
+		{
+			if ((i % amargin) == 0 && i>0) printk("\n");
+			if ((i % amargin) == 0) printk("0x%04x:", i);
+			if (*x > 26 && *x < 128) printk("%c", *x);
+			else printk(".");
+			x++;
+		}
+		printk("\n");
+	}
+}
+
+static void
+print_cmd(CommandList_struct *cp)
+{
+	printk("queue:%d\n", cp->Header.ReplyQueue);
+	printk("sglist:%d\n", cp->Header.SGList);
+	printk("sgtot:%d\n", cp->Header.SGTotal);
+	printk("Tag:0x%08x/0x%08x\n", cp->Header.Tag.upper, 
+			cp->Header.Tag.lower);
+	printk("LUN:0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+		cp->Header.LUN.LunAddrBytes[0],
+		cp->Header.LUN.LunAddrBytes[1],
+		cp->Header.LUN.LunAddrBytes[2],
+		cp->Header.LUN.LunAddrBytes[3],
+		cp->Header.LUN.LunAddrBytes[4],
+		cp->Header.LUN.LunAddrBytes[5],
+		cp->Header.LUN.LunAddrBytes[6],
+		cp->Header.LUN.LunAddrBytes[7]);
+	printk("CDBLen:%d\n", cp->Request.CDBLen);
+	printk("Type:%d\n",cp->Request.Type.Type);
+	printk("Attr:%d\n",cp->Request.Type.Attribute);
+	printk(" Dir:%d\n",cp->Request.Type.Direction);
+	printk("Timeout:%d\n",cp->Request.Timeout);
+	printk( "CDB: %02x %02x %02x %02x %02x %02x %02x %02x"
+		" %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		cp->Request.CDB[0], cp->Request.CDB[1],
+		cp->Request.CDB[2], cp->Request.CDB[3],
+		cp->Request.CDB[4], cp->Request.CDB[5],
+		cp->Request.CDB[6], cp->Request.CDB[7],
+		cp->Request.CDB[8], cp->Request.CDB[9],
+		cp->Request.CDB[10], cp->Request.CDB[11],
+		cp->Request.CDB[12], cp->Request.CDB[13],
+		cp->Request.CDB[14], cp->Request.CDB[15]),
+	printk("edesc.Addr: 0x%08x/0%08x, Len  = %d\n", 
+		cp->ErrDesc.Addr.upper, cp->ErrDesc.Addr.lower, 
+			cp->ErrDesc.Len);
+	printk("sgs..........Errorinfo:\n");
+	printk("scsistatus:%d\n", cp->err_info->ScsiStatus);
+	printk("senselen:%d\n", cp->err_info->SenseLen);
+	printk("cmd status:%d\n", cp->err_info->CommandStatus);
+	printk("resid cnt:%d\n", cp->err_info->ResidualCnt);
+	printk("offense size:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_size);
+	printk("offense byte:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_num);
+	printk("offense value:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+			
+}
+
+#endif
+
+static int 
+find_bus_target_lun(int ctlr, int *bus, int *target, int *lun)
+{
+	/* finds an unused bus, target, lun for a new device */
+	/* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
+	int i, found=0;
+	unsigned char target_taken[CCISS_MAX_SCSI_DEVS_PER_HBA];
+
+	memset(&target_taken[0], 0, CCISS_MAX_SCSI_DEVS_PER_HBA);
+
+	target_taken[SELF_SCSI_ID] = 1;	
+	for (i=0;i<ccissscsi[ctlr].ndevices;i++)
+		target_taken[ccissscsi[ctlr].dev[i].target] = 1;
+	
+	for (i=0;i<CCISS_MAX_SCSI_DEVS_PER_HBA;i++) {
+		if (!target_taken[i]) {
+			*bus = 0; *target=i; *lun = 0; found=1;
+			break;
+		}
+	}
+	return (!found);	
+}
+
+static int 
+cciss_scsi_add_entry(int ctlr, int hostno, 
+		unsigned char *scsi3addr, int devtype)
+{
+	/* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
+	int n = ccissscsi[ctlr].ndevices;
+	struct cciss_scsi_dev_t *sd;
+
+	if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
+		printk("cciss%d: Too many devices, "
+			"some will be inaccessible.\n", ctlr);
+		return -1;
+	}
+	sd = &ccissscsi[ctlr].dev[n];
+	if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0)
+		return -1;
+	memcpy(&sd->scsi3addr[0], scsi3addr, 8);
+	sd->devtype = devtype;
+	ccissscsi[ctlr].ndevices++;
+
+	/* initially, (before registering with scsi layer) we don't 
+	   know our hostno and we don't want to print anything first 
+	   time anyway (the scsi layer's inquiries will show that info) */
+	if (hostno != -1)
+		printk("cciss%d: %s device c%db%dt%dl%d added.\n", 
+			ctlr, DEVICETYPE(sd->devtype), hostno, 
+			sd->bus, sd->target, sd->lun);
+	return 0;
+}
+
+static void
+cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
+{
+	/* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
+	int i;
+	struct cciss_scsi_dev_t sd;
+
+	if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
+	sd = ccissscsi[ctlr].dev[entry];
+	for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
+		ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
+	ccissscsi[ctlr].ndevices--;
+	printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+		ctlr, DEVICETYPE(sd.devtype), hostno, 
+			sd.bus, sd.target, sd.lun);
+}
+
+
+#define SCSI3ADDR_EQ(a,b) ( \
+	(a)[7] == (b)[7] && \
+	(a)[6] == (b)[6] && \
+	(a)[5] == (b)[5] && \
+	(a)[4] == (b)[4] && \
+	(a)[3] == (b)[3] && \
+	(a)[2] == (b)[2] && \
+	(a)[1] == (b)[1] && \
+	(a)[0] == (b)[0])
+
+static int
+adjust_cciss_scsi_table(int ctlr, int hostno,
+	struct cciss_scsi_dev_t sd[], int nsds)
+{
+	/* sd contains scsi3 addresses and devtypes, but
+	   bus target and lun are not filled in.  This funciton
+	   takes what's in sd to be the current and adjusts
+	   ccissscsi[] to be in line with what's in sd. */ 
+
+	int i,j, found, changes=0;
+	struct cciss_scsi_dev_t *csd;
+	unsigned long flags;
+
+	CPQ_TAPE_LOCK(ctlr, flags);
+
+	/* find any devices in ccissscsi[] that are not in 
+	   sd[] and remove them from ccissscsi[] */
+
+	i = 0;
+	while(i<ccissscsi[ctlr].ndevices) {
+		csd = &ccissscsi[ctlr].dev[i];
+		found=0;
+		for (j=0;j<nsds;j++) {
+			if (SCSI3ADDR_EQ(sd[j].scsi3addr,
+				csd->scsi3addr)) {
+				if (sd[j].devtype == csd->devtype)
+					found=2;
+				else
+					found=1;
+				break;
+			}
+		}
+
+		if (found == 0) { /* device no longer present. */ 
+			changes++;
+			/* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
+				ctlr, DEVICETYPE(csd->devtype), hostno, 
+					csd->bus, csd->target, csd->lun); */
+			cciss_scsi_remove_entry(ctlr, hostno, i);
+			/* note, i not incremented */
+		} 
+		else if (found == 1) { /* device is different kind */
+			changes++;
+			printk("cciss%d: device c%db%dt%dl%d type changed "
+				"(device type now %s).\n",
+				ctlr, hostno, csd->bus, csd->target, csd->lun,
+					DEVICETYPE(csd->devtype));
+			csd->devtype = sd[j].devtype;
+			i++;	/* so just move along. */
+		} else 		/* device is same as it ever was, */
+			i++;	/* so just move along. */
+	}
+
+	/* Now, make sure every device listed in sd[] is also
+ 	   listed in ccissscsi[], adding them if they aren't found */
+
+	for (i=0;i<nsds;i++) {
+		found=0;
+		for (j=0;j<ccissscsi[ctlr].ndevices;j++) {
+			csd = &ccissscsi[ctlr].dev[j];
+			if (SCSI3ADDR_EQ(sd[i].scsi3addr,
+				csd->scsi3addr)) {
+				if (sd[i].devtype == csd->devtype)
+					found=2;	/* found device */
+				else
+					found=1; 	/* found a bug. */
+				break;
+			}
+		}
+		if (!found) {
+			changes++;
+			if (cciss_scsi_add_entry(ctlr, hostno, 
+				&sd[i].scsi3addr[0], sd[i].devtype) != 0)
+				break;
+		} else if (found == 1) {
+			/* should never happen... */
+			changes++;
+			printk("cciss%d: device unexpectedly changed type\n",
+				ctlr);
+			/* but if it does happen, we just ignore that device */
+		}
+	}
+	CPQ_TAPE_UNLOCK(ctlr, flags);
+
+	if (!changes) 
+		printk("cciss%d: No device changes detected.\n", ctlr);
+
+	return 0;
+}
+
+static int
+lookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr)
+{
+	int i;
+	struct cciss_scsi_dev_t *sd;
+	unsigned long flags;
+
+	CPQ_TAPE_LOCK(ctlr, flags);
+	for (i=0;i<ccissscsi[ctlr].ndevices;i++) {
+		sd = &ccissscsi[ctlr].dev[i];
+		if (sd->bus == bus &&
+		    sd->target == target &&
+		    sd->lun == lun) {
+			memcpy(scsi3addr, &sd->scsi3addr[0], 8);
+			CPQ_TAPE_UNLOCK(ctlr, flags);
+			return 0;
+		}
+	}
+	CPQ_TAPE_UNLOCK(ctlr, flags);
+	return -1;
+}
+
+
+static void 
+cciss_find_non_disk_devices(int cntl_num)
+{
+	ReportLunData_struct *ld_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int i;
+	int listlength = 0;
+	int num_luns;
+	unsigned char scsi3addr[8];
+	unsigned long flags;
+	int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+
+	hba[cntl_num]->scsi_ctlr = (void *)
+		kmalloc(sizeof(struct cciss_scsi_adapter_data_t),
+			GFP_KERNEL);	
+	if (hba[cntl_num]->scsi_ctlr == NULL)
+		return;
+
+	((struct cciss_scsi_adapter_data_t *) 
+		hba[cntl_num]->scsi_ctlr)->scsi_host = NULL;
+	((struct cciss_scsi_adapter_data_t *) 
+		hba[cntl_num]->scsi_ctlr)->lock = SPIN_LOCK_UNLOCKED;
+	((struct cciss_scsi_adapter_data_t *) 
+		hba[cntl_num]->scsi_ctlr)->registered = 0;
+
+	if (scsi_cmd_stack_setup(cntl_num) != 0) {
+		printk("Trouble, returned non-zero!\n");
+		return;
+	}
+
+	ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+        if (inq_buff == NULL) {
+                printk(KERN_ERR "cciss: out of memory\n");
+                kfree(ld_buff);
+                return;
+        }
+
+	/* Get the physical luns */ 
+	return_code = sendcmd(CISS_REPORT_PHYS, cntl_num, ld_buff, 
+			reportlunsize, 0, 0, 0, NULL );
+
+	if( return_code == IO_OK) {
+		unsigned char *c = &ld_buff->LUNListLength[0];
+		listlength = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+	} 
+	else {  /* getting report of physical luns failed */
+		printk(KERN_WARNING "cciss: report physical luns"
+			" command failed\n");
+		listlength = 0;
+	}
+
+	CPQ_TAPE_LOCK(cntl_num, flags);
+	ccissscsi[cntl_num].ndevices = 0;
+	num_luns = listlength / 8; // 8 bytes pre entry
+	/* printk("Found %d LUNs\n", num_luns); */
+
+	if (num_luns > CISS_MAX_PHYS_LUN)
+	{
+		printk(KERN_WARNING 
+			"cciss: Maximum physical LUNs (%d) exceeded.  "
+			"%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, 
+			num_luns - CISS_MAX_PHYS_LUN);
+		num_luns = CISS_MAX_PHYS_LUN;
+	}
+
+	for(i=0; i<num_luns; i++) {
+		/* Execute an inquiry to figure the device type */
+		memset(inq_buff, 0, sizeof(InquiryData_struct));
+		memcpy(scsi3addr, ld_buff->LUN[i], 8); /* ugly... */
+		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+                	sizeof(InquiryData_struct), 2, 0 ,0, scsi3addr );
+	  	if (return_code == IO_OK) {
+			if(inq_buff->data_byte[8] == 0xFF)
+			{
+			   printk(KERN_WARNING "cciss: inquiry failed\n");
+                        } else {
+			   int devtype;
+
+			   /* printk("Inquiry...\n");
+			   print_bytes((unsigned char *) inq_buff, 36, 1, 1); */
+			   devtype = (inq_buff->data_byte[0] & 0x1f);
+
+			   switch (devtype)
+			   {
+			    case 0x01: /* sequential access, (tape) */
+			    case 0x08: /* medium changer */
+					  /* this is the only kind of dev */
+					  /* we want to expose here. */
+				if (cciss_scsi_add_entry(cntl_num, -1,
+					(unsigned char *) ld_buff->LUN[i],
+					devtype) != 0) 
+						i=num_luns; // leave loop
+				break;
+			    default: 
+				break;
+			   }
+
+			}
+		}
+		else printk("cciss: inquiry failed.\n");
+	}
+#if 0
+	for (i=0;i<ccissscsi[cntl_num].ndevices;i++)
+		printk("Tape device presented at c%db%dt%dl%d\n", 
+			cntl_num, // <-- this is wrong
+			ccissscsi[cntl_num].dev[i].bus,
+			ccissscsi[cntl_num].dev[i].target,
+			ccissscsi[cntl_num].dev[i].lun);
+#endif			
+	CPQ_TAPE_UNLOCK(cntl_num, flags);
+	kfree(ld_buff);
+	kfree(inq_buff);
+	return;
+}
+
+static void
+complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
+{
+	Scsi_Cmnd *cmd;
+	ctlr_info_t *ctlr;
+	u64bit addr64;
+	ErrorInfo_struct *ei;
+
+	ei = cp->err_info;
+
+	/* First, see if it was a message rather than a command */
+	if (cp->Request.Type.Type == TYPE_MSG)  {
+		cp->cmd_type = CMD_MSG_DONE;
+		return;
+	}
+
+	cmd = (Scsi_Cmnd *) cp->scsi_cmd;	
+	ctlr = hba[cp->ctlr];
+
+	/* undo the DMA mappings */
+
+	if (cmd->use_sg) {
+		pci_unmap_sg(ctlr->pdev,
+			cmd->buffer, cmd->use_sg,
+				scsi_to_pci_dma_dir(cmd->sc_data_direction)); 
+	}
+	else if (cmd->request_bufflen) {
+		addr64.val32.lower = cp->SG[0].Addr.lower;
+                addr64.val32.upper = cp->SG[0].Addr.upper;
+                pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
+                	cmd->request_bufflen, 
+				scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
+
+	cmd->result = (DID_OK << 16); 		/* host byte */
+	cmd->result |= (COMMAND_COMPLETE << 8);	/* msg byte */
+	/* cmd->result |= (GOOD < 1); */		/* status byte */
+
+	cmd->result |= (ei->ScsiStatus);
+	/* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus);  */
+
+	/* copy the sense data whether we need to or not. */
+
+	memcpy(cmd->sense_buffer, ei->SenseInfo, 
+		ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
+			SCSI_SENSE_BUFFERSIZE : 
+			ei->SenseLen);
+	cmd->resid = ei->ResidualCnt;
+
+	if(ei->CommandStatus != 0) 
+	{ /* an error has occurred */ 
+		switch(ei->CommandStatus)
+		{
+			case CMD_TARGET_STATUS:
+				/* Pass it up to the upper layers... */
+				if( ei->ScsiStatus)
+                		{
+#if 0
+                    			printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n",
+                        			cp,  
+						ei->ScsiStatus); 
+#endif
+					cmd->result |= (ei->ScsiStatus < 1);
+                		}
+				else {  /* scsi status is zero??? How??? */
+					
+	/* Ordinarily, this case should never happen, but there is a bug
+	   in some released firmware revisions that allows it to happen
+	   if, for example, a 4100 backplane loses power and the tape
+	   drive is in it.  We assume that it's a fatal error of some
+	   kind because we can't show that it wasn't. We will make it
+	   look like selection timeout since that is the most common
+	   reason for this to occur, and it's severe enough. */
+
+					cmd->result = DID_NO_CONNECT << 16;
+				}
+			break;
+			case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+			break;
+			case CMD_DATA_OVERRUN:
+				printk(KERN_WARNING "cciss: cp %p has"
+					" completed with data overrun "
+					"reported\n", cp);
+			break;
+			case CMD_INVALID: {
+				/* print_bytes(cp, sizeof(*cp), 1, 0);
+				print_cmd(cp); */
+     /* We get CMD_INVALID if you address a non-existent tape drive instead
+	of a selection timeout (no response).  You will see this if you yank 
+	out a tape drive, then try to access it. This is kind of a shame
+	because it means that any other CMD_INVALID (e.g. driver bug) will
+	get interpreted as a missing target. */
+				cmd->result = DID_NO_CONNECT << 16;
+				}
+			break;
+			case CMD_PROTOCOL_ERR:
+                                printk(KERN_WARNING "cciss: cp %p has "
+					"protocol error \n", cp);
+                        break;
+			case CMD_HARDWARE_ERR:
+				cmd->result = DID_ERROR << 16;
+                                printk(KERN_WARNING "cciss: cp %p had " 
+                                        " hardware error\n", cp);
+                        break;
+			case CMD_CONNECTION_LOST:
+				cmd->result = DID_ERROR << 16;
+				printk(KERN_WARNING "cciss: cp %p had "
+					"connection lost\n", cp);
+			break;
+			case CMD_ABORTED:
+				cmd->result = DID_ABORT << 16;
+				printk(KERN_WARNING "cciss: cp %p was "
+					"aborted\n", cp);
+			break;
+			case CMD_ABORT_FAILED:
+				cmd->result = DID_ERROR << 16;
+				printk(KERN_WARNING "cciss: cp %p reports "
+					"abort failed\n", cp);
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				cmd->result = DID_ABORT << 16;
+				printk(KERN_WARNING "cciss: cp %p aborted "
+					"do to an unsolicited abort\n", cp);
+			break;
+			case CMD_TIMEOUT:
+				cmd->result = DID_TIME_OUT << 16;
+				printk(KERN_WARNING "cciss: cp %p timedout\n",
+					cp);
+			break;
+			default:
+				cmd->result = DID_ERROR << 16;
+				printk(KERN_WARNING "cciss: cp %p returned "
+					"unknown status %x\n", cp, 
+						ei->CommandStatus); 
+		}
+	}
+	// printk("c:%p:c%db%dt%dl%d ", cmd, ctlr->ctlr, cmd->channel, 
+	//	cmd->target, cmd->lun);
+	cmd->scsi_done(cmd);
+	scsi_cmd_free(ctlr, cp);
+}
+
+/* cciss_scsi_detect is called from the scsi mid layer.  
+   The scsi mid layer (scsi_register_host) is
+   called from cciss.c:cciss_init_one().  */
+
+int __init 
+cciss_scsi_detect(Scsi_Host_Template *tpnt)
+{
+	int i;
+	struct Scsi_Host *sh;
+
+	/* Tell the kernel we want to be a SCSI driver... */
+	sh = scsi_register(tpnt, sizeof(struct ctlr_info *));
+	if (sh == NULL) return 0;
+
+	sh->io_port = 0;	// good enough?  FIXME, 
+	sh->n_io_port = 0;	// I don't think we use these two...
+
+	sh->this_id = SELF_SCSI_ID;  
+
+	/* This is a bit kludgey, using the adapter name to figure out */
+	/* which scsi host template we've got, won't scale beyond 9 ctlrs. */
+	i = tpnt->name[5] - '0';
+
+#	if MAX_CTLR > 9
+#		error "cciss_scsi.c: MAX_CTLR > 9, code maintenance needed."
+#	endif	
+
+	if (i<0 || i>=MAX_CTLR || hba[i] == NULL) {
+		/* we didn't find ourself... we shouldn't get here. */
+		printk("cciss_scsi_detect: could not find ourself in hba[]\n");
+		return 0;
+	}
+
+	((struct cciss_scsi_adapter_data_t *) 
+		hba[i]->scsi_ctlr)->scsi_host = (void *) sh;
+	sh->hostdata[0] = (unsigned long) hba[i];
+	sh->irq = hba[i]->intr;
+	sh->unique_id = sh->irq;
+	scsi_set_pci_device(sh, hba[i]->pdev);
+
+	return 1;	/* Say we have 1 scsi adapter, this will be */
+			/* called multiple times, once for each adapter */
+			/* from cciss.c:cciss_init_one().  We do it this */
+			/* way for PCI-hot plug reasons. (we don't know how */
+			/* many adapters we have total, so we say we have */
+			/* 1, each of a unique type.) */
+}
+
+static void __exit cleanup_cciss_module(void);
+int
+cciss_scsi_release(struct Scsi_Host *sh)
+{
+	return 0;
+}
+
+static void
+cciss_unmap_one(struct pci_dev *pdev,
+		CommandList_struct *cp,
+		size_t buflen,
+		int data_direction)
+{
+	u64bit addr64;
+
+	addr64.val32.lower = cp->SG[0].Addr.lower;
+	addr64.val32.upper = cp->SG[0].Addr.upper;
+	pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction);
+}
+
+static void
+cciss_map_one(struct pci_dev *pdev,
+		CommandList_struct *cp,
+		unsigned char *buf,
+		size_t buflen,
+		int data_direction)
+{
+	__u64 addr64;
+
+	addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
+	cp->SG[0].Addr.lower = 
+	  (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+	cp->SG[0].Addr.upper =
+	  (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+	cp->SG[0].Len = buflen;
+	cp->Header.SGList = (__u8) 1;   /* no. SGs contig in this cmd */
+	cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
+}
+
+static int
+cciss_scsi_do_simple_cmd(ctlr_info_t *c,
+			CommandList_struct *cp,
+			unsigned char *scsi3addr, 
+			unsigned char *cdb,
+			unsigned char cdblen,
+			unsigned char *buf, int bufsize,
+			int direction)
+{
+	unsigned long flags;
+
+	cp->cmd_type = CMD_IOCTL_PEND;		// treat this like an ioctl 
+	cp->scsi_cmd = NULL;
+	cp->Header.ReplyQueue = 0;  // unused in simple mode
+	memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN));
+	cp->Header.Tag.lower = cp->busaddr;  // Use k. address of cmd as tag
+	// Fill in the request block...
+
+	/* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n", 
+		scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
+		scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */
+
+	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+	memcpy(cp->Request.CDB, cdb, cdblen);
+	cp->Request.Timeout = 1000;		// guarantee completion. 
+	cp->Request.CDBLen = cdblen;
+	cp->Request.Type.Type = TYPE_CMD;
+	cp->Request.Type.Attribute = ATTR_SIMPLE;
+	cp->Request.Type.Direction = direction;
+
+	/* Fill in the SG list and do dma mapping */
+	cciss_map_one(c->pdev, cp, 
+			(unsigned char *) buf, bufsize,
+			scsi_to_pci_dma_dir(SCSI_DATA_READ)); 
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+	addQ(&c->reqQ, cp);
+	c->Qdepth++;
+	start_io(c);
+	spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+
+	/* Wait for the request to complete */
+	while(cp->cmd_type != CMD_IOCTL_DONE)
+		schedule_timeout(1);
+
+	/* undo the dma mapping */
+	cciss_unmap_one(c->pdev, cp, bufsize,
+				scsi_to_pci_dma_dir(SCSI_DATA_READ)); 
+
+	return(0);
+}
+
+static void 
+cciss_scsi_interpret_error(CommandList_struct *cp)
+{
+	ErrorInfo_struct *ei;
+
+	ei = cp->err_info; 
+	switch(ei->CommandStatus)
+	{
+		case CMD_TARGET_STATUS:
+			printk(KERN_WARNING "cciss: cmd %p has "
+				"completed with errors\n", cp);
+			printk(KERN_WARNING "cciss: cmd %p "
+				"has SCSI Status = %x\n",
+					cp,  
+					ei->ScsiStatus);
+			if (ei->ScsiStatus == 0)
+				printk(KERN_WARNING 
+				"cciss:SCSI status is abnormally zero.  "
+				"(probably indicates selection timeout "
+				"reported incorrectly due to a known "
+				"firmware bug, circa July, 2001.)\n");
+		break;
+		case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
+			printk("UNDERRUN\n");
+		break;
+		case CMD_DATA_OVERRUN:
+			printk(KERN_WARNING "cciss: cp %p has"
+				" completed with data overrun "
+				"reported\n", cp);
+		break;
+		case CMD_INVALID: {
+			/* controller unfortunately reports SCSI passthru's */
+			/* to non-existent targets as invalid commands. */
+			printk(KERN_WARNING "cciss: cp %p is "
+				"reported invalid (probably means "
+				"target device no longer present)\n", 
+				cp); 
+			/* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
+			print_cmd(cp);  */
+			}
+		break;
+		case CMD_PROTOCOL_ERR:
+			printk(KERN_WARNING "cciss: cp %p has "
+				"protocol error \n", cp);
+		break;
+		case CMD_HARDWARE_ERR:
+			/* cmd->result = DID_ERROR << 16; */
+			printk(KERN_WARNING "cciss: cp %p had " 
+				" hardware error\n", cp);
+		break;
+		case CMD_CONNECTION_LOST:
+			printk(KERN_WARNING "cciss: cp %p had "
+				"connection lost\n", cp);
+		break;
+		case CMD_ABORTED:
+			printk(KERN_WARNING "cciss: cp %p was "
+				"aborted\n", cp);
+		break;
+		case CMD_ABORT_FAILED:
+			printk(KERN_WARNING "cciss: cp %p reports "
+				"abort failed\n", cp);
+		break;
+		case CMD_UNSOLICITED_ABORT:
+			printk(KERN_WARNING "cciss: cp %p aborted "
+				"do to an unsolicited abort\n", cp);
+		break;
+		case CMD_TIMEOUT:
+			printk(KERN_WARNING "cciss: cp %p timedout\n",
+				cp);
+		break;
+		default:
+			printk(KERN_WARNING "cciss: cp %p returned "
+				"unknown status %x\n", cp, 
+					ei->CommandStatus); 
+	}
+}
+
+static int
+cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, 
+		 InquiryData_struct *buf)
+{
+	int rc;
+	CommandList_struct *cp;
+	char cdb[6];
+	ErrorInfo_struct *ei;
+	unsigned long flags;
+
+	spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+	cp = scsi_cmd_alloc(c);
+	spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+	ei = cp->err_info; 
+
+	if (cp == NULL) {			/* trouble... */
+		printk("cmd_alloc returned NULL!\n");
+		return -1;
+	}
+
+	cdb[0] = CISS_INQUIRY;
+	cdb[1] = 0;
+	cdb[2] = 0;
+	cdb[3] = 0;
+	cdb[4] = sizeof(*buf) & 0xff;
+	cdb[5] = 0;
+	rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, 
+				6, (unsigned char *) buf, 
+				sizeof(*buf), XFER_READ);
+
+	if (rc != 0) return rc; /* something went wrong */
+
+	if (ei->CommandStatus != 0 && 
+	    ei->CommandStatus != CMD_DATA_UNDERRUN) {
+		cciss_scsi_interpret_error(cp);
+		rc = -1;
+	}
+	spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+	scsi_cmd_free(c, cp);
+	spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+	return rc;	
+}
+
+static int
+cciss_scsi_do_report_phys_luns(ctlr_info_t *c, 
+		ReportLunData_struct *buf, int bufsize)
+{
+	int rc;
+	CommandList_struct *cp;
+	unsigned char cdb[12];
+	unsigned char scsi3addr[8]; 
+	ErrorInfo_struct *ei;
+	unsigned long flags;
+
+	spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+	cp = scsi_cmd_alloc(c);
+	spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+	if (cp == NULL) {			/* trouble... */
+		printk("cmd_alloc returned NULL!\n");
+		return -1;
+	}
+
+	memset(&scsi3addr[0], 0, 8); /* address the controller */
+	cdb[0] = CISS_REPORT_PHYS;
+	cdb[1] = 0;
+	cdb[2] = 0;
+	cdb[3] = 0;
+	cdb[4] = 0;
+	cdb[5] = 0;
+	cdb[6] = (sizeof(*buf) >> 24) & 0xFF;  //MSB
+	cdb[7] = (sizeof(*buf) >> 16) & 0xFF;
+	cdb[8] = (sizeof(*buf) >> 8) & 0xFF;
+	cdb[9] = sizeof(*buf) & 0xFF;
+	cdb[10] = 0;
+	cdb[11] = 0;
+
+	rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, 
+				cdb, 12, 
+				(unsigned char *) buf, 
+				bufsize, XFER_READ);
+
+	if (rc != 0) return rc; /* something went wrong */
+
+	ei = cp->err_info; 
+	if (ei->CommandStatus != 0 && 
+	    ei->CommandStatus != CMD_DATA_UNDERRUN) {
+		cciss_scsi_interpret_error(cp);
+		rc = -1;
+	}
+	spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
+	scsi_cmd_free(c, cp);
+	spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
+	return rc;	
+}
+
+static void
+cciss_update_non_disk_devices(int cntl_num, int hostno)
+{
+	/* the idea here is we could get notified from /proc
+	   that some devices have changed, so we do a report 
+	   physical luns cmd, and adjust our list of devices 
+	   accordingly.  (We can't rely on the scsi-mid layer just
+	   doing inquiries, because the "busses" that the scsi 
+	   mid-layer probes are totally fabricated by this driver,
+	   so new devices wouldn't show up.
+
+	   the scsi3addr's of devices won't change so long as the 
+	   adapter is not reset.  That means we can rescan and 
+	   tell which devices we already know about, vs. new 
+	   devices, vs.  disappearing devices.
+
+	   Also, if you yank out a tape drive, then put in a disk
+	   in it's place, (say, a configured volume from another 
+	   array controller for instance)  _don't_ poke this driver 
+           (so it thinks it's still a tape, but _do_ poke the scsi 
+           mid layer, so it does an inquiry... the scsi mid layer 
+           will see the physical disk.  This would be bad.  Need to
+	   think about how to prevent that.  One idea would be to 
+	   snoop all scsi responses and if an inquiry repsonse comes
+	   back that reports a disk, chuck it an return selection
+	   timeout instead and adjust our table...  Not sure i like
+	   that though.  
+
+	 */
+
+	ReportLunData_struct *ld_buff;
+	InquiryData_struct *inq_buff;
+	unsigned char scsi3addr[8];
+	ctlr_info_t *c;
+	__u32 num_luns=0;
+	unsigned char *ch;
+	/* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */
+	struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
+	int ncurrent=0;
+	int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
+	int i;
+
+	c = (ctlr_info_t *) hba[cntl_num];	
+	ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return;
+	}
+	memset(ld_buff, 0, reportlunsize);
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+        if (inq_buff == NULL) {
+                printk(KERN_ERR "cciss: out of memory\n");
+                kfree(ld_buff);
+                return;
+	}
+
+	if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
+		ch = &ld_buff->LUNListLength[0];
+		num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
+		if (num_luns > CISS_MAX_PHYS_LUN) {
+			printk(KERN_WARNING 
+				"cciss: Maximum physical LUNs (%d) exceeded.  "
+				"%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, 
+				num_luns - CISS_MAX_PHYS_LUN);
+			num_luns = CISS_MAX_PHYS_LUN;
+		}
+	}
+	else {
+		printk(KERN_ERR  "cciss: Report physical LUNs failed.\n");
+		return;
+	}
+
+
+	/* adjust our table of devices */	
+	for(i=0; i<num_luns; i++)
+	{
+		int devtype;
+
+		/* for each physical lun, do an inquiry */
+		memset(inq_buff, 0, sizeof(InquiryData_struct));
+		memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
+
+		if (cciss_scsi_do_inquiry(hba[cntl_num], 
+			scsi3addr, inq_buff) != 0)
+		{
+			/* Inquiry failed (msg printed already) */
+			devtype = 0; /* so we will skip this device. */
+		} else /* what kind of device is this? */
+			devtype = (inq_buff->data_byte[0] & 0x1f);
+
+		switch (devtype)
+		{
+		  case 0x01: /* sequential access, (tape) */
+		  case 0x08: /* medium changer */
+			memcpy(&currentsd[ncurrent].scsi3addr[0], 
+				&scsi3addr[0], 8);
+			currentsd[ncurrent].devtype = devtype;
+			currentsd[ncurrent].bus = -1;
+			currentsd[ncurrent].target = -1;
+			currentsd[ncurrent].lun = -1;
+			ncurrent++;
+			break;
+		  default: 
+			break;
+		}
+	}
+
+	adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);
+
+	kfree(inq_buff);
+	kfree(ld_buff);
+	return;
+}
+
+static int
+is_keyword(char *ptr, int len, char *verb)  // Thanks to ncr53c8xx.c
+{
+	int verb_len = strlen(verb);
+	if (len >= verb_len && !memcmp(verb,ptr,verb_len))
+		return verb_len;
+	else
+		return 0;
+}
+
+static int
+cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length)
+{
+	int arg_len;
+
+	if ((arg_len = is_keyword(buffer, length, "rescan")) != 0)
+		cciss_update_non_disk_devices(ctlr, hostno);
+	else
+		return -EINVAL;
+	return length;
+}
+
+/* It's a pity that we need this, but, we do... */
+extern struct Scsi_Host *scsi_hostlist;  /* from ../scsi/hosts.c */
+
+int
+cciss_scsi_proc_info(char *buffer, /* data buffer */
+		char **start, 	   /* where data in buffer starts */
+		off_t offset,	   /* offset from start of imaginary file */
+		int length, 	   /* length of data in buffer */
+		int hostnum, 	   /* which host adapter (always zero for me) */
+		int func)	   /* 0 == read, 1 == write */
+{
+
+	int buflen, datalen;
+	struct Scsi_Host *sh;
+	int found;
+	ctlr_info_t *ci;
+	int cntl_num;
+
+	/* Lets see if we can find our Scsi_Host... 
+	   this might be kind of "bad", searching scis_hostlist this way
+	   but how else can we find the scsi host?  I think I've seen
+	   this coded both ways, (circular list and null terminated list)
+	   I coded it to work either way, since I wasn't sure.  */
+
+	sh = scsi_hostlist;
+	found=0;
+	do {
+		if (sh == NULL) break;
+		if (sh->host_no == hostnum) {
+			found++;
+			break;
+		}
+		sh = sh->next;
+	} while (sh != scsi_hostlist && sh != NULL);
+
+	if (sh == NULL || found == 0) /* This really shouldn't ever happen. */
+		return -EINVAL;
+
+	ci = (ctlr_info_t *) sh->hostdata[0];
+	if (ci == NULL)  /* This really shouldn't ever happen. */
+		return -EINVAL;
+
+	cntl_num = ci->ctlr;	/* Get our index into the hba[] array */
+
+	if (func == 0) {	/* User is reading from /proc/scsi/ciss*?/?*  */
+		buflen = sprintf(buffer, "hostnum=%d\n", hostnum); 	
+
+		datalen = buflen - offset;
+		if (datalen < 0) { 	/* they're reading past EOF. */
+			datalen = 0;
+			*start = buffer+buflen;	
+		} else
+			*start = buffer + offset;
+		return(datalen);
+	} else 	/* User is writing to /proc/scsi/cciss*?/?*  ... */
+		return cciss_scsi_user_command(cntl_num, hostnum,
+			buffer, length);	
+} 
+
+/* this is via the generic proc support */
+const char *
+cciss_scsi_info(struct Scsi_Host *sa)
+{
+	static char buf[300];
+	ctlr_info_t *ci;
+
+	/* probably need to work on putting a bit more info in here... */
+	/* this is output via the /proc filesystem. */
+
+	ci = (ctlr_info_t *) sa->hostdata[0];
+
+	sprintf(buf, "%s %c%c%c%c\n",
+		ci->product_name, 
+		ci->firm_ver[0],
+		ci->firm_ver[1],
+		ci->firm_ver[2],
+		ci->firm_ver[3]);
+
+	return buf; 
+}
+
+
+/* cciss_scatter_gather takes a Scsi_Cmnd, (cmd), and does the pci 
+   dma mapping  and fills in the scatter gather entries of the 
+   cciss command, cp. */
+
+static void
+cciss_scatter_gather(struct pci_dev *pdev, 
+		CommandList_struct *cp,	
+		Scsi_Cmnd *cmd)
+{
+	unsigned int use_sg, nsegs=0, len;
+	struct scatterlist *scatter = (struct scatterlist *) cmd->buffer;
+	__u64 addr64;
+
+	/* is it just one virtual address? */	
+	if (!cmd->use_sg) {
+		if (cmd->request_bufflen) {	/* anything to xfer? */
+
+			addr64 = (__u64) pci_map_single(pdev, 
+				cmd->request_buffer, 
+				cmd->request_bufflen, 
+				scsi_to_pci_dma_dir(cmd->sc_data_direction)); 
+	
+			cp->SG[0].Addr.lower = 
+			  (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+			cp->SG[0].Addr.upper =
+			  (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+			cp->SG[0].Len = cmd->request_bufflen;
+			nsegs=1;
+		}
+	} /* else, must be a list of virtual addresses.... */
+	else if (cmd->use_sg <= MAXSGENTRIES) {	/* not too many addrs? */
+
+		use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, 
+			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+
+		for (nsegs=0; nsegs < use_sg; nsegs++) {
+			addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
+			len  = sg_dma_len(&scatter[nsegs]);
+			cp->SG[nsegs].Addr.lower =
+			  (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+			cp->SG[nsegs].Addr.upper =
+			  (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+			cp->SG[nsegs].Len = len;
+			cp->SG[nsegs].Ext = 0;  // we are not chaining
+		}
+	} else BUG();
+
+	cp->Header.SGList = (__u8) nsegs;   /* no. SGs contig in this cmd */
+	cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+	return;
+}
+
+
+int 
+cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+	ctlr_info_t **c;
+	int ctlr, rc;
+	unsigned char scsi3addr[8];
+	CommandList_struct *cp;
+	unsigned long flags;
+
+	// Get the ptr to our adapter structure (hba[i]) out of cmd->host.
+	// We violate cmd->host privacy here.  (Is there another way?)
+	c = (ctlr_info_t **) &cmd->host->hostdata[0];	
+	ctlr = (*c)->ctlr;
+
+	rc = lookup_scsi3addr(ctlr, cmd->channel, cmd->target, cmd->lun, 
+			scsi3addr);
+	if (rc != 0) {
+		/* the scsi nexus does not match any that we presented... */
+		/* pretend to mid layer that we got selection timeout */
+		cmd->result = DID_NO_CONNECT << 16;
+		done(cmd);
+		/* we might want to think about registering controller itself
+		   as a processor device on the bus so sg binds to it. */
+		return 0;
+	}
+
+	/* printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n", 
+		cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun);*/
+	// printk("q:%p:c%db%dt%dl%d ", cmd, ctlr, cmd->channel, 
+	//	cmd->target, cmd->lun);
+
+	/* Ok, we have a reasonable scsi nexus, so send the cmd down, and
+           see what the device thinks of it. */
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	cp = scsi_cmd_alloc(*c);
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+	if (cp == NULL) {			/* trouble... */
+		printk("scsi_cmd_alloc returned NULL!\n");
+		/* FIXME: next 3 lines are -> BAD! <- */
+		cmd->result = DID_NO_CONNECT << 16;
+		done(cmd);
+		return 0;
+	}
+
+	// Fill in the command list header
+
+	cmd->scsi_done = done;    // save this for use by completion code 
+
+	// save cp in case we have to abort it 
+	cmd->host_scribble = (unsigned char *) cp; 
+
+	cp->cmd_type = CMD_SCSI;
+	cp->scsi_cmd = cmd;
+	cp->Header.ReplyQueue = 0;  // unused in simple mode
+	memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+	cp->Header.Tag.lower = cp->busaddr;  // Use k. address of cmd as tag
+	
+	// Fill in the request block...
+
+	cp->Request.Timeout = 1000; // guarantee completion
+	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
+	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
+	cp->Request.CDBLen = cmd->cmd_len;
+	memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);
+	cp->Request.Type.Type = TYPE_CMD;
+	cp->Request.Type.Attribute = ATTR_SIMPLE;
+	switch(cmd->sc_data_direction)
+	{
+	  case SCSI_DATA_WRITE: cp->Request.Type.Direction = XFER_WRITE; break;
+	  case SCSI_DATA_READ: cp->Request.Type.Direction = XFER_READ; break;
+	  case SCSI_DATA_NONE: cp->Request.Type.Direction = XFER_NONE; break;
+
+	  case SCSI_DATA_UNKNOWN:
+		// This can happen if a buggy application does a scsi passthru
+		// and sets both inlen and outlen to non-zero. ( see
+		// ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
+
+	  	cp->Request.Type.Direction = XFER_RSVD;
+		// This is technically wrong, and cciss controllers should
+		// reject it with CMD_INVALID, which is the most correct 
+		// response, but non-fibre backends appear to let it 
+		// slide by, and give the same results as if this field
+		// were set correctly.  Either way is acceptable for
+		// our purposes here.
+
+		break;
+
+	  default: 
+		printk("cciss: unknown data direction: %d\n", 
+			cmd->sc_data_direction);
+		BUG();
+		break;
+	}
+
+	cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
+
+	/* Put the request on the tail of the request queue */
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	addQ(&(*c)->reqQ, cp);
+	(*c)->Qdepth++;
+	start_io(*c);
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+	/* the cmd'll come back via intr handler in complete_scsi_command()  */
+	return 0;
+}
+
+static void 
+init_driver_template(int ctlr)
+{
+	memset(&driver_template[ctlr], 0, sizeof(driver_template[ctlr]));
+	driver_template[ctlr].name = ccissscsi[ctlr].name;
+	driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+	driver_template[ctlr].detect = cciss_scsi_detect;
+	driver_template[ctlr].release = cciss_scsi_release;
+	driver_template[ctlr].proc_info = cciss_scsi_proc_info;
+	driver_template[ctlr].queuecommand = cciss_scsi_queue_command;
+	driver_template[ctlr].eh_abort_handler = NULL;
+	driver_template[ctlr].eh_device_reset_handler = NULL;
+	driver_template[ctlr].bios_param = scsicam_bios_param;
+	driver_template[ctlr].can_queue = SCSI_CCISS_CAN_QUEUE;
+	driver_template[ctlr].this_id = 7;
+	driver_template[ctlr].sg_tablesize = MAXSGENTRIES;
+	driver_template[ctlr].cmd_per_lun = 1;
+	driver_template[ctlr].use_clustering = DISABLE_CLUSTERING;
+	driver_template[ctlr].module = THIS_MODULE;
+
+	/* set scsi_host to NULL so our detect routine will 
+	   find us on register */
+
+	((struct cciss_scsi_adapter_data_t *) 
+		hba[ctlr]->scsi_ctlr)->scsi_host = NULL;
+
+}
+
+static void 
+cciss_unregister_scsi(int ctlr)
+{
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+	unsigned long flags;
+
+	/* we are being forcibly unloaded, and may not refuse. */
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+
+	/* if we weren't ever actually registered, don't unregister */ 
+	if (((struct cciss_scsi_adapter_data_t *) 
+		hba[ctlr]->scsi_ctlr)->registered) {
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+		scsi_unregister_host(&driver_template[ctlr]);
+		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	}
+	init_driver_template(ctlr);
+	scsi_cmd_stack_free(ctlr);
+	kfree(hba[ctlr]->scsi_ctlr);
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+}
+
+static int 
+cciss_register_scsi(int ctlr, int this_is_init_time)
+{
+	unsigned long flags;
+
+	CPQ_TAPE_LOCK(ctlr, flags);
+	driver_template[ctlr].name = ccissscsi[ctlr].name;
+	driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
+	driver_template[ctlr].module = THIS_MODULE;;
+
+	/* Since this is really a block driver, the SCSI core may not be 
+	   initialized yet, in which case, calling scsi_register_host
+	   would hang.  instead, we will do it later, via /proc filesystem 
+	   and rc scripts, when we know SCSI core is good to go. */
+
+	if (this_is_init_time) {
+		CPQ_TAPE_UNLOCK(ctlr, flags);
+		return 0;
+	}
+
+	/* Only register if SCSI devices are detected. */
+	if (ccissscsi[ctlr].ndevices != 0) {
+		((struct cciss_scsi_adapter_data_t *) 
+			hba[ctlr]->scsi_ctlr)->registered = 1;
+		CPQ_TAPE_UNLOCK(ctlr, flags);
+		return scsi_register_host(&driver_template[ctlr]);
+	}
+	CPQ_TAPE_UNLOCK(ctlr, flags);
+	printk(KERN_INFO 
+		"cciss%d: No appropriate SCSI device detected, "
+		"SCSI subsystem not engaged.\n", ctlr);
+	return 0;
+}
+
+static int 
+cciss_engage_scsi(int ctlr)
+{
+	struct cciss_scsi_adapter_data_t *sa;
+	struct cciss_scsi_cmd_stack_t *stk;
+	unsigned long flags;
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
+	stk = &sa->cmd_stack; 
+
+	if (((struct cciss_scsi_adapter_data_t *) 
+		hba[ctlr]->scsi_ctlr)->registered) {
+		printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+		return ENXIO;
+	}
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+	cciss_update_non_disk_devices(ctlr, -1);
+	cciss_register_scsi(ctlr, 0);
+	return 0;
+}
+
+static void
+cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
+{
+	int size;
+	unsigned int flags;
+
+	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
+
+	CPQ_TAPE_LOCK(ctlr, flags);
+	size = sprintf(buffer + *len, 
+		"       Sequential access devices: %d\n\n",
+			ccissscsi[ctlr].ndevices);
+	CPQ_TAPE_UNLOCK(ctlr, flags);
+	*pos += size; *len += size;
+}
+
+#else /* no CONFIG_CISS_SCSI_TAPE */
+
+/* If no tape support, then these become defined out of existence */
+
+#define cciss_find_non_disk_devices(cntl_num)
+#define cciss_unregister_scsi(ctlr)
+#define cciss_register_scsi(ctlr, this_is_init_time)
+#define cciss_proc_tape_report(ctlr, buffer, pos, len)
+
+#endif /* CONFIG_CISS_SCSI_TAPE */
diff -urN linux-2.5.2-pre11/drivers/block/cciss_scsi.h linux/drivers/block/cciss_scsi.h
--- linux-2.5.2-pre11/drivers/block/cciss_scsi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/cciss_scsi.h	Mon Jan 14 18:28:28 2002
@@ -0,0 +1,98 @@
+/*
+ *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
+ *    Copyright 2001 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ */
+#ifdef CONFIG_CISS_SCSI_TAPE
+#ifndef _CCISS_SCSI_H_
+#define _CCISS_SCSI_H_
+
+#include <scsi/scsicam.h> /* possibly irrelevant, since we don't show disks */
+
+		// the scsi id of the adapter...
+#define SELF_SCSI_ID 15
+		// 15 is somewhat arbitrary, since the scsi-2 bus
+		// that's presented by the driver to the OS is
+		// fabricated.  The "real" scsi-3 bus the 
+		// hardware presents is fabricated too.
+		// The actual, honest-to-goodness physical
+		// bus that the devices are attached to is not 
+		// addressible natively, and may in fact turn
+		// out to be not scsi at all.
+
+#define SCSI_CCISS_CAN_QUEUE 2
+
+/* this notation works fine for static initializations (as is the usual
+   case for linux scsi drivers), but not so well for dynamic settings,
+   so, if you change this, you also have to change cciss_unregister_scsi()
+   in cciss_scsi.c  */
+#define CCISS_SCSI {    \
+	name:           	"",				\
+	detect:         	cciss_scsi_detect,		\
+	release:        	cciss_scsi_release,		\
+	proc_info:           	cciss_scsi_proc_info,		\
+	queuecommand:   	cciss_scsi_queue_command,	\
+	bios_param:     	scsicam_bios_param,		\
+	can_queue:      	SCSI_CCISS_CAN_QUEUE,		\
+	this_id:        	7,				\
+	sg_tablesize:   	MAXSGENTRIES, 			\
+	cmd_per_lun:		1,				\
+	use_clustering:		DISABLE_CLUSTERING,\
+} 
+
+/* 
+	info:           	cciss_scsi_info,		\
+
+Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
+Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
+
+If the upper scsi layer tries to track how many commands we have 
+outstanding, it will be operating under the misapprehension that it is
+the only one sending us requests.  We also have the block interface,
+which is where most requests must surely come from, so the upper layer's
+notion of how many requests we have outstanding will be wrong most or
+all of the time. 
+
+Note, the normal SCSI mid-layer error handling doesn't work well
+for this driver because 1) it takes the io_request_lock before
+calling error handlers and uses a local variable to store flags,
+so the io_request_lock cannot be released and interrupts enabled
+inside the error handlers, and, the error handlers cannot poll
+for command completion because they might get commands from the
+block half of the driver completing, and not know what to do
+with them.  That's what we get for making a hybrid scsi/block
+driver, I suppose.
+
+*/
+
+struct cciss_scsi_dev_t {
+	int devtype;
+	int bus, target, lun;		/* as presented to the OS */
+	unsigned char scsi3addr[8];	/* as presented to the HW */
+};
+
+struct cciss_scsi_hba_t {
+	char *name;
+	int ndevices;
+#define CCISS_MAX_SCSI_DEVS_PER_HBA 16
+	struct cciss_scsi_dev_t dev[CCISS_MAX_SCSI_DEVS_PER_HBA];
+};
+
+#endif /* _CCISS_SCSI_H_ */
+#endif /* CONFIG_CISS_SCSI_TAPE */
diff -urN linux-2.5.2-pre11/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- linux-2.5.2-pre11/drivers/block/cpqarray.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/cpqarray.c	Mon Jan 14 18:28:28 2002
@@ -32,6 +32,7 @@
 #include <linux/blkpg.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
@@ -70,6 +71,7 @@
 
 static int nr_ctlr;
 static ctlr_info_t *hba[MAX_CTLR];
+static devfs_handle_t de_arr[MAX_CTLR][NWD];
 
 static int eisa[8];
 
@@ -336,6 +338,7 @@
 
 		del_gendisk(&ida_gendisk[i]);
 	}
+	devfs_unregister(devfs_find_handle(NULL, "ida", 0, 0, 0, 0));
 	remove_proc_entry("cpqarray", proc_root_driver);
 	kfree(ida);
 	kfree(ida_sizes);
@@ -486,6 +489,8 @@
 		ida_gendisk[i].part = ida + (i*256);
 		ida_gendisk[i].sizes = ida_sizes + (i*256);
 		ida_gendisk[i].nr_real = 0; 
+		ida_gendisk[i].de_arr = de_arr[i]; 
+		ida_gendisk[i].fops = &ida_fops; 
 	
 		/* Get on the disk list */
 		add_gendisk(&ida_gendisk[i]);
@@ -1794,6 +1799,14 @@
                 			kfree(id_ldrive);
                 			return;
 
+				}
+				if (!de_arr[ctlr][log_unit]) {
+					char txt[16];
+
+					sprintf(txt, "ida/c%dd%d", ctlr,
+						log_unit);
+					de_arr[ctlr][log_unit] =
+						devfs_mk_dir(NULL, txt, NULL);
 				}
 				info_p->phys_drives =
 				    sense_config_buf->ctlr_phys_drv;
diff -urN linux-2.5.2-pre11/drivers/block/elevator.c linux/drivers/block/elevator.c
--- linux-2.5.2-pre11/drivers/block/elevator.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/elevator.c	Mon Jan 14 18:28:28 2002
@@ -58,8 +58,6 @@
 
 	next_rq = list_entry(next, struct request, queuelist);
 
-	BUG_ON(next_rq->flags & REQ_STARTED);
-
 	/*
 	 * not a sector based request
 	 */
@@ -147,9 +145,10 @@
 	 */
 	if (q->last_merge) {
 		struct request *__rq = list_entry_rq(q->last_merge);
-		BUG_ON(__rq->flags & REQ_STARTED);
 
-		if ((ret = elv_try_merge(__rq, bio)))
+		if (!rq_mergeable(__rq))
+			q->last_merge = NULL;
+		else if ((ret = elv_try_merge(__rq, bio)))
 			*req = __rq;
 	}
 
@@ -230,6 +229,12 @@
 {
 	elevator_t *e = &q->elevator;
 	int lat = 0, *latency = e->elevator_data;
+
+	/*
+	 * it's a bug to let this rq preempt an already started request
+	 */
+	if (insert_here->next != &q->queue_head)
+		BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
 
 	if (!(rq->flags & REQ_BARRIER))
 		lat = latency[rq_data_dir(rq)];
diff -urN linux-2.5.2-pre11/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.5.2-pre11/drivers/block/ll_rw_blk.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/ll_rw_blk.c	Mon Jan 14 18:28:28 2002
@@ -818,7 +818,6 @@
 	q->plug_tq.data		= q;
 	q->queue_flags		= (1 << QUEUE_FLAG_CLUSTER);
 	q->queue_lock		= lock;
-	q->last_merge		= NULL;
 	
 	blk_queue_segment_boundary(q, 0xffffffff);
 
@@ -964,12 +963,6 @@
 	drive_stat_acct(req, req->nr_sectors, 1);
 
 	/*
-	 * it's a bug to let this rq preempt an already started request
-	 */
-	if (insert_here->next != &q->queue_head)
-		BUG_ON(list_entry_rq(insert_here->next)->flags & REQ_STARTED);
-
-	/*
 	 * elevator indicated where it wants this request to be
 	 * inserted at elevator_merge time
 	 */
@@ -1121,8 +1114,10 @@
 	switch (el_ret) {
 		case ELEVATOR_BACK_MERGE:
 			BUG_ON(!rq_mergeable(req));
-			if (!q->back_merge_fn(q, req, bio))
+			if (!q->back_merge_fn(q, req, bio)) {
+				insert_here = &req->queuelist;
 				break;
+			}
 
 			elv_merge_cleanup(q, req, nr_sectors);
 
@@ -1135,8 +1130,10 @@
 
 		case ELEVATOR_FRONT_MERGE:
 			BUG_ON(!rq_mergeable(req));
-			if (!q->front_merge_fn(q, req, bio))
+			if (!q->front_merge_fn(q, req, bio)) {
+				insert_here = req->queuelist.prev;
 				break;
+			}
 
 			elv_merge_cleanup(q, req, nr_sectors);
 
diff -urN linux-2.5.2-pre11/drivers/block/nbd.c linux/drivers/block/nbd.c
--- linux-2.5.2-pre11/drivers/block/nbd.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/block/nbd.c	Mon Jan 14 18:28:28 2002
@@ -206,7 +206,7 @@
 	if (result <= 0)
 		HARDFAIL("Recv control failed.");
 	memcpy(&xreq, reply.handle, sizeof(xreq));
-	req = blkdev_entry_prev_request(&lo->queue_head);
+	req = blkdev_entry_to_request(lo->queue_head.prev);
 
 	if (xreq != req)
 		FAIL("Unexpected handle received.\n");
@@ -250,7 +250,7 @@
 			goto out;
 		}
 #ifdef PARANOIA
-		if (req != blkdev_entry_prev_request(&lo->queue_head)) {
+		if (req != blkdev_entry_to_request(lo->queue_head.prev)) {
 			printk(KERN_ALERT "NBD: I have problem...\n");
 		}
 		if (lo != &nbd_dev[minor(req->rq_dev)]) {
@@ -285,7 +285,7 @@
 #endif
 
 	while (!list_empty(&lo->queue_head)) {
-		req = blkdev_entry_prev_request(&lo->queue_head);
+		req = blkdev_entry_to_request(lo->queue_head.prev);
 #ifdef PARANOIA
 		if (!req) {
 			printk( KERN_ALERT "NBD: panic, panic, panic\n" );
diff -urN linux-2.5.2-pre11/drivers/char/rtc.c linux/drivers/char/rtc.c
--- linux-2.5.2-pre11/drivers/char/rtc.c	Tue Nov 13 09:16:05 2001
+++ linux/drivers/char/rtc.c	Mon Jan 14 18:28:28 2002
@@ -785,6 +785,9 @@
 		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
 #endif
 #if RTC_IRQ
+	if (rtc_has_irq == 0)
+		goto no_irq2;
+
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	spin_lock_irq(&rtc_lock);
@@ -792,6 +795,7 @@
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
 	spin_unlock_irq(&rtc_lock);
 	rtc_freq = 1024;
+no_irq2:
 #endif
 
 	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
diff -urN linux-2.5.2-pre11/drivers/md/md.c linux/drivers/md/md.c
--- linux-2.5.2-pre11/drivers/md/md.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/md/md.c	Mon Jan 14 18:28:29 2002
@@ -641,7 +641,7 @@
 	int err = 0;
 	struct block_device *bdev;
 
-	bdev = bdget(rdev->dev);
+	bdev = bdget(kdev_t_to_nr(rdev->dev));
 	if (!bdev)
 		return -ENOMEM;
 	err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
@@ -3697,7 +3697,7 @@
  * Searches all registered partitions for autorun RAID arrays
  * at boot time.
  */
-static int detected_devices[128];
+static kdev_t detected_devices[128];
 static int dev_cnt;
 
 void md_autodetect_dev(kdev_t dev)
@@ -3738,7 +3738,7 @@
 	}
 	dev_cnt = 0;
 
-	autorun_devices(-1);
+	autorun_devices(to_kdev_t(-1));
 }
 
 static struct {
@@ -3855,14 +3855,14 @@
 				*p++ = 0;
 
 			dev = name_to_kdev_t(devname);
-			handle = devfs_find_handle(NULL, devname, MAJOR (dev), MINOR (dev),
+			handle = devfs_find_handle(NULL, devname, major(dev), minor(dev),
 							DEVFS_SPECIAL_BLK, 1);
 			if (handle != 0) {
 				unsigned major, minor;
 				devfs_get_maj_min(handle, &major, &minor);
 				dev = mk_kdev(major, minor);
 			}
-			if (!dev) {
+			if (kdev_none(dev)) {
 				printk(KERN_WARNING "md: Unknown device name: %s\n", devname);
 				break;
 			}
@@ -3872,7 +3872,7 @@
 
 			devname = p;
 		}
-		devices[i] = 0;
+		devices[i] = to_kdev_t(0);
 
 		if (!md_setup_args.device_set[minor])
 			continue;
@@ -3908,7 +3908,10 @@
 			ainfo.layout = 0;
 			ainfo.chunk_size = md_setup_args.chunk[minor];
 			err = set_array_info(mddev, &ainfo);
-			for (i = 0; !err && (dev = devices[i]); i++) {
+			for (i = 0; !err && i <= MD_SB_DISKS; i++) {
+				dev = devices[i];
+				if (kdev_none(dev))
+					break;
 				dinfo.number = i;
 				dinfo.raid_disk = i;
 				dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC);
@@ -3922,7 +3925,10 @@
 			}
 		} else {
 			/* persistent */
-			for (i = 0; (dev = devices[i]); i++) {
+			for (i = 0; i <= MD_SB_DISKS; i++) {
+				dev = devices[i];
+				if (kdev_none(dev))
+					break;
 				dinfo.major = major(dev);
 				dinfo.minor = minor(dev);
 				add_new_disk (mddev, &dinfo);
diff -urN linux-2.5.2-pre11/drivers/md/multipath.c linux/drivers/md/multipath.c
--- linux-2.5.2-pre11/drivers/md/multipath.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/md/multipath.c	Mon Jan 14 18:28:29 2002
@@ -274,6 +274,7 @@
 	memcpy(bh_req, bh, sizeof(*bh));
 	bh_req->b_blocknr = bh->b_rsector;
 	bh_req->b_dev = multipath->dev;
+	/* FIXME - later we will need bdev here */
 	bh_req->b_rdev = multipath->dev;
 /*	bh_req->b_rsector = bh->n_rsector; */
 	bh_req->b_end_io = multipath_end_request;
diff -urN linux-2.5.2-pre11/drivers/md/raid5.c linux/drivers/md/raid5.c
--- linux-2.5.2-pre11/drivers/md/raid5.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/md/raid5.c	Mon Jan 14 18:28:29 2002
@@ -469,6 +469,7 @@
 
 	init_buffer(bh, raid5_end_read_request, sh);
 	bh->b_dev       = conf->disks[i].dev;
+	/* FIXME - later we will need bdev here */
 	bh->b_blocknr   = block;
 
 	bh->b_state	= (1 << BH_Req) | (1 << BH_Mapped);
@@ -1137,6 +1138,7 @@
 			else if (spare && action[i] == WRITE+1)
 				bh->b_dev = spare->dev;
 			else skip=1;
+			/* FIXME - later we will need bdev here */
 			if (!skip) {
 				PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, action[i]-1, i);
 				atomic_inc(&sh->count);
diff -urN linux-2.5.2-pre11/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c
--- linux-2.5.2-pre11/drivers/message/i2o/i2o_block.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/message/i2o/i2o_block.c	Mon Jan 14 18:28:29 2002
@@ -892,13 +892,13 @@
 	u32 m;
 	
 	
-	while (!list_empty(&q->queue_head)) {
+	while (!blk_queue_empty(q)) {
 		/*
 		 *	On an IRQ completion if there is an inactive
 		 *	request on the queue head it means it isnt yet
 		 *	ready to dispatch.
 		 */
-		req = blkdev_entry_next_request(&q->queue_head);
+		req = elv_next_request(q);
 
 		if(req->rq_status == RQ_INACTIVE)
 			return;
diff -urN linux-2.5.2-pre11/drivers/net/7990.c linux/drivers/net/7990.c
--- linux-2.5.2-pre11/drivers/net/7990.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/7990.c	Mon Jan 14 18:28:29 2002
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -569,7 +570,7 @@
         struct dev_mc_list *dmi=dev->mc_list;
         char *addrs;
         int i, j, bit, byte;
-        u32 crc, poly = CRC_POLYNOMIAL_LE;
+        u32 crc;
         
         /* set all multicast bits */
         if (dev->flags & IFF_ALLMULTI){ 
@@ -590,21 +591,7 @@
                 if (!(*addrs & 1))
                         continue;
                 
-                crc = 0xffffffff;
-                for (byte = 0; byte < 6; byte++)
-                        for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
-                        {
-                                int test;
-
-                                test = ((bit ^ crc) & 0x01);
-                                crc >>= 1;
-
-                                if (test)
-                                {
-                                        crc = crc ^ poly;
-                                }
-                        }
-                
+		crc = ether_crc_le(6, addrs);
                 crc = crc >> 26;
                 mcast_table [crc >> 4] |= 1 << (crc & 0xf);
         }
diff -urN linux-2.5.2-pre11/drivers/net/7990.h linux/drivers/net/7990.h
--- linux-2.5.2-pre11/drivers/net/7990.h	Thu Jan  4 13:00:55 2001
+++ linux/drivers/net/7990.h	Mon Jan 14 18:28:29 2002
@@ -132,9 +132,6 @@
 	char tx_full;
 };
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
  *              Am7990 Control and Status Registers
  */
diff -urN linux-2.5.2-pre11/drivers/net/8139cp.c linux/drivers/net/8139cp.c
--- linux-2.5.2-pre11/drivers/net/8139cp.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/8139cp.c	Mon Jan 14 18:28:29 2002
@@ -55,6 +55,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -722,22 +723,6 @@
 
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	return crc;
-}
 
 static void __cp_set_rx_mode (struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/8139too.c linux/drivers/net/8139too.c
--- linux-2.5.2-pre11/drivers/net/8139too.c	Sat Nov 24 11:26:37 2001
+++ linux/drivers/net/8139too.c	Mon Jan 14 18:28:29 2002
@@ -109,6 +109,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/completion.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -587,7 +588,6 @@
 static int rtl8139_close (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
 static void rtl8139_set_rx_mode (struct net_device *dev);
 static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
@@ -2370,23 +2370,6 @@
 
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	return crc;
-}
-
 
 static void __set_rx_mode (struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/8390.c linux/drivers/net/8390.c
--- linux-2.5.2-pre11/drivers/net/8390.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/8390.c	Mon Jan 14 18:28:29 2002
@@ -68,6 +68,7 @@
 #include <linux/in.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -885,27 +886,6 @@
 }
 
 /*
- * Update the given Autodin II CRC value with another data byte.
- */
-
-static inline u32 update_crc(u8 byte, u32 current_crc)
-{
-	int bit;
-	u8 ah = 0;
-	for (bit=0; bit<8; bit++) 
-	{
-		u8 carry = (current_crc>>31);
-		current_crc <<= 1;
-		ah = ((ah<<1) | carry) ^ byte;
-		if (ah&1)
-			current_crc ^= 0x04C11DB7;	/* CRC polynomial */
-		ah >>= 1;
-		byte >>= 1;
-	}
-	return current_crc;
-}
-
-/*
  * Form the 64 bit 8390 multicast table from the linked list of addresses
  * associated with this dev structure.
  */
@@ -916,16 +896,13 @@
 
 	for (dmi=dev->mc_list; dmi; dmi=dmi->next) 
 	{
-		int i;
 		u32 crc;
 		if (dmi->dmi_addrlen != ETH_ALEN) 
 		{
 			printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
 			continue;
 		}
-		crc = 0xffffffff;	/* initial CRC value */
-		for (i=0; i<ETH_ALEN; i++)
-			crc = update_crc(dmi->dmi_addr[i], crc);
+		crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
 		/* 
 		 * The 8390 uses the 6 most significant bits of the
 		 * CRC to index the multicast table.
diff -urN linux-2.5.2-pre11/drivers/net/Makefile.lib linux/drivers/net/Makefile.lib
--- linux-2.5.2-pre11/drivers/net/Makefile.lib	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/Makefile.lib	Mon Jan 14 18:28:29 2002
@@ -0,0 +1,69 @@
+# These drivers all require crc32.o
+obj-$(CONFIG_8139CP)		+= crc32.o
+obj-$(CONFIG_8139TOO)		+= crc32.o
+obj-$(CONFIG_A2065)		+= crc32.o
+obj-$(CONFIG_ARM_AM79C961A)	+= crc32.o
+obj-$(CONFIG_AT1700)		+= crc32.o
+obj-$(CONFIG_ATP)		+= crc32.o
+obj-$(CONFIG_DE2104X)		+= crc32.o
+obj-$(CONFIG_DE4X5)		+= crc32.o
+obj-$(CONFIG_DECLANCE)		+= crc32.o
+obj-$(CONFIG_DEPCA)		+= crc32.o
+obj-$(CONFIG_DL2K)		+= crc32.o
+obj-$(CONFIG_DM9102)		+= crc32.o
+obj-$(CONFIG_EPIC100)		+= crc32.o
+obj-$(CONFIG_EWRK3)		+= crc32.o
+obj-$(CONFIG_FEALNX)		+= crc32.o
+obj-$(CONFIG_HAPPYMEAL)		+= crc32.o
+obj-$(CONFIG_MACE)		+= crc32.o	
+obj-$(CONFIG_MACMACE)		+= crc32.o
+obj-$(CONFIG_MIPS_AU1000_ENET)	+= crc32.o
+obj-$(CONFIG_NATSEMI)		+= crc32.o	
+obj-$(CONFIG_PCMCIA_FMVJ18X)	+= crc32.o
+obj-$(CONFIG_PCMCIA_SMC91C92)	+= crc32.o
+obj-$(CONFIG_PCMCIA_XIRTULIP)	+= crc32.o
+obj-$(CONFIG_PCNET32)		+= crc32.o
+obj-$(CONFIG_SIS900)		+= crc32.o
+obj-$(CONFIG_SMC9194)		+= crc32.o
+obj-$(CONFIG_STARFIRE)		+= crc32.o
+obj-$(CONFIG_SUNBMAC)		+= crc32.o
+obj-$(CONFIG_SUNDANCE)		+= crc32.o
+obj-$(CONFIG_SUNGEM)		+= crc32.o
+obj-$(CONFIG_SUNGEM)		+= crc32.o
+obj-$(CONFIG_SUNLANCE)		+= crc32.o
+obj-$(CONFIG_SUNQE)		+= crc32.o
+obj-$(CONFIG_TULIP)		+= crc32.o
+obj-$(CONFIG_VIA_RHINE)		+= crc32.o
+obj-$(CONFIG_YELLOWFIN)		+= crc32.o
+obj-$(CONFIG_WINBOND_840)	+= crc32.o
+
+
+# These rely on drivers/net/7990.o which requires crc32.o
+obj-$(CONFIG_HPLANCE)		+= crc32.o	
+obj-$(CONFIG_MVME147_NET)	+= crc32.o	
+
+
+# These rely on drivers/net/8390.o which requires crc32.o
+obj-$(CONFIG_OAKNET)		+= crc32.o
+obj-$(CONFIG_NE2K_PCI)		+= crc32.o
+obj-$(CONFIG_STNIC)		+= crc32.o
+obj-$(CONFIG_MAC8390)		+= crc32.o
+obj-$(CONFIG_APNE)		+= crc32.o
+obj-$(CONFIG_PCMCIA_PCNET)	+= crc32.o
+obj-$(CONFIG_ARM_ETHERH)	+= crc32.o
+obj-$(CONFIG_WD80x3)		+= crc32.o
+obj-$(CONFIG_EL2)		+= crc32.o
+obj-$(CONFIG_NE2000)		+= crc32.o
+obj-$(CONFIG_NE2_MCA)		+= crc32.o
+obj-$(CONFIG_HPLAN)		+= crc32.o
+obj-$(CONFIG_HPLAN_PLUS)	+= crc32.o
+obj-$(CONFIG_ULTRA)		+= crc32.o
+obj-$(CONFIG_ULTRAMCA)		+= crc32.o
+obj-$(CONFIG_ULTRA32)		+= crc32.o
+obj-$(CONFIG_E2100)		+= crc32.o
+obj-$(CONFIG_ES3210)		+= crc32.o
+obj-$(CONFIG_LNE390)		+= crc32.o
+obj-$(CONFIG_NE3210)		+= crc32.o
+obj-$(CONFIG_AC3200)		+= crc32.o
+obj-$(CONFIG_ARIADNE2)		+= crc32.o
+obj-$(CONFIG_HYDRA)		+= crc32.o
diff -urN linux-2.5.2-pre11/drivers/net/a2065.c linux/drivers/net/a2065.c
--- linux-2.5.2-pre11/drivers/net/a2065.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/a2065.c	Mon Jan 14 18:28:29 2002
@@ -6,6 +6,7 @@
  * Fixes and tips by:
  *	- Janos Farkas (CHEXUM@sparta.banki.hu)
  *	- Jes Degn Soerensen (jds@kom.auc.dk)
+ *	- Matt Domsch (Matt_Domsch@dell.com)
  *
  * ----------------------------------------------------------------------------
  *
@@ -47,6 +48,7 @@
 #include <linux/string.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -639,7 +641,7 @@
 	struct dev_mc_list *dmi=dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 	
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI){ 
@@ -660,21 +662,7 @@
 		if (!(*addrs & 1))
 			continue;
 		
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++)
-			for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
-			{
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test)
-				{
-					crc = crc ^ poly;
-				}
-			}
-		
+		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
 		mcast_table [crc >> 4] |= 1 << (crc & 0xf);
 	}
diff -urN linux-2.5.2-pre11/drivers/net/a2065.h linux/drivers/net/a2065.h
--- linux-2.5.2-pre11/drivers/net/a2065.h	Wed Jan 26 12:45:20 2000
+++ linux/drivers/net/a2065.h	Mon Jan 14 18:28:29 2002
@@ -43,9 +43,6 @@
 };
 
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
  *		Am7990 Control and Status Registers
  */
diff -urN linux-2.5.2-pre11/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c
--- linux-2.5.2-pre11/drivers/net/am79c961a.c	Wed Jun 27 14:12:04 2001
+++ linux/drivers/net/am79c961a.c	Mon Jan 14 18:28:29 2002
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -308,33 +309,13 @@
 	return &priv->stats;
 }
 
-static inline u32 update_crc(u32 crc, u8 byte)
-{
-	int i;
-
-	for (i = 8; i != 0; i--) {
-		byte ^= crc & 1;
-		crc >>= 1;
-
-		if (byte & 1)
-			crc ^= 0xedb88320;
-
-		byte >>= 1;
-	}
-
-	return crc;
-}
-
 static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
 {
 	if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
-		int i, idx, bit;
+		int idx, bit;
 		u32 crc;
 
-		crc = 0xffffffff;
-
-		for (i = 0; i < ETH_ALEN; i++)
-			crc = update_crc(crc, dmi->dmi_addr[i]);
+		crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
 
 		idx = crc >> 30;
 		bit = (crc >> 26) & 15;
diff -urN linux-2.5.2-pre11/drivers/net/at1700.c linux/drivers/net/at1700.c
--- linux-2.5.2-pre11/drivers/net/at1700.c	Wed Oct 10 23:24:09 2001
+++ linux/drivers/net/at1700.c	Mon Jan 14 18:28:29 2002
@@ -49,6 +49,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -803,27 +804,6 @@
 /*
   Set the multicast/promiscuous mode for this adaptor.
 */
-
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
 
 static void
 set_rx_mode(struct net_device *dev)
diff -urN linux-2.5.2-pre11/drivers/net/atp.c linux/drivers/net/atp.c
--- linux-2.5.2-pre11/drivers/net/atp.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/atp.c	Mon Jan 14 18:28:29 2002
@@ -140,6 +140,7 @@
 #include <asm/dma.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -856,26 +857,6 @@
 /*
  *	Set or clear the multicast filter for this adapter.
  */
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-    unsigned int crc = 0xffffffff;	/* Initial value. */
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-    }
-    return crc;
-}
 
 static void set_rx_mode_8002(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/au1000_eth.c linux/drivers/net/au1000_eth.c
--- linux-2.5.2-pre11/drivers/net/au1000_eth.c	Sun Sep  9 10:43:01 2001
+++ linux/drivers/net/au1000_eth.c	Mon Jan 14 18:28:29 2002
@@ -47,6 +47,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1092,22 +1093,6 @@
 	printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);
 	reset_mac(dev);
 	au1000_init(dev);
-}
-
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
 }
 
 static void set_rx_mode(struct net_device *dev)
diff -urN linux-2.5.2-pre11/drivers/net/bmac.c linux/drivers/net/bmac.c
--- linux-2.5.2-pre11/drivers/net/bmac.c	Wed Nov 14 15:16:31 2001
+++ linux/drivers/net/bmac.c	Mon Jan 14 18:28:29 2002
@@ -1053,16 +1053,13 @@
 
 /* The version of set_multicast below was lifted from sunhme.c */
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void bmac_set_multicast(struct net_device *dev)
 {
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
 	unsigned short rx_cfg;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
 		bmwrite(dev, BHASH0, 0xffff);
@@ -1089,17 +1086,7 @@
 			if(!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for(byte = 0; byte < 6; byte++) {
-				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if(test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.5.2-pre11/drivers/net/bonding.c linux/drivers/net/bonding.c
--- linux-2.5.2-pre11/drivers/net/bonding.c	Tue Nov 13 09:19:41 2001
+++ linux/drivers/net/bonding.c	Mon Jan 14 18:28:29 2002
@@ -153,6 +153,14 @@
  *
  * 2001/10/23 - Takao Indoh <indou dot takao at jp dot fujitsu dot com>
  *     - Various memory leak fixes
+ *
+ * 2001/11/5 - Mark Huth <mark dot huth at mvista dot com>
+ *     - Don't take rtnl lock in bond_mii_monitor as it deadlocks under 
+ *       certain hotswap conditions.  
+ *       Note:  this same change may be required in bond_arp_monitor ???
+ *     - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr 
+ *     - Handle hot swap ethernet interface deregistration events to remove
+ *       kernel oops following hot swap of enslaved interface
  */
 
 #include <linux/config.h>
@@ -185,7 +193,6 @@
 
 #include <linux/if_bonding.h>
 #include <linux/smp.h>
-#include <limits.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 
@@ -257,6 +264,7 @@
 static void bond_set_slave_active_flags(slave_t *slave);
 static int bond_enslave(struct net_device *master, struct net_device *slave);
 static int bond_release(struct net_device *master, struct net_device *slave);
+static int bond_release_all(struct net_device *master);
 static int bond_sethwaddr(struct net_device *master, struct net_device *slave);
 
 /*
@@ -372,10 +380,13 @@
 static u16 bond_check_mii_link(bonding_t *bond)
 {
 	int has_active_interface = 0;
+	unsigned long flags;
 
+	read_lock_irqsave(&bond->lock, flags);
 	read_lock(&bond->ptrlock);
 	has_active_interface = (bond->current_slave != NULL);
 	read_unlock(&bond->ptrlock);
+	read_unlock_irqrestore(&bond->lock, flags);
 
 	return (has_active_interface ? MII_LINK_READY : 0);
 }
@@ -407,7 +418,6 @@
 static int bond_close(struct net_device *master)
 {
 	bonding_t *bond = (struct bonding *) master->priv;
-	slave_t *slave;
 	unsigned long flags;
 
 	write_lock_irqsave(&bond->lock, flags);
@@ -418,13 +428,11 @@
 	if (arp_interval> 0) {  /* arp interval, in milliseconds. */
 		del_timer(&bond->arp_timer);
 	}
-	/* We need to unlock this because bond_release will re-lock it */
-	write_unlock_irqrestore(&bond->lock, flags);
 
 	/* Release the bonded slaves */
-	while ((slave = bond->prev) != (slave_t *)bond) {
-		bond_release(master, slave->dev);
-	}
+	bond_release_all(master);
+
+	write_unlock_irqrestore(&bond->lock, flags);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -866,6 +874,49 @@
 	return -EINVAL;
 }
 
+/* 
+ * This function releases all slaves.
+ * Warning: must put write-locks around the call to this function.
+ */
+static int bond_release_all(struct net_device *master)
+{
+	bonding_t *bond;
+	slave_t *our_slave;
+	struct net_device *slave_dev;
+
+	if (master == NULL)  {
+		return -ENODEV;
+	}
+
+	if (master->flags & IFF_SLAVE) {
+		return -EINVAL;
+	}
+
+	bond = (struct bonding *) master->priv;
+	bond->current_slave = NULL;
+
+	while ((our_slave = bond->prev) != (slave_t *)bond) {
+		slave_dev = our_slave->dev;
+		bond->prev = our_slave->prev;
+
+		kfree(our_slave);
+
+		netdev_set_master(slave_dev, NULL);
+
+		/* only restore its RUNNING flag if monitoring set it down */
+		if (slave_dev->flags & IFF_UP)
+			slave_dev->flags |= IFF_RUNNING;
+
+		if (slave_dev->flags & IFF_NOARP)
+			dev_close(slave_dev);
+	}
+	bond->next = (slave_t *)bond;
+	bond->slave_cnt = 0;
+	printk (KERN_INFO "%s: releases all slaves\n", master->name);
+
+	return 0;
+}
+
 /* this function is called regularly to monitor each slave's link. */
 static void bond_mii_monitor(struct net_device *master)
 {
@@ -876,14 +927,6 @@
 
 	read_lock_irqsave(&bond->lock, flags);
 
-	if (rtnl_shlock_nowait()) {
-		goto monitor_out;
-	}
-
-	if (rtnl_exlock_nowait()) {
-		rtnl_shunlock();
-		goto monitor_out;
-	}
 	/* we will try to read the link status of each of our slaves, and
 	 * set their IFF_RUNNING flag appropriately. For each slave not
 	 * supporting MII status, we won't do anything so that a user-space
@@ -1057,9 +1100,10 @@
 		} /* end of switch */
 	} /* end of while */
 
-	/* if there's no active interface and we discovered that one
-	   of the slaves could be activated earlier, so we do it.
-	*/
+	/* 
+	 * if there's no active interface and we discovered that one
+	 * of the slaves could be activated earlier, so we do it.
+	 */
 	read_lock(&bond->ptrlock);
 	oldcurrent = bond->current_slave;
 	read_unlock(&bond->ptrlock);
@@ -1097,9 +1141,6 @@
 		}
 	}
 
-	rtnl_exunlock();
-	rtnl_shunlock();
-monitor_out:
 	read_unlock_irqrestore(&bond->lock, flags);
 	/* re-arm the timer */
 	mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000));
@@ -1128,17 +1169,17 @@
 
 	if (!IS_UP(master)) {
 		mod_timer(&bond->arp_timer, next_timer);
-		goto monitor_out;
+		goto arp_monitor_out;
 	}
 
 
 	if (rtnl_shlock_nowait()) {
-		goto monitor_out;
+		goto arp_monitor_out;
 	}
 
 	if (rtnl_exlock_nowait()) {
 		rtnl_shunlock();
-		goto monitor_out;
+		goto arp_monitor_out;
 	}
 
 	/* see if any of the previous devices are up now (i.e. they have seen a 
@@ -1243,7 +1284,9 @@
 	 * an arp on all of the interfaces 
 	 */
 
+	read_lock(&bond->ptrlock);
 	if (bond->current_slave == NULL) { 
+		read_unlock(&bond->ptrlock);
 		slave = (slave_t *)bond;
 		while ((slave = slave->prev) != (slave_t *)bond)   {
 			arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, 
@@ -1251,11 +1294,14 @@
 				 slave->dev->dev_addr, arp_target_hw_addr); 
 		}
 	}
+	else {
+		read_unlock(&bond->ptrlock);
+	}
 
 	rtnl_exunlock();
 	rtnl_shunlock();
 
-monitor_out:
+arp_monitor_out:
 	read_unlock_irqrestore(&bond->lock, flags);
 
 	/* re-arm the timer */
@@ -1367,16 +1413,17 @@
 {
 	bonding_t *bond = (struct bonding *) master->priv;
 	slave_t *slave;
+	unsigned long flags;
 
 	info->bond_mode = mode;
 	info->num_slaves = 0;
 	info->miimon = miimon;
 
-	read_lock(&bond->ptrlock);
+	read_lock_irqsave(&bond->lock, flags);
 	for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) {
 		info->num_slaves++;
 	}
-	read_unlock(&bond->ptrlock);
+	read_unlock_irqrestore(&bond->lock, flags);
 
 	return 0;
 }
@@ -1387,27 +1434,28 @@
 	bonding_t *bond = (struct bonding *) master->priv;
 	slave_t *slave;
 	int cur_ndx = 0;
+	unsigned long flags;
 
 	if (info->slave_id < 0) {
 		return -ENODEV;
 	}
 
-	read_lock(&bond->ptrlock);
+	read_lock_irqsave(&bond->lock, flags);
 	for (slave = bond->prev; 
 		 slave != (slave_t *)bond && cur_ndx < info->slave_id; 
 		 slave = slave->prev) {
 		cur_ndx++;
 	}
+	read_unlock_irqrestore(&bond->lock, flags);
+
 	if (cur_ndx == info->slave_id) {
 		strcpy(info->slave_name, slave->dev->name);
 		info->link = slave->link;
 		info->state = slave->state;
 		info->link_failure_count = slave->link_failure_count;
 	} else {
-		read_unlock(&bond->ptrlock);
 		return -ENODEV;
 	}
-	read_unlock(&bond->ptrlock);
 
 	return 0;
 }
@@ -1480,40 +1528,40 @@
 	}
 
 	slave_dev = dev_get_by_name(ifr->ifr_slave);
+
 #ifdef BONDING_DEBUG
 	printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev);
 	printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name);
 #endif
-	switch (cmd) {
-	case BOND_ENSLAVE_OLD:
-	case SIOCBONDENSLAVE:		
-		ret = bond_enslave(master_dev, slave_dev);
-		break;
-	case BOND_RELEASE_OLD:			
-	case SIOCBONDRELEASE:	
-		ret = bond_release(master_dev, slave_dev); 
-		break;
-	case BOND_SETHWADDR_OLD:
-	case SIOCBONDSETHWADDR:	
-		ret = bond_sethwaddr(master_dev, slave_dev);
-		break;
-	case BOND_CHANGE_ACTIVE_OLD:
-	case SIOCBONDCHANGEACTIVE:
-		if (mode == BOND_MODE_ACTIVEBACKUP) {
-			ret = bond_change_active(master_dev, slave_dev);
-		}
-		else {
-			ret = -EINVAL;
-		}
-		break;
-	default:
-		ret = -EOPNOTSUPP;
-	}
 
-	if (slave_dev) {
-		/*
-		 * Clear the module reference that was added by dev_get_by_name
-		 */
+	if (slave_dev == NULL) {
+		ret = -ENODEV;
+	} else {
+		switch (cmd) {
+		case BOND_ENSLAVE_OLD:
+		case SIOCBONDENSLAVE:		
+			ret = bond_enslave(master_dev, slave_dev);
+			break;
+		case BOND_RELEASE_OLD:			
+		case SIOCBONDRELEASE:	
+			ret = bond_release(master_dev, slave_dev); 
+			break;
+		case BOND_SETHWADDR_OLD:
+		case SIOCBONDSETHWADDR:	
+			ret = bond_sethwaddr(master_dev, slave_dev);
+			break;
+		case BOND_CHANGE_ACTIVE_OLD:
+		case SIOCBONDCHANGEACTIVE:
+			if (mode == BOND_MODE_ACTIVEBACKUP) {
+				ret = bond_change_active(master_dev, slave_dev);
+			}
+			else {
+				ret = -EINVAL;
+			}
+			break;
+		default:
+			ret = -EOPNOTSUPP;
+		}
 		dev_put(slave_dev);
 	}
 	return ret;
@@ -1593,13 +1641,11 @@
 	}
 
 	read_lock_irqsave(&bond->lock, flags);
-	read_lock(&bond->ptrlock);
 	slave = bond->prev;
 
 	/* we're at the root, get the first slave */
 	if ((slave == NULL) || (slave->dev == NULL)) { 
 		/* no suitable interface, frame not sent */
-		read_unlock(&bond->ptrlock);
 		dev_kfree_skb(skb);
 		read_unlock_irqrestore(&bond->lock, flags);
 		return 0;
@@ -1607,8 +1653,6 @@
 
 	slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt;
 
-	read_unlock(&bond->ptrlock);
-
 	while ( (slave_no > 0) && (slave != (slave_t *)bond) ) {
 		slave = slave->prev;
 		slave_no--;
@@ -1749,6 +1793,7 @@
 	off_t begin = 0;
 	u16 link;
 	slave_t *slave = NULL;
+	unsigned long flags;
 
 	while (bond != NULL) {
 		/*
@@ -1757,17 +1802,19 @@
 		 */
 		link = bond_check_mii_link(bond);
 
-		read_lock(&bond->ptrlock);
-
 		len += sprintf(buf + len, "Bonding Mode: ");
 		len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing");
 
 		if (mode == BOND_MODE_ACTIVEBACKUP) {
+			read_lock_irqsave(&bond->lock, flags);
+			read_lock(&bond->ptrlock);
 			if (bond->current_slave != NULL) {
 				len += sprintf(buf + len, 
 					"Currently Active Slave: %s\n", 
 					bond->current_slave->dev->name);
 			}
+			read_unlock(&bond->ptrlock);
+			read_unlock_irqrestore(&bond->lock, flags);
 		}
 
 		len += sprintf(buf + len, "MII Status: ");
@@ -1778,6 +1825,7 @@
 		len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
 		len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay);
 
+		read_lock_irqsave(&bond->lock, flags);
 		for (slave = bond->prev; slave != (slave_t *)bond; 
 		     slave = slave->prev) {
 			len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name);
@@ -1790,6 +1838,7 @@
 			len += sprintf(buf + len, "Link Failure Count: %d\n", 
 				slave->link_failure_count);
 		}
+		read_unlock_irqrestore(&bond->lock, flags);
 
 		/*
 		 * Figure out the calcs for the /proc/net interface
@@ -1803,7 +1852,6 @@
 			len = 0;
 		}
 
-		read_unlock(&bond->ptrlock);
 
 		bond = bond->next_bond;
 	}
@@ -1844,7 +1892,14 @@
 			default:
 				return NOTIFY_DONE;
 			}
-		} 
+		} else if (this_bond->device == event_dev->master) {
+			switch (event) {
+			case NETDEV_UNREGISTER:
+				bond_release(this_bond->device, event_dev);
+				break;
+			}
+			return NOTIFY_DONE;
+		}
 		this_bond = this_bond->next_bond;
 	}
 	return NOTIFY_DONE;
diff -urN linux-2.5.2-pre11/drivers/net/de2104x.c linux/drivers/net/de2104x.c
--- linux-2.5.2-pre11/drivers/net/de2104x.c	Mon Jan 14 18:28:22 2002
+++ linux/drivers/net/de2104x.c	Mon Jan 14 18:28:29 2002
@@ -43,6 +43,7 @@
 #include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/rtnetlink.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -655,41 +656,6 @@
    Note that we only use exclusion around actually queueing the
    new frame, not around filling de->setup_frame.  This is non-deterministic
    when re-entered but still correct. */
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
-	u32 crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
 
 #undef set_bit_le
 #define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
diff -urN linux-2.5.2-pre11/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- linux-2.5.2-pre11/drivers/net/de4x5.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/de4x5.c	Mon Jan 14 18:28:29 2002
@@ -436,6 +436,7 @@
                            'pb' is now only initialized if a de4x5 chip is
                            present. 
                            <france@handhelds.org>  
+      0.547  08-Nov-01    Use library crc32 functions by <Matt_Domsch@dell.com>
     =========================================================================
 */
 
@@ -457,6 +458,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/spinlock.h>
+#include <linux/crc32.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -622,9 +624,6 @@
 #define QUEUE_PKT_TIMEOUT (3*HZ)        /* 3 second timeout */
 
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
 ** EISA bus defines
 */
@@ -2050,7 +2049,7 @@
     u_long iobase = dev->base_addr;
     int i, j, bit, byte;
     u16 hashcode;
-    u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
+    u32 omr, crc;
     char *pa;
     unsigned char *addrs;
 
@@ -2065,13 +2064,7 @@
 	    addrs=dmi->dmi_addr;
 	    dmi=dmi->next;
 	    if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
-		crc = 0xffffffff;            /* init CRC for each address */
-		for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-		                             /* process each address bit */ 
-		    for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
-			crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
-		    }
-		}
+		crc = ether_crc_le(ETH_ALEN, addrs);
 		hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
 		
 		byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
diff -urN linux-2.5.2-pre11/drivers/net/declance.c linux/drivers/net/declance.c
--- linux-2.5.2-pre11/drivers/net/declance.c	Sun Sep  9 10:45:43 2001
+++ linux/drivers/net/declance.c	Mon Jan 14 18:28:29 2002
@@ -79,6 +79,7 @@
 #include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <linux/etherdevice.h>
 
@@ -88,9 +89,6 @@
 #endif
 static int type;
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -920,7 +918,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_BE;
+	u32 crc;
 
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -945,19 +943,7 @@
 		if (!(*addrs & 1))
 			continue;
 
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++)
-			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test) {
-					crc = crc ^ poly;
-				}
-			}
-
+		crc = ether_crc(6, addrs);
 		crc = crc >> 26;
 		mcast_table[crc >> 3] |= 1 << (crc & 0xf);
 	}
diff -urN linux-2.5.2-pre11/drivers/net/depca.c linux/drivers/net/depca.c
--- linux-2.5.2-pre11/drivers/net/depca.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/depca.c	Mon Jan 14 18:28:29 2002
@@ -228,6 +228,8 @@
 			   by <peterd@pnd-pc.demon.co.uk>
       0.53    12-Jan-01	  Release resources on failure, bss tidbits
       			   by acme@conectiva.com.br
+      0.54    08-Nov-01	  use library crc32 functions
+      			   by Matt_Domsch@dell.com
 
     =========================================================================
 */
@@ -245,6 +247,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -296,9 +299,6 @@
 #define RX_BUFF_SZ	1536            /* Buffer size for each Rx buffer */
 #define TX_BUFF_SZ	1536            /* Buffer size for each Tx buffer */
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 /*
 ** EISA bus defines
 */
@@ -1225,7 +1225,7 @@
   char *addrs;
   int i, j, bit, byte;
   u16 hashcode;
-  s32 crc, poly = CRC_POLYNOMIAL_BE;
+  u32 crc;
 
   if (dev->flags & IFF_ALLMULTI) {         /* Set all multicast bits */
     for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
@@ -1240,13 +1240,7 @@
       addrs=dmi->dmi_addr;
       dmi=dmi->next;
       if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
-	crc = 0xffffffff;                  /* init CRC for each address */
-	for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
-	                                   /* process each address bit */ 
-	  for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
-	    crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
-	  }
-	}
+        crc = ether_crc(ETH_ALEN, addrs);
 	hashcode = (crc & 1);              /* hashcode is 6 LSb of CRC ... */
 	for (j=0;j<5;j++) {                /* ... in reverse order. */
 	  hashcode = (hashcode << 1) | ((crc>>=1) & 1);
diff -urN linux-2.5.2-pre11/drivers/net/dl2k.c linux/drivers/net/dl2k.c
--- linux-2.5.2-pre11/drivers/net/dl2k.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/dl2k.c	Mon Jan 14 18:28:29 2002
@@ -75,7 +75,6 @@
 static int find_miiphy (struct net_device *dev);
 static int parse_eeprom (struct net_device *dev);
 static int read_eeprom (long ioaddr, int eep_addr);
-static unsigned get_crc (unsigned char *p, int len);
 static int mii_wait_link (struct net_device *dev, int wait);
 static int mii_set_media (struct net_device *dev);
 static int mii_get_media (struct net_device *dev);
@@ -327,7 +326,7 @@
 	}
 
 	/* Check CRC */
-	crc = ~get_crc (sromdata, 256 - 4);
+ 	crc = ~ether_crc_le(256-4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -972,23 +971,6 @@
 	return 0;
 }
 
-#define CRC_POLY 0xedb88320
-static unsigned
-get_crc (unsigned char *p, int len)
-{
-	int bit;
-	unsigned char byte;
-	unsigned crc = 0xffffffff;
-
-	while (--len >= 0) {
-		byte = *p++;
-		for (bit = 0; bit < 8; bit++, byte >>= 1) {
-			crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0);
-		}
-	}
-	return crc;
-}
-
 static void
 set_multicast (struct net_device *dev)
 {
@@ -1023,7 +1005,7 @@
 
 	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 	     i++, mclist = mclist->next) {
-		set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f,
+		set_bit (ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
 			 hash_table);
 	}
 	writel (hash_table[0], ioaddr + HashTable0);
diff -urN linux-2.5.2-pre11/drivers/net/dl2k.h linux/drivers/net/dl2k.h
--- linux-2.5.2-pre11/drivers/net/dl2k.h	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/dl2k.h	Mon Jan 14 18:28:29 2002
@@ -26,6 +26,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
diff -urN linux-2.5.2-pre11/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- linux-2.5.2-pre11/drivers/net/dmfe.c	Fri Nov  9 13:50:01 2001
+++ linux/drivers/net/dmfe.c	Mon Jan 14 18:28:29 2002
@@ -84,6 +84,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#include <linux/crc32.h>
 
 #include <asm/processor.h>
 #include <asm/bitops.h>
@@ -288,72 +289,6 @@
 static u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
 				   4: TX pause packet */
 
-unsigned long CrcTable[256] = {
-	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
-	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
-	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
-	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
-	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
-	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
-	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
-	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
-	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
-	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
-	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
-	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
-	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
-	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
-	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
-	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
-	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
-	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
-	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
-	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
-	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
-	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
-	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
-	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
-	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
-	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
-	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
-	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
-	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
-	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
-	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
-	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
-	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
-	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
-	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
-	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
-	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
-	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
-	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
-	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
-	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
-	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
-	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
-	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
-	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
-	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
-	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
-	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
-	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
-	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
-	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
-	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
-	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
-	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
-	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
-	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
-	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
-	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
-	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
-	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
-	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
-	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
-	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
-	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
-};
 
 /* function declaration ------------------------------------- */
 static int dmfe_open(struct DEVICE *);
@@ -382,7 +317,7 @@
 static void dmfe_dynamic_reset(struct DEVICE *);
 static void dmfe_free_rxbuffer(struct dmfe_board_info *);
 static void dmfe_init_dm910x(struct DEVICE *);
-static unsigned long cal_CRC(unsigned char *, unsigned int, u8);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
 static void dmfe_parse_srom(struct dmfe_board_info *);
 static void dmfe_program_DM9801(struct dmfe_board_info *, int);
 static void dmfe_program_DM9802(struct dmfe_board_info *);
@@ -1851,18 +1786,11 @@
  *		0 : return the normal CRC (for Hash Table index)
  */
 
-unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
 {
-	unsigned long Crc = 0xffffffff;
-
-	while (Len--) {
-		Crc = CrcTable[(Crc ^ *Data++) & 0xFF] ^ (Crc >> 8);
-	}
-
-	if (flag)
-		return ~Crc;
-	else
-		return Crc;
+	u32 crc = crc32(~0, Data, Len);
+	if (flag) crc = ~crc;
+	return crc;
 }
 
 
diff -urN linux-2.5.2-pre11/drivers/net/epic100.c linux/drivers/net/epic100.c
--- linux-2.5.2-pre11/drivers/net/epic100.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/epic100.c	Mon Jan 14 18:28:29 2002
@@ -124,6 +124,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1301,27 +1302,6 @@
    Note that we only use exclusion around actually queueing the
    new frame, not around filling ep->setup_frame.  This is non-deterministic
    when re-entered but still correct. */
-
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- linux-2.5.2-pre11/drivers/net/ewrk3.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/ewrk3.c	Mon Jan 14 18:28:29 2002
@@ -132,6 +132,7 @@
    <kenneth@bbs.sas.ntu.ac.sg>.
    0.42    22-Apr-96      Fix alloc_device() bug <jari@markkus2.fimr.fi>
    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>
 
    =========================================================================
  */
@@ -148,6 +149,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -207,9 +209,6 @@
 #define EISA_SLOT_INC 0x1000
 #endif
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 #define QUEUE_PKT_TIMEOUT (1*HZ)	/* Jiffies */
 
 /*
@@ -1174,10 +1173,10 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	u_long iobase = dev->base_addr;
 	int i;
-	char *addrs, j, bit, byte;
+	char *addrs, bit, byte;
 	short *p = (short *) lp->mctbl;
 	u16 hashcode;
-	s32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	spin_lock_irq(&lp->hw_lock);
 
@@ -1219,13 +1218,7 @@
 			addrs = dmi->dmi_addr;
 			dmi = dmi->next;
 			if ((*addrs & 0x01) == 1) {	/* multicast address? */
-				crc = 0xffffffff;	/* init CRC for each address */
-				for (byte = 0; byte < ETH_ALEN; byte++) {	/* for each address byte */
-					/* process each address bit */
-					for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-						crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
-					}
-				}
+				crc = ether_crc_le(ETH_ALEN, addrs);
 				hashcode = crc & ((1 << 9) - 1);	/* hashcode is 9 LSb of CRC */
 
 				byte = hashcode >> 3;	/* bit[3-8] -> byte in filter */
diff -urN linux-2.5.2-pre11/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- linux-2.5.2-pre11/drivers/net/fealnx.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/fealnx.c	Mon Jan 14 18:28:29 2002
@@ -72,6 +72,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -426,7 +427,6 @@
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static int netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -1710,26 +1710,6 @@
 
 	return &np->stats;
 }
-
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-	int crc = -1;
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-	}
-
-	return crc;
-}
-
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/gmac.c linux/drivers/net/gmac.c
--- linux-2.5.2-pre11/drivers/net/gmac.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/gmac.c	Mon Jan 14 18:28:29 2002
@@ -16,6 +16,8 @@
  *  - PHY updates
  * BenH <benh@kernel.crashing.org> - 08/08/2001
  * - Add more PHYs, fixes to sleep code
+ * Matt Domsch <Matt_Domsch@dell.com> - 11/12/2001
+ * - use library crc32 functions
  */
 
 #include <linux/module.h>
@@ -33,6 +35,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -997,14 +1000,13 @@
  * Configure promisc mode and setup multicast hash table
  * filter
  */
-#define CRC_POLY	0xedb88320
 static void
 gmac_set_multicast(struct net_device *dev)
 {
 	struct gmac *gm = (struct gmac *) dev->priv;
 	struct dev_mc_list *dmi = dev->mc_list;
 	int i,j,k,b;
-	unsigned long crc;
+	u32 crc;
 	int multicast_hash = 0;
 	int multicast_all = 0;
 	int promisc = 0;
@@ -1027,17 +1029,7 @@
 			hash_table[i] = 0;
 
 	    	for (i = 0; i < dev->mc_count; i++) {
-			crc = ~0;
-			for (j = 0; j < 6; ++j) {
-			    b = dmi->dmi_addr[j];
-			    for (k = 0; k < 8; ++k) {
-				if ((crc ^ b) & 1)
-				    crc = (crc >> 1) ^ CRC_POLY;
-				else
-				    crc >>= 1;
-				b >>= 1;
-			    }
-			}
+			crc = ether_crc_le(6, dmi->dmi_addr);
 			j = crc >> 24;	/* bit number in multicast_filter */
 			hash_table[j >> 4] |= 1 << (15 - (j & 0xf));
 			dmi = dmi->next;
diff -urN linux-2.5.2-pre11/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- linux-2.5.2-pre11/drivers/net/ioc3-eth.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/ioc3-eth.c	Mon Jan 14 18:28:29 2002
@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 
 #ifdef CONFIG_SERIAL
 #include <linux/serial.h>
@@ -1611,27 +1612,16 @@
  * Given a multicast ethernet address, this routine calculates the
  * address's bit index in the logical address filter mask
  */
-#define CRC_MASK        0xedb88320
 
 static inline unsigned int
 ioc3_hash(const unsigned char *addr)
 {
 	unsigned int temp = 0;
 	unsigned char byte;
-	unsigned int crc;
-	int bits, len;
+	u32 crc;
+	int bits;
 
-	len = ETH_ALEN;
-	for (crc = ~0; --len >= 0; addr++) {
-		byte = *addr;
-		for (bits = 8; --bits >= 0; ) {
-			if ((byte ^ crc) & 1)
-				crc = (crc >> 1) ^ CRC_MASK;
-			else
-				crc >>= 1;
-			byte >>= 1;
-		}
-	}
+	crc = ether_crc_le(ETH_ALEN, addr);
 
 	crc &= 0x3f;    /* bit reverse lowest 6 bits for hash index */
 	for (bits = 6; --bits >= 0; ) {
diff -urN linux-2.5.2-pre11/drivers/net/mace.c linux/drivers/net/mace.c
--- linux-2.5.2-pre11/drivers/net/mace.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/mace.c	Mon Jan 14 18:28:29 2002
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -508,17 +509,12 @@
     return &p->stats;
 }
 
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY	0xedb88320
-
 static void mace_set_multicast(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
     volatile struct mace *mb = mp->mace;
-    int i, j, k, b;
-    unsigned long crc;
+    int i, j;
+    u32 crc;
 
     mp->maccc &= ~PROM;
     if (dev->flags & IFF_PROMISC) {
@@ -534,17 +530,7 @@
 	    for (i = 0; i < 8; i++)
 		multicast_filter[i] = 0;
 	    for (i = 0; i < dev->mc_count; i++) {
-		crc = ~0;
-		for (j = 0; j < 6; ++j) {
-		    b = dmi->dmi_addr[j];
-		    for (k = 0; k < 8; ++k) {
-			if ((crc ^ b) & 1)
-			    crc = (crc >> 1) ^ CRC_POLY;
-			else
-			    crc >>= 1;
-			b >>= 1;
-		    }
-		}
+	        crc = ether_crc_le(6, dmi->dmi_addr);
 		j = crc >> 26;	/* bit number in multicast_filter */
 		multicast_filter[j >> 3] |= 1 << (j & 7);
 		dmi = dmi->next;
diff -urN linux-2.5.2-pre11/drivers/net/macmace.c linux/drivers/net/macmace.c
--- linux-2.5.2-pre11/drivers/net/macmace.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/macmace.c	Mon Jan 14 18:28:29 2002
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -539,17 +540,12 @@
 	return &p->stats;
 }
 
-/*
- * CRC polynomial - used in working out multicast filter bits.
- */
-#define CRC_POLY	0xedb88320
-
 static void mace68k_set_multicast(struct net_device *dev)
 {
 	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
 	volatile struct mace *mb = mp->mace;
 	int i, j, k, b;
-	unsigned long crc;
+	u32 crc;
 
 	mp->maccc &= ~PROM;
 	if (dev->flags & IFF_PROMISC)
@@ -570,19 +566,7 @@
 				multicast_filter[i] = 0;
 			for (i = 0; i < dev->mc_count; i++)
 			{
-				crc = ~0;
-				for (j = 0; j < 6; ++j)
-				{
-					b = dmi->dmi_addr[j];
-					for (k = 0; k < 8; ++k)
-					{
-						if ((crc ^ b) & 1)
-							crc = (crc >> 1) ^ CRC_POLY;
-						else
-							crc >>= 1;
-						b >>= 1;
-					}
-				}
+				crc = ether_crc_le(6, dmi->dmi_addr);
 				j = crc >> 26;	/* bit number in multicast_filter */
 				multicast_filter[j >> 3] |= 1 << (j & 7);
 				dmi = dmi->next;
diff -urN linux-2.5.2-pre11/drivers/net/myri_code.h linux/drivers/net/myri_code.h
--- linux-2.5.2-pre11/drivers/net/myri_code.h	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/myri_code.h	Mon Jan 14 18:28:29 2002
@@ -6284,4 +6284,4 @@
 #define MYRI_NetReceiveBadCrcs       0xB8D4
 #define MYRI_NetReceiveBytes         0xB8DC
 
-#endif SYMBOL_DEFINES_COMPILED
+#endif /* SYMBOL_DEFINES_COMPILED */
diff -urN linux-2.5.2-pre11/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- linux-2.5.2-pre11/drivers/net/myri_sbus.c	Fri Oct 19 08:32:28 2001
+++ linux/drivers/net/myri_sbus.c	Mon Jan 14 18:28:29 2002
@@ -800,9 +800,6 @@
 static struct net_device_stats *myri_get_stats(struct net_device *dev)
 { return &(((struct myri_eth *)dev->priv)->enet_stats); }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void myri_set_multicast(struct net_device *dev)
 {
 	/* Do nothing, all MyriCOM nodes transmit multicast frames
diff -urN linux-2.5.2-pre11/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- linux-2.5.2-pre11/drivers/net/natsemi.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/natsemi.c	Mon Jan 14 18:28:29 2002
@@ -102,6 +102,9 @@
 	version 1.0.13:
 		* ETHTOOL_[GS]EEPROM support (Tim Hockin)
 
+	version 1.0.13:
+		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
+
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
@@ -110,7 +113,7 @@
 
 #define DRV_NAME	"natsemi"
 #define DRV_VERSION	"1.07+LK1.0.13"
-#define DRV_RELDATE	"Oct 19, 2001"
+#define DRV_RELDATE	"Nov 12, 2001"
 
 /* Updated to recommendations in pci-skeleton v2.03. */
 
@@ -1706,36 +1709,15 @@
 	return &np->stats;
 }
 
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
-   them.  Select the endian-ness that results in minimal calculations.
-*/
-#if 0
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-#else
+/**
+ * dp83815_crc - computer CRC for hash table entries
+ *
+ * Note - this is, for some reason, *not* the same function
+ * as ether_crc_le() or ether_crc(), though it uses the
+ * same big-endian polynomial.
+ */
 #define DP_POLYNOMIAL			0x04C11DB7
-/* dp83815_crc - computer CRC for hash table entries */
-static unsigned ether_crc_le(int length, unsigned char *data)
+static unsigned dp83815_crc(int length, unsigned char *data)
 {
     u32 crc;
     u8 cur_byte;
@@ -1759,7 +1741,7 @@
 
     return (crc);
 }
-#endif
+
 
 void set_bit_le(int offset, unsigned char * data)
 {
@@ -1788,7 +1770,7 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			set_bit_le(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+			set_bit_le(dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
 					mc_filter);
 		}
 		rx_mode = RxFilterEnable | AcceptBroadcast 
diff -urN linux-2.5.2-pre11/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- linux-2.5.2-pre11/drivers/net/pci-skeleton.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/pci-skeleton.c	Mon Jan 14 18:28:29 2002
@@ -96,6 +96,7 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 
 #define NETDRV_VERSION		"1.0.0"
@@ -509,7 +510,6 @@
 static int netdrv_close (struct net_device *dev);
 static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
-static inline u32 ether_crc (int length, unsigned char *data);
 static void netdrv_set_rx_mode (struct net_device *dev);
 static void netdrv_hw_start (struct net_device *dev);
 
@@ -1852,27 +1852,6 @@
 
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc (int length, unsigned char *data)
-{
-	int crc = -1;
-
-	DPRINTK ("ENTER\n");
-
-	while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ?
-			     ethernet_polynomial : 0);
-	}
-
-	DPRINTK ("EXIT\n");
-	return crc;
-}
-
 
 static void netdrv_set_rx_mode (struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.5.2-pre11/drivers/net/pcmcia/fmvj18x_cs.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Mon Jan 14 18:28:29 2002
@@ -47,6 +47,7 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/crc32.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -1180,27 +1181,6 @@
 /*
   Set the multicast/promiscuous mode for this adaptor.
 */
-
-/* The little-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-    unsigned int crc = 0xffffffff;	/* Initial value. */
-    while(--length >= 0) {
-	unsigned char current_octet = *data++;
-	int bit;
-	for (bit = 8; --bit >= 0; current_octet >>= 1) {
-	    if ((crc ^ current_octet) & 1) {
-		crc >>= 1;
-		crc ^= ethernet_polynomial_le;
-	    } else
-		crc >>= 1;
-	}
-    }
-    return crc;
-}
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.5.2-pre11/drivers/net/pcmcia/smc91c92_cs.c	Tue Nov 13 09:02:30 2001
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Mon Jan 14 18:28:29 2002
@@ -34,6 +34,7 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -1740,31 +1741,6 @@
     return &smc->stats;
 }
 
-/*======================================================================
-
-    Compute the AUTODIN polynomial "CRC32" for ethernet packets.
-
-======================================================================*/
-
-static const u_int ethernet_polynomial = 0x04c11db7U;
-
-static u_int ether_crc(int length, u_char *data)
-{
-    int crc = 0xffffffff;	/* Initial value. */
-    
-    while (--length >= 0) {
-	u_char current_octet = *data++;
-	int bit;
-	for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-	    crc = (crc << 1) ^
-		((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-	}
-    }
-    /* The hash index is the either the upper or lower bits of the CRC, so
-     * we return the entire CRC.
-     */
-    return crc;
-}
 
 /*======================================================================
   
diff -urN linux-2.5.2-pre11/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.5.2-pre11/drivers/net/pcmcia/xircom_tulip_cb.c	Fri Nov  9 13:41:42 2001
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Mon Jan 14 18:28:29 2002
@@ -101,6 +101,7 @@
 #include <linux/init.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
@@ -1517,43 +1518,6 @@
 
 	return -EOPNOTSUPP;
 }
-
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
-	u32 crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
 
 /* Set or clear the multicast filter for this adaptor.
    Note that we only use exclusion around actually queueing the
diff -urN linux-2.5.2-pre11/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- linux-2.5.2-pre11/drivers/net/pcnet32.c	Sun Nov 11 10:09:33 2001
+++ linux/drivers/net/pcnet32.c	Mon Jan 14 18:28:29 2002
@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -215,8 +216,6 @@
 
 #define PCNET32_TOTAL_SIZE 0x20
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
-
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
     u32 base;
@@ -1425,8 +1424,8 @@
     volatile u16 *mcast_table = (u16 *)&ib->filter;
     struct dev_mc_list *dmi=dev->mc_list;
     char *addrs;
-    int i, j, bit, byte;
-    u32 crc, poly = CRC_POLYNOMIAL_LE;
+    int i;
+    u32 crc;
 	
     /* set all multicast bits */
     if (dev->flags & IFF_ALLMULTI){ 
@@ -1447,19 +1446,7 @@
 	if (!(*addrs & 1))
 	    continue;
 	
-	crc = 0xffffffff;
-	for (byte = 0; byte < 6; byte++)
-	    for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-		int test;
-		
-		test = ((bit ^ crc) & 0x01);
-		crc >>= 1;
-		
-		if (test) {
-		    crc = crc ^ poly;
-		}
-	    }
-	
+	crc = ether_crc_le(6, addrs);
 	crc = crc >> 26;
 	mcast_table [crc >> 4] |= 1 << (crc & 0xf);
     }
diff -urN linux-2.5.2-pre11/drivers/net/shaper.c linux/drivers/net/shaper.c
--- linux-2.5.2-pre11/drivers/net/shaper.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/net/shaper.c	Mon Jan 14 18:28:29 2002
@@ -737,6 +737,11 @@
 
 static void __exit shaper_exit (void)
 {
+	int i;
+
+	for (i = 0; i < shapers; i++)
+		unregister_netdev(&devs[i]);
+
 	kfree(devs);
 	devs = NULL;
 }
diff -urN linux-2.5.2-pre11/drivers/net/sis900.c linux/drivers/net/sis900.c
--- linux-2.5.2-pre11/drivers/net/sis900.c	Tue Oct  9 15:13:03 2001
+++ linux/drivers/net/sis900.c	Mon Jan 14 18:28:29 2002
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.08.01	Aug. 25 2001
+   Revision:	1.08.02	Jan. 4 2002
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,7 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.02 Jan. 4 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
    Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
    Rev 1.07.11 Apr.  2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
@@ -62,11 +63,12 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 
 #include "sis900.h"
 
 static char version[] __devinitdata =
-KERN_INFO "sis900.c: v1.08.01  9/25/2001\n";
+KERN_INFO "sis900.c: v1.08.02  1/4/2002\n";
 
 static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
@@ -1928,26 +1930,7 @@
 static u16 sis900_compute_hashtable_index(u8 *addr, u8 revision)
 {
 
-/* what is the correct value of the POLYNOMIAL ??
-   Donald Becker use 0x04C11DB7U
-   Joseph Zbiciak im14u2c@primenet.com gives me the
-   correct answer, thank you Joe !! */
-#define POLYNOMIAL 0x04C11DB7L
-	u32 crc = 0xffffffff, msb;
-	int  i, j;
-	u32  byte;
-
-	for (i = 0; i < 6; i++) {
-		byte = *addr++;
-		for (j = 0; j < 8; j++) {
-			msb = crc >> 31;
-			crc <<= 1;
-			if (msb ^ (byte & 1)) {
-				crc ^= POLYNOMIAL;
-			}
-			byte >>= 1;
-		}
-	}
+	u32 crc = ether_crc(6, addr);
 
 	/* leave 8 or 7 most siginifant bits */
 	if ((revision == SIS635A_900_REV) || (revision == SIS900B_900_REV))
diff -urN linux-2.5.2-pre11/drivers/net/sk98lin/h/skdrv1st.h linux/drivers/net/sk98lin/h/skdrv1st.h
--- linux-2.5.2-pre11/drivers/net/sk98lin/h/skdrv1st.h	Sun Sep  9 10:45:43 2001
+++ linux/drivers/net/sk98lin/h/skdrv1st.h	Mon Jan 14 18:28:29 2002
@@ -116,6 +116,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/crc32.h>
 #include <asm/byteorder.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
diff -urN linux-2.5.2-pre11/drivers/net/sk98lin/skaddr.c linux/drivers/net/sk98lin/skaddr.c
--- linux-2.5.2-pre11/drivers/net/sk98lin/skaddr.c	Wed Jul  4 11:50:39 2001
+++ linux/drivers/net/sk98lin/skaddr.c	Mon Jan 14 18:28:29 2002
@@ -199,7 +199,6 @@
 /* defines ********************************************************************/
 
 
-#define CRC32_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
 #define HASH_BITS	6				/* #bits in hash */
 #define	SK_MC_BIT	0x01
 
@@ -534,18 +533,9 @@
 unsigned SkCrc32McHash(
 unsigned char *pMc)	/* Multicast address */
 {
-	unsigned Idx;
-	unsigned Bit;
-	unsigned Data;
-	unsigned Crc;
-
-	Crc = 0xFFFFFFFFUL;
-	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
-		Data = *pMc++;
-		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
-			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0);
-		}
-	}
+	u32 Crc;
+
+	Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
 
 	return (Crc & ((1 << HASH_BITS) - 1));
 }	/* SkCrc32McHash */
diff -urN linux-2.5.2-pre11/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- linux-2.5.2-pre11/drivers/net/smc9194.c	Tue Oct 16 21:56:29 2001
+++ linux/drivers/net/smc9194.c	Mon Jan 14 18:28:29 2002
@@ -51,6 +51,7 @@
  .				 allocation
  .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
  .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
+ .      11/08/01 Matt Domsch     Use common crc32 function
  ----------------------------------------------------------------------------*/
 
 static const char version[] =
@@ -69,6 +70,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/errno.h>
@@ -223,10 +225,6 @@
 */
 static void smc_set_multicast_list(struct net_device *dev);
 
-/*
- . CRC compute
- */
-static int crc32( char * s, int length );
 
 /*---------------------------------------------------------------
  .
@@ -436,7 +434,7 @@
 			continue;
 
 		/* only use the low order bits */
-		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+		position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
 
 		/* do some messy swapping to put the bit in the right spot */
 		multicast_table[invert3[position&7]] |=
@@ -450,33 +448,6 @@
 		outb( multicast_table[i], ioaddr + MULTICAST1 + i );
 	}
 }
-
-/*
-  Finds the CRC32 of a set of bytes.
-  Again, from Peter Cammaert's code.
-*/
-static int crc32( char * s, int length ) {
-	/* indices */
-	int perByte;
-	int perBit;
-	/* crc polynomial for Ethernet */
-	const unsigned long poly = 0xedb88320;
-	/* crc value - preinitialized to all 1's */
-	unsigned long crc_value = 0xffffffff;
-
-	for ( perByte = 0; perByte < length; perByte ++ ) {
-		unsigned char	c;
-
-		c = *(s++);
-		for ( perBit = 0; perBit < 8; perBit++ ) {
-			crc_value = (crc_value>>1)^
-				(((crc_value^c)&0x01)?poly:0);
-			c >>= 1;
-		}
-	}
-	return	crc_value;
-}
-
 
 /*
  . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
diff -urN linux-2.5.2-pre11/drivers/net/starfire.c linux/drivers/net/starfire.c
--- linux-2.5.2-pre11/drivers/net/starfire.c	Sun Sep 30 12:26:07 2001
+++ linux/drivers/net/starfire.c	Mon Jan 14 18:28:29 2002
@@ -109,6 +109,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1612,32 +1613,9 @@
 }
 
 
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
+/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
    them.  Select the endian-ness that results in minimal calculations.
 */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- linux-2.5.2-pre11/drivers/net/sunbmac.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/net/sunbmac.c	Mon Jan 14 18:28:29 2002
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -979,9 +980,6 @@
 	return &bp->enet_stats;
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void bigmac_set_multicast(struct net_device *dev)
 {
 	struct bigmac *bp = (struct bigmac *) dev->priv;
@@ -989,7 +987,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 tmp, crc, poly = CRC_POLYNOMIAL_LE;
+	u32 tmp, crc;
 
 	/* Disable the receiver.  The bit self-clears when
 	 * the operation is complete.
@@ -1022,17 +1020,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.5.2-pre11/drivers/net/sundance.c linux/drivers/net/sundance.c
--- linux-2.5.2-pre11/drivers/net/sundance.c	Fri Oct 19 08:32:28 2001
+++ linux/drivers/net/sundance.c	Mon Jan 14 18:28:29 2002
@@ -98,6 +98,7 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -1260,32 +1261,6 @@
 	np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16;
 
 	return &np->stats;
-}
-
-/* The little-endian AUTODIN II ethernet CRC calculations.
-   A big-endian version is also available.
-   This is slow but compact code.  Do not use this routine for bulk data,
-   use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c.
-   Chips may use the upper or lower CRC bits, and may reverse and/or invert
-   them.  Select the endian-ness that results in minimal calculations.
-*/
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
 }
 
 static void set_rx_mode(struct net_device *dev)
diff -urN linux-2.5.2-pre11/drivers/net/sungem.c linux/drivers/net/sungem.c
--- linux-2.5.2-pre11/drivers/net/sungem.c	Sun Oct 21 10:36:54 2001
+++ linux/drivers/net/sungem.c	Mon Jan 14 18:28:29 2002
@@ -1,7 +1,15 @@
-/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $
+/* $Id: sungem.c,v 1.44 2001/12/08 04:06:27 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * 
+ * Support for Apple GMAC and assorted PHYs by
+ * Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * 
+ * TODO: 
+ *  - Get rid of all those nasty mdelay's and replace them
+ * with schedule_timeout.
+ *  - Implement WOL
  */
 
 #include <linux/module.h>
@@ -23,11 +31,16 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
 
 #ifdef __sparc__
 #include <asm/idprom.h>
@@ -45,15 +58,33 @@
 
 #include "sungem.h"
 
+#define DRV_NAME	"sungem"
+#define DRV_VERSION	"0.96"
+#define DRV_RELDATE	"11/17/01"
+#define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
+
 static char version[] __devinitdata =
-        "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n";
+        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
 
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(gem_debug, "i");
 MODULE_PARM_DESC(gem_debug, "(ignored)");
+MODULE_PARM(link_mode, "i");
+
+static int link_mode;
+
+static u16 link_modes[] __devinitdata = {
+	BMCR_ANENABLE,			/* 0 : autoneg */
+	0,				/* 1 : 10bt half duplex */
+	BMCR_SPEED100,			/* 2 : 100bt half duplex */
+	BMCR_SPD2, /* verify this */	/* 3 : 1000bt half duplex */
+	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */
+	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */
+	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */
+};
 
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
@@ -73,7 +104,7 @@
 	 * they only support 10/100 speeds. -DaveM
 	 * 
 	 * Apple's GMAC does support gigabit on machines with
-	 * the BCM5400 or 5401 PHYs. -BenH
+	 * the BCM54xx PHYs. -BenH
 	 */
 	{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -362,10 +393,6 @@
 	return 1;
 }
 
-static void gem_stop(struct gem *, unsigned long);
-static void gem_init_rings(struct gem *, int);
-static void gem_init_hw(struct gem *);
-
 /* All non-normal interrupt conditions get serviced here.
  * Returns non-zero if we should just exit the interrupt
  * handler right now (ie. if we reset the card which invalidates
@@ -418,9 +445,9 @@
 	return 0;
 
 do_reset:
-	gem_stop(gp, gp->regs);
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
+
 	return 1;
 }
 
@@ -627,6 +654,10 @@
 	struct gem *gp = dev->priv;
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+	if (!gp->hw_running) {
+		printk("%s: hrm.. hw not running !\n", dev->name);
+		return;
+	}
 	printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
 	       dev->name,
 	       readl(gp->regs + TXDMA_CFG),
@@ -640,13 +671,19 @@
 
 	spin_lock_irq(&gp->lock);
 
-	gem_stop(gp, gp->regs);
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
 
 	spin_unlock_irq(&gp->lock);
+}
 
-	netif_wake_queue(dev);
+static __inline__ int gem_intme(int entry)
+{
+	/* Algorithm: IRQ every 1/2 of descriptors. */
+	if (!(entry & ((TX_RING_SIZE>>1)-1)))
+		return 1;
+
+	return 0;
 }
 
 static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -690,15 +727,22 @@
 					~PAGE_MASK),
 				       len, PCI_DMA_TODEVICE);
 		ctrl |= TXDCTRL_SOF | TXDCTRL_EOF | len;
+		if (gem_intme(entry))
+			ctrl |= TXDCTRL_INTME;
 		txd->buffer = cpu_to_le64(mapping);
 		txd->control_word = cpu_to_le64(ctrl);
 		entry = NEXT_TX(entry);
 	} else {
 		struct gem_txd *txd;
 		u32 first_len;
+		u64 intme;
 		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
 
+		intme = 0;
+		if (gem_intme(entry))
+			intme |= TXDCTRL_INTME;
+
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
@@ -727,11 +771,15 @@
 			txd->buffer = cpu_to_le64(mapping);
 			txd->control_word = cpu_to_le64(this_ctrl | len);
 
+			if (gem_intme(entry))
+				intme |= TXDCTRL_INTME;
+
 			entry = NEXT_TX(entry);
 		}
 		txd = &gp->init_block->txd[first_entry];
 		txd->buffer = cpu_to_le64(first_mapping);
-		txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | first_len);
+		txd->control_word =
+			cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len);
 	}
 
 	gp->tx_new = entry;
@@ -761,18 +809,19 @@
 		return -EINVAL;
 
 	spin_lock_irq(&gp->lock);
-	gem_stop(gp, gp->regs);
 	dev->mtu = new_mtu;
-	gem_init_rings(gp, 1);
-	gem_init_hw(gp);
+	gp->reset_task_pending = 1;
+	schedule_task(&gp->reset_task);
 	spin_unlock_irq(&gp->lock);
 
+	flush_scheduled_tasks();
+
 	return 0;
 }
 
 #define STOP_TRIES 32
 
-static void gem_stop(struct gem *gp, unsigned long regs)
+static void gem_stop(struct gem *gp)
 {
 	int limit;
 	u32 val;
@@ -781,13 +830,13 @@
 	writel(0xffffffff, gp->regs + GREG_IMASK);
 
 	/* Reset the chip */
-	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST);
+	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
 
 	limit = STOP_TRIES;
 
 	do {
 		udelay(20);
-		val = readl(regs + GREG_SWRST);
+		val = readl(gp->regs + GREG_SWRST);
 		if (limit-- <= 0)
 			break;
 	} while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
@@ -810,6 +859,9 @@
 	val = readl(gp->regs + MAC_RXCFG);
 	writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
 
+	(void) readl(gp->regs + MAC_RXCFG);
+	udelay(100);
+
 	writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
 
 	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
@@ -828,6 +880,88 @@
 	{ 1, 0, 1 },	/* 1000BT */
 };
 
+static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
+{
+	u16 ctl;
+	
+	/* Setup link parameters */
+	if (!ep)
+		goto start_aneg;
+	if (ep->autoneg == AUTONEG_ENABLE) {
+		/* TODO: parse ep->advertising */
+		gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+		gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+		gp->link_cntl = BMCR_ANENABLE;
+	} else {
+		gp->link_cntl = 0;
+		if (ep->speed == SPEED_100)
+			gp->link_cntl |= BMCR_SPEED100;
+		else if (ep->speed == SPEED_1000 && gp->gigabit_capable)
+			/* Hrm... check if this is right... */
+			gp->link_cntl |= BMCR_SPD2;
+		if (ep->duplex == DUPLEX_FULL)
+			gp->link_cntl |= BMCR_FULLDPLX;
+	}
+
+start_aneg:
+	spin_lock_irq(&gp->lock);
+	if (!gp->hw_running) {
+		spin_unlock_irq(&gp->lock);
+		return;
+	}
+
+	/* Configure PHY & start aneg */
+	ctl = phy_read(gp, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+	ctl |= gp->link_cntl;
+	if (ctl & BMCR_ANENABLE) {
+		ctl |= BMCR_ANRESTART;
+		gp->lstate = link_aneg;
+	} else {
+		gp->lstate = link_force_ok;
+	}
+	phy_write(gp, MII_BMCR, ctl);
+
+	gp->timer_ticks = 0;
+	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+	add_timer(&gp->link_timer);
+	spin_unlock_irq(&gp->lock);
+}
+
+static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
+{
+	u32 val;
+
+	*fd = 0;
+	*spd = 10;
+	*pause = 0;
+	
+	if (gp->phy_mod == phymod_bcm5400 ||
+	    gp->phy_mod == phymod_bcm5401 ||
+	    gp->phy_mod == phymod_bcm5411) {
+		int link_mode;	
+
+	    	val = phy_read(gp, MII_BCM5400_AUXSTATUS);
+		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
+		*fd = phy_BCM5400_link_table[link_mode][0];
+		*spd = phy_BCM5400_link_table[link_mode][2] ?
+			1000 :
+			(phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
+		val = phy_read(gp, MII_LPA);
+		if (val & LPA_PAUSE)
+			*pause = 1;
+	} else {
+		val = phy_read(gp, MII_LPA);
+
+		if (val & (LPA_10FULL | LPA_100FULL))
+			*fd = 1;
+		if (val & (LPA_100FULL | LPA_100HALF))
+			*spd = 100;
+	}
+}
+
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
  */
@@ -842,32 +976,13 @@
 
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		if (gp->lstate == aneg_wait) {
-			if (gp->phy_mod == phymod_bcm5400 ||
-			    gp->phy_mod == phymod_bcm5401 ||
-			    gp->phy_mod == phymod_bcm5411) {
-				int link_mode;	
-		    		val = phy_read(gp, PHY_BCM5400_AUXSTATUS);
-		    		link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
-		    			PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
-		    		full_duplex = phy_BCM5400_link_table[link_mode][0];
-		    		speed = phy_BCM5400_link_table[link_mode][2] ? 1000
-		    			: (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
-					val = phy_read(gp, PHY_LPA);
-					if (val & PHY_LPA_PAUSE)
-						pause = 1;	
-			} else {
-				val = phy_read(gp, PHY_LPA);
-				if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
-					full_duplex = 1;
-				if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
-					speed = 100;
-			}
-		} else {
-			val = phy_read(gp, PHY_CTRL);
-			if (val & PHY_CTRL_FDPLX)
+		val = phy_read(gp, MII_BMCR);
+		if (val & BMCR_ANENABLE)
+			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+		else {
+			if (val & BMCR_FULLDPLX)
 				full_duplex = 1;
-			if (val & PHY_CTRL_SPD100)
+			if (val & BMCR_SPEED100)
 				speed = 100;
 		}
 	} else {
@@ -944,56 +1059,142 @@
 
 static int gem_mdio_link_not_up(struct gem *gp)
 {
-	if (gp->lstate == aneg_wait) {
-		u16 val = phy_read(gp, PHY_CTRL);
+	if (gp->lstate == link_force_ret) {
+		printk(KERN_INFO "%s: Autoneg failed again, keeping"
+			" forced mode\n", gp->dev->name);
+		phy_write(gp, MII_BMCR, gp->link_fcntl);
+		gp->timer_ticks = 5;
+		gp->lstate = link_force_ok;
+	} else if (gp->lstate == link_aneg) {
+		u16 val = phy_read(gp, MII_BMCR);
 
 		/* Try forced modes. */
-		val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
-		val &= ~(PHY_CTRL_FDPLX);
-		val |= PHY_CTRL_SPD100;
-		phy_write(gp, PHY_CTRL, val);
-		gp->timer_ticks = 0;
-		gp->lstate = force_wait;
-		return 1;
+		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+		val &= ~(BMCR_FULLDPLX);
+		val |= BMCR_SPEED100;
+		phy_write(gp, MII_BMCR, val);
+		gp->timer_ticks = 5;
+		gp->lstate = link_force_try;
 	} else {
 		/* Downgrade from 100 to 10 Mbps if necessary.
 		 * If already at 10Mbps, warn user about the
 		 * situation every 10 ticks.
 		 */
-		u16 val = phy_read(gp, PHY_CTRL);
-		if (val & PHY_CTRL_SPD100) {
-			val &= ~PHY_CTRL_SPD100;
-			phy_write(gp, PHY_CTRL, val);
-			gp->timer_ticks = 0;
-			return 1;
+		u16 val = phy_read(gp, MII_BMCR);
+		if (val & BMCR_SPEED100) {
+			val &= ~BMCR_SPEED100;
+			phy_write(gp, MII_BMCR, val);
+			gp->timer_ticks = 5;
 		} else {
-			printk(KERN_ERR "%s: Link down, cable problem?\n",
-			       gp->dev->name);
-			val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
-			phy_write(gp, PHY_CTRL, val);
-			gp->timer_ticks = 1;
-			gp->lstate = aneg_wait;
 			return 1;
 		}
 	}
+	return 0;
+}
+
+static void gem_init_rings(struct gem *, int);
+static void gem_init_hw(struct gem *, int);
+
+static void gem_reset_task(void *data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	/* The link went down, we reset the ring, but keep
+	 * DMA stopped. Todo: Use this function for reset
+	 * on error as well.
+	 */
+	if (gp->hw_running && gp->opened) {
+		/* Make sure we don't get interrupts or tx packets */
+		spin_lock_irq(&gp->lock);
+
+		netif_stop_queue(gp->dev);
+
+		writel(0xffffffff, gp->regs + GREG_IMASK);
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Reset the chip & rings */
+		gem_stop(gp);
+		gem_init_rings(gp, 0);
+		gem_init_hw(gp, 0);
+
+		netif_wake_queue(gp->dev);
+	}
+	gp->reset_task_pending = 0;
 }
 
 static void gem_link_timer(unsigned long data)
 {
 	struct gem *gp = (struct gem *) data;
-	int restart_timer = 0;
 
-	gp->timer_ticks++;
+	if (!gp->hw_running)
+		return;
+
+	/* If the link of task is still pending, we just
+	 * reschedule the link timer
+	 */
+	if (gp->reset_task_pending)
+		goto restart;
+	    	
+	spin_lock_irq(&gp->lock);
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		u16 val = phy_read(gp, PHY_STAT);
+		u16 val = phy_read(gp, MII_BMSR);
+		int up;
 
-		if (val & PHY_STAT_LSTAT) {
-			gem_set_link_modes(gp);
-		} else if (gp->timer_ticks < 10) {
-			restart_timer = 1;
+		/* When using autoneg, we really wait for ANEGCOMPLETE or we may
+		 * get a "transcient" incorrect link state
+		 */
+#if 0
+		{
+			u16 cntl = phy_read(gp, MII_BMCR);
+			if (cntl & BMCR_ANENABLE)
+				up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+			else
+				up = (val & BMSR_LSTATUS) != 0;
+		}
+#else
+		up = (val & BMSR_LSTATUS) != 0;
+#endif
+		if (up) {
+			/* Ok, here we got a link. If we had it due to a forced
+			 * fallback, and we were configured for autoneg, we do
+			 * retry a short autoneg pass. If you know your hub is
+			 * broken, use ethtool ;)
+			 */
+			if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) {
+				gp->lstate = link_force_ret;
+				gp->link_fcntl = phy_read(gp, MII_BMCR);
+				gp->timer_ticks = 5;
+				printk(KERN_INFO "%s: Got link after fallback, retrying autoneg"
+				       " once...\n", gp->dev->name);
+				phy_write(gp, MII_BMCR,
+					  gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART);
+			} else if (gp->lstate != link_up) {
+				gp->lstate = link_up;
+				if (gp->opened)
+					gem_set_link_modes(gp);
+			}
 		} else {
-			restart_timer = gem_mdio_link_not_up(gp);
+			int restart = 0;
+
+			/* If the link was previously up, we restart the
+			 * whole process
+			 */
+			if (gp->lstate == link_up) {
+				gp->lstate = link_down;
+				printk(KERN_INFO "%s: Link down\n", gp->dev->name);
+				gp->reset_task_pending = 1;
+				schedule_task(&gp->reset_task);
+				restart = 1;
+			} else if (++gp->timer_ticks > 10)
+				restart = gem_mdio_link_not_up(gp);
+
+			if (restart) {
+				spin_unlock_irq(&gp->lock);
+				gem_begin_auto_negotiation(gp, NULL);
+				return;
+			}
 		}
 	} else {
 		u32 val = readl(gp->regs + PCS_MIISTAT);
@@ -1001,17 +1202,17 @@
 		if (!(val & PCS_MIISTAT_LS))
 			val = readl(gp->regs + PCS_MIISTAT);
 
-		if ((val & PCS_MIISTAT_LS) == 0) {
-			restart_timer = 1;
-		} else {
-			gem_set_link_modes(gp);
+		if ((val & PCS_MIISTAT_LS) != 0) {
+			gp->lstate = link_up;
+			if (gp->opened)
+				gem_set_link_modes(gp);
 		}
 	}
 
-	if (restart_timer) {
-		gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-		add_timer(&gp->link_timer);
-	}
+restart:
+	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
+	add_timer(&gp->link_timer);
+	spin_unlock_irq(&gp->lock);
 }
 
 static void gem_clean_rings(struct gem *gp)
@@ -1108,66 +1309,72 @@
 	}
 }
 
-static int
-gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
+static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
 {
 	u16 val;
 	int limit = 10000;
 	
-	val = __phy_read(gp, PHY_CTRL, phy_addr);
-	val &= ~PHY_CTRL_ISO;
-	val |= PHY_CTRL_RST;
-	__phy_write(gp, PHY_CTRL, val, phy_addr);
+	val = __phy_read(gp, MII_BMCR, phy_addr);
+	val &= ~BMCR_ISOLATE;
+	val |= BMCR_RESET;
+	__phy_write(gp, MII_BMCR, val, phy_addr);
 
 	udelay(100);
 
 	while (limit--) {
-		val = __phy_read(gp, PHY_CTRL, phy_addr);
-		if ((val & PHY_CTRL_RST) == 0)
+		val = __phy_read(gp, MII_BMCR, phy_addr);
+		if ((val & BMCR_RESET) == 0)
 			break;
 		udelay(10);
 	}
-	if ((val & PHY_CTRL_ISO) && limit > 0)
-		__phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr);
+	if ((val & BMCR_ISOLATE) && limit > 0)
+		__phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr);
 	
 	return (limit <= 0);
 }
 
-static void
-gem_init_bcm5400_phy(struct gem *gp)
+static void gem_init_bcm5201_phy(struct gem *gp)
+{
+	u16 data;
+
+	data = phy_read(gp, MII_BCM5201_MULTIPHY);
+	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
+	phy_write(gp, MII_BCM5201_MULTIPHY, data);
+}
+
+static void gem_init_bcm5400_phy(struct gem *gp)
 {
 	u16 data;
 
 	/* Configure for gigabit full duplex */
-	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
-	data |= PHY_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
-	
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
+	
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 	
 	mdelay(10);
 
 	/* Reset and configure cascaded 10/100 PHY */
 	gem_reset_one_mii_phy(gp, 0x1f);
 	
-	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
-	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
 
-	data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
-	data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
+	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
 }
 
-static void
-gem_init_bcm5401_phy(struct gem *gp)
+static void gem_init_bcm5401_phy(struct gem *gp)
 {
 	u16 data;
 	int rev;
 
-	rev = phy_read(gp, PHY_ID1) & 0x000f;
+	rev = phy_read(gp, MII_PHYSID2) & 0x000f;
 	if (rev == 0 || rev == 3) {
 		/* Some revisions of 5401 appear to need this
 		 * initialisation sequence to disable, according
@@ -1191,22 +1398,21 @@
 	}
 	
 	/* Configure for gigabit full duplex */
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 
 	mdelay(1);
 
 	/* Reset and configure cascaded 10/100 PHY */
 	gem_reset_one_mii_phy(gp, 0x1f);
 	
-	data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
-	data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
 }
 
-static void
-gem_init_bcm5411_phy(struct gem *gp)
+static void gem_init_bcm5411_phy(struct gem *gp)
 {
 	u16 data;
 
@@ -1220,20 +1426,30 @@
 	/* Here, Apple seems to want to reset it, do
 	 * it as well
 	 */
-	phy_write(gp, PHY_CTRL, PHY_CTRL_RST);
+	phy_write(gp, MII_BMCR, BMCR_RESET);
 
 	/* Start autoneg */
-	phy_write(gp, PHY_CTRL,
-		  (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX |
-		   PHY_CTRL_ANRES | PHY_CTRL_SPD2));
-
-	data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
-	data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+	phy_write(gp, MII_BMCR,
+		  (BMCR_ANENABLE | BMCR_FULLDPLX |
+		   BMCR_ANRESTART | BMCR_SPD2));
+
+	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 }
 
 static void gem_init_phy(struct gem *gp)
 {
+	u32 mifcfg;
+
+	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+	/* Revert MIF CFG setting done on stop_phy */
+	mifcfg = readl(gp->regs + MIF_CFG);
+	mifcfg &= ~MIF_CFG_BBMODE;
+	writel(mifcfg, gp->regs + MIF_CFG);
+	
 #ifdef CONFIG_ALL_PPC
 	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		int i;
@@ -1241,7 +1457,7 @@
 		pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
 		for (i = 0; i < 32; i++) {
 			gp->mii_phy_addr = i;
-			if (phy_read(gp, PHY_CTRL) != 0xffff)
+			if (phy_read(gp, MII_BMCR) != 0xffff)
 				break;
 		}
 		if (i == 32) {
@@ -1277,54 +1493,68 @@
 		/* Take PHY out of isloate mode and reset it. */
 		gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
 
-		phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1))
+		phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2))
 			 	& 0xfffffff0;
 		printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
 		switch(phy_id) {
-			case 0x406210:
-				gp->phy_mod = phymod_bcm5201;
-				printk("BCM 5201\n");
-				break;
-			case 0x4061e0:
-				printk("BCM 5221\n");
-				gp->phy_mod = phymod_bcm5221;
-				break;
-			case 0x206040:
-				printk("BCM 5400\n");
-				gp->phy_mod = phymod_bcm5400;
-				gem_init_bcm5400_phy(gp);
-				break;
-			case 0x206050:
-				printk("BCM 5401\n");
-				gp->phy_mod = phymod_bcm5401;
-				gem_init_bcm5401_phy(gp);
-				break;
-			case 0x206070:
-				printk("BCM 5411\n");
-				gp->phy_mod = phymod_bcm5411;
-				gem_init_bcm5411_phy(gp);
-				break;
-			default:
-				printk("Generic\n");
-				gp->phy_mod = phymod_generic;
+		case 0x406210:
+			gp->phy_mod = phymod_bcm5201;
+			gem_init_bcm5201_phy(gp);
+			printk("BCM 5201\n");
+			break;
+
+		case 0x4061e0:
+			printk("BCM 5221\n");
+			gp->phy_mod = phymod_bcm5221;
+			break;
+
+		case 0x206040:
+			printk("BCM 5400\n");
+			gp->phy_mod = phymod_bcm5400;
+			gem_init_bcm5400_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x206050:
+			printk("BCM 5401\n");
+			gp->phy_mod = phymod_bcm5401;
+			gem_init_bcm5401_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x206070:
+			printk("BCM 5411\n");
+			gp->phy_mod = phymod_bcm5411;
+			gem_init_bcm5411_phy(gp);
+			gp->gigabit_capable = 1;
+			break;
+
+		case 0x18074c0:
+			printk("Lucent\n");
+			gp->phy_mod = phymod_generic;
+			break;
+
+		case 0x437420:
+			printk("Enable Semiconductor\n");
+			gp->phy_mod = phymod_generic;
+			break;
+
+		default:
+			printk("Unknown\n");
+			gp->phy_mod = phymod_generic;
+			break;
 		};
 
 		/* Init advertisement and enable autonegotiation. */
-		val = phy_read(gp, PHY_CTRL);
-		val &= ~PHY_CTRL_ANENAB;
-		phy_write(gp, PHY_CTRL, val);
+		val = phy_read(gp, MII_BMCR);
+		val &= ~BMCR_ANENABLE;
+		phy_write(gp, MII_BMCR, val);
 		udelay(10);
 		
-		phy_write(gp, PHY_ADV,
-			  phy_read(gp, PHY_ADV) |
-			  (PHY_ADV_10HALF | PHY_ADV_10FULL |
-			   PHY_ADV_100HALF | PHY_ADV_100FULL));
-
-		val = phy_read(gp, PHY_CTRL);
-		val |= PHY_CTRL_ANENAB;
-		phy_write(gp, PHY_CTRL, val);
-		val |= PHY_CTRL_ANRES;
-		phy_write(gp, PHY_CTRL, val);
+		phy_write(gp, MII_ADVERTISE,
+			  phy_read(gp, MII_ADVERTISE) |
+			  (ADVERTISE_10HALF | ADVERTISE_10FULL |
+			   ADVERTISE_100HALF | ADVERTISE_100FULL));
 	} else {
 		u32 val;
 		int limit;
@@ -1379,6 +1609,7 @@
 		else
 			val |= PCS_SCTRL_LOOP;
 		writel(val, gp->regs + PCS_SCTRL);
+		gp->gigabit_capable = 1;
 	}
 }
 
@@ -1392,7 +1623,7 @@
 
 	writel(desc_dma >> 32, gp->regs + TXDMA_DBHI);
 	writel(desc_dma & 0xffffffff, gp->regs + TXDMA_DBLOW);
-	desc_dma += (TX_RING_SIZE * sizeof(struct gem_txd));
+	desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
 
 	writel(0, gp->regs + TXDMA_KICK);
 
@@ -1410,17 +1641,15 @@
 	writel(val, gp->regs + RXDMA_PTHRESH);
 
 	if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
-		writel(((6 & RXDMA_BLANK_IPKTS) |
-			((4 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((8 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 	else
-		writel(((6 & RXDMA_BLANK_IPKTS) |
-			((2 << 12) & RXDMA_BLANK_ITIME)),
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((4 << 12) & RXDMA_BLANK_ITIME)),
 		       gp->regs + RXDMA_BLANK);
 }
 
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void gem_init_mac(struct gem *gp)
 {
 	unsigned char *e = &gp->dev->dev_addr[0];
@@ -1484,9 +1713,9 @@
 		rxcfg |= MAC_RXCFG_PROM;
 	} else {
 		u16 hash_table[16];
-		u32 crc, poly = CRC_POLYNOMIAL_LE;
+		u32 crc;
 		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i, j, bit, byte;
+		int i;
 
 		for (i = 0; i < 16; i++)
 			hash_table[i] = 0;
@@ -1499,17 +1728,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+ 			crc = ether_crc_le(6, addrs);
 			crc >>= 24;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
@@ -1551,18 +1770,20 @@
 	writel(0, gp->regs + MAC_MCCFG);
 	writel(0, gp->regs + MAC_XIFCFG);
 
-	writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE |
-		MAC_TXSTAT_NCE | MAC_TXSTAT_ECE |
-		MAC_TXSTAT_LCE | MAC_TXSTAT_FCE |
-		MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK);
-	writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE |
-		MAC_RXSTAT_ACE | MAC_RXSTAT_CCE |
-		MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK);
-	writel(0, gp->regs + MAC_MCMASK);
+	/* Setup MAC interrupts.  We want to get all of the interesting
+	 * counter expiration events, but we do not want to hear about
+	 * normal rx/tx as the DMA engine tells us that.
+	 */
+	writel(MAC_TXSTAT_XMIT, gp->regs + MAC_TXMASK);
+	writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+
+	/* Don't enable even the PAUSE interrupts for now, we
+	 * make no use of those events other than to record them.
+	 */
+	writel(0xffffffff, gp->regs + MAC_MCMASK);
 }
 
-static void
-gem_init_pause_thresholds(struct gem* gp)
+static void gem_init_pause_thresholds(struct gem *gp)
 {
 	/* Calculate pause thresholds.  Setting the OFF threshold to the
 	 * full RX fifo size effectively disables PAUSE generation which
@@ -1580,11 +1801,7 @@
 	}
 
 	{
-		u32 cfg = readl(gp->regs + GREG_BIFCFG);
-
-		/* XXX Why do I do this? -DaveM XXX */
-		cfg |= GREG_BIFCFG_B64DIS;
-		writel(cfg, gp->regs + GREG_BIFCFG);
+		u32 cfg;
 
 		cfg  = GREG_CFG_IBURST;
 		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
@@ -1598,21 +1815,15 @@
 	struct pci_dev *pdev = gp->pdev;
 	u32 mif_cfg;
 
-	/* On Apple's sungem, we can't realy on registers as the chip
+	/* On Apple's sungem, we can't rely on registers as the chip
 	 * was been powered down by the firmware. We do the PHY lookup
 	 * when the interface is opened and we configure the driver
 	 * with known values.
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gp->phy_type = phy_mii_mdio0;
-		mif_cfg = readl(gp->regs + MIF_CFG);
-		mif_cfg &= ~MIF_CFG_PSELECT;
-		writel(mif_cfg, gp->regs + MIF_CFG);
-		writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
-		writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
 		gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
 		gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
-		gem_init_pause_thresholds(gp);
 		return 0;
 	}
 
@@ -1651,7 +1862,7 @@
 
 		for (i = 0; i < 32; i++) {
 			gp->mii_phy_addr = i;
-			if (phy_read(gp, PHY_CTRL) != 0xffff)
+			if (phy_read(gp, MII_BMCR) != 0xffff)
 				break;
 		}
 		if (i == 32) {
@@ -1685,12 +1896,10 @@
 		}
 	}
 
-	gem_init_pause_thresholds(gp);
-
 	return 0;
 }
 
-static void gem_init_hw(struct gem *gp)
+static void gem_init_hw(struct gem *gp, int restart_link)
 {
 	/* On Apple's gmac, I initialize the PHY only after
 	 * setting up the chip. It appears the gigabit PHYs
@@ -1698,18 +1907,28 @@
 	 * the chip is not running, I suspect it might not
 	 * be clocked at that point. --BenH
 	 */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-		gem_check_invariants(gp);
-		gp->hw_running = 1;
-	}
-	gem_init_phy(gp);
+	if (restart_link)
+		gem_init_phy(gp);
 	gem_init_dma(gp);
 	gem_init_mac(gp);
+	gem_init_pause_thresholds(gp);
 
-	gp->timer_ticks = 0;
-	gp->lstate = aneg_wait;
-	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-	add_timer(&gp->link_timer);
+	spin_lock_irq(&gp->lock);
+	if (restart_link) {
+		/* Default aneg parameters */
+		gp->timer_ticks = 0;
+		gp->lstate = link_down;
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
+		gem_begin_auto_negotiation(gp, NULL);
+	} else {
+		if (gp->lstate == link_up)
+			gem_set_link_modes(gp);
+
+		spin_unlock_irq(&gp->lock);
+	}
 }
 
 #ifdef CONFIG_ALL_PPC
@@ -1717,10 +1936,10 @@
  * setup properly. There appear to be no need to restore the
  * base addresses.
  */
-static void
-gem_apple_powerup(struct gem* gp)
+static void gem_apple_powerup(struct gem *gp)
 {
 	u16 cmd;
+	u32 mif_cfg;
 
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
@@ -1731,31 +1950,162 @@
     	pci_write_config_word(gp->pdev, PCI_COMMAND, cmd);
     	pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6);
     	pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8);
+
+	mdelay(1);
+	
+	mif_cfg = readl(gp->regs + MIF_CFG);
+	mif_cfg &= ~(MIF_CFG_PSELECT|MIF_CFG_POLL|MIF_CFG_BBMODE|MIF_CFG_MDI1);
+	mif_cfg |= MIF_CFG_MDI0;
+	writel(mif_cfg, gp->regs + MIF_CFG);
+	writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+	writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+
+	mdelay(1);
 }
 
 /* Turn off the chip's clock */
-static void
-gem_apple_powerdown(struct gem* gp)
+static void gem_apple_powerdown(struct gem *gp)
 {
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
 }
+
 #endif /* CONFIG_ALL_PPC */
 
+static void gem_stop_phy(struct gem *gp)
+{
+	u32 mifcfg;
+
+	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
+		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
+
+	/* Make sure we aren't polling PHY status change. We
+	 * don't currently use that feature though
+	 */
+	mifcfg = readl(gp->regs + MIF_CFG);
+	mifcfg &= ~MIF_CFG_POLL;
+	writel(mifcfg, gp->regs + MIF_CFG);
+
+	/* Here's a strange hack used by both MacOS 9 and X */
+	phy_write(gp, MII_LPA, phy_read(gp, MII_LPA));
+
+	if (gp->wake_on_lan) {
+		/* Setup wake-on-lan */
+	} else
+		writel(0, gp->regs + MAC_RXCFG);
+	writel(0, gp->regs + MAC_TXCFG);
+	writel(0, gp->regs + MAC_XIFCFG);
+	writel(0, gp->regs + TXDMA_CFG);
+	writel(0, gp->regs + RXDMA_CFG);
+
+	if (!gp->wake_on_lan) {
+		gem_stop(gp);
+		writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
+		writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
+		if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 ||
+		    gp->phy_mod == phymod_bcm5411) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+			phy_write(gp, MII_BMCR, BMCR_PDOWN);
+#endif
+		} else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+			u16 val = phy_read(gp, MII_BCM5201_AUXMODE2)
+			phy_write(gp, MII_BCM5201_AUXMODE2,
+				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
+#endif				
+			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+		}
+
+		/* According to Apple, we must set the MDIO pins to this begnign
+		 * state or we may 1) eat more current, 2) damage some PHYs
+		 */
+		writel(mifcfg | MIF_CFG_BBMODE, gp->regs + MIF_CFG);
+		writel(0, gp->regs + MIF_BBCLK);
+		writel(0, gp->regs + MIF_BBDATA);
+		writel(0, gp->regs + MIF_BBOENAB);
+		writel(MAC_XIFCFG_GMII | MAC_XIFCFG_LBCK, gp->regs + MAC_XIFCFG);
+		(void) readl(gp->regs + MAC_XIFCFG);
+	}
+}
+
+/* Shut down the chip, must be called with pm_sem held.  */
+static void gem_shutdown(struct gem *gp)
+{
+	/* Make us not-running to avoid timers respawning */
+	gp->hw_running = 0;
+
+	/* Stop the link timer */
+	del_timer_sync(&gp->link_timer);
+
+	/* Stop the reset task */
+	while (gp->reset_task_pending)
+		schedule();
+	
+	/* Actually stop the chip */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_stop_phy(gp);
+	else
+		gem_stop(gp);
+
+#ifdef CONFIG_ALL_PPC
+	/* Power down the chip */
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
+}
+
+static void gem_pm_task(void *data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	/* We assume if we can't lock the pm_sem, then open() was
+	 * called again (or suspend()), and we can safely ignore
+	 * the PM request
+	 */
+	if (down_trylock(&gp->pm_sem))
+		return;
+
+	/* Driver was re-opened or already shut down */
+	if (gp->opened || !gp->hw_running) {
+		up(&gp->pm_sem);
+		return;
+	}
+
+	gem_shutdown(gp);
+
+	up(&gp->pm_sem);
+}
+
+static void gem_pm_timer(unsigned long data)
+{
+	struct gem *gp = (struct gem *) data;
+
+	schedule_task(&gp->pm_task);
+}
+
 static int gem_open(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
-	unsigned long regs = gp->regs;
+	int hw_was_up = gp->hw_running;
 
-	del_timer(&gp->link_timer);
+	down(&gp->pm_sem);
 
+	/* Stop the PM timer/task */
+	del_timer(&gp->pm_timer);
+	flush_scheduled_tasks();
+
+	if (!gp->hw_running) {
 #ifdef CONFIG_ALL_PPC
-	/* First, we need to bring up the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-		gem_apple_powerup(gp);
+		/* First, we need to bring up the chip */
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+			gem_apple_powerup(gp);
+			gem_check_invariants(gp);
+		}
 #endif /* CONFIG_ALL_PPC */
+		/* Reset the chip */
+		gem_stop(gp);
 
-	/* Reset the chip */
-	gem_stop(gp, regs);
+		gp->hw_running = 1;
+	}
 
 	/* We can now request the interrupt as we know it's masked
 	 * on the controller
@@ -1763,9 +2113,14 @@
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
 #ifdef CONFIG_ALL_PPC
-		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
+		/* Fire the PM timer that will shut us down in about 10 seconds */
+		gp->pm_timer.expires = jiffies + 10*HZ;
+		add_timer(&gp->pm_timer);
+		up(&gp->pm_sem);
+
 		return -EAGAIN;
 	}
 
@@ -1773,7 +2128,11 @@
 	gem_init_rings(gp, 0);
 
 	/* Init & setup chip hardware */
-	gem_init_hw(gp);
+	gem_init_hw(gp, !hw_was_up);
+
+	gp->opened = 1;
+
+	up(&gp->pm_sem);
 
 	return 0;
 }
@@ -1782,17 +2141,110 @@
 {
 	struct gem *gp = dev->priv;
 
-	del_timer(&gp->link_timer);
-	gem_stop(gp, gp->regs);
+	/* Make sure we don't get distracted by suspend/resume */
+	down(&gp->pm_sem);
+
+	/* Stop traffic, mark us closed */
+	spin_lock_irq(&gp->lock);
+
+	gp->opened = 0;	
+	writel(0xffffffff, gp->regs + GREG_IMASK);
+	netif_stop_queue(dev);
+
+	spin_unlock_irq(&gp->lock);
+
+	/* Stop chip */
+	gem_stop(gp);
+
+	/* Get rid of rings */
 	gem_clean_rings(gp);
-	gp->hw_running = 0;
+
+	/* Bye, the pm timer will finish the job */
+	free_irq(gp->pdev->irq, (void *) dev);
+
+	/* Fire the PM timer that will shut us down in about 10 seconds */
+	gp->pm_timer.expires = jiffies + 10*HZ;
+	add_timer(&gp->pm_timer);
+
+	up(&gp->pm_sem);
+	
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gem_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct gem *gp = dev->priv;
+
+	/* We hold the PM semaphore during entire driver
+	 * sleep time
+	 */
+	down(&gp->pm_sem);
+
+	printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
+	       dev->name, gp->wake_on_lan ? "enabled" : "disabled");
+	
+	/* If the driver is opened, we stop the DMA */
+	if (gp->opened) {
+		/* Stop traffic, mark us closed */
+		netif_device_detach(dev);
+
+		spin_lock_irq(&gp->lock);
+
+		writel(0xffffffff, gp->regs + GREG_IMASK);
+
+		spin_unlock_irq(&gp->lock);
+
+		/* Stop chip */
+		gem_stop(gp);
+
+		/* Get rid of ring buffers */
+		gem_clean_rings(gp);
+
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+			disable_irq(gp->pdev->irq);
+	}
+
+	if (gp->hw_running) {
+		/* Kill PM timer if any */
+		del_timer_sync(&gp->pm_timer);
+		flush_scheduled_tasks();
+
+		gem_shutdown(gp);
+	}
+
+	return 0;
+}
+
+static int gem_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct gem *gp = dev->priv;
+
+	printk(KERN_INFO "%s: resuming\n", dev->name);
+
+	if (gp->opened) {
 #ifdef CONFIG_ALL_PPC
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
-		gem_apple_powerdown(gp);
+		/* First, we need to bring up the chip */
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+			gem_apple_powerup(gp);
+			gem_check_invariants(gp);
+		}
 #endif /* CONFIG_ALL_PPC */
-	free_irq(gp->pdev->irq, (void *)dev);
+		gem_stop(gp);
+		gp->hw_running = 1;
+		gem_init_rings(gp, 0);
+		gem_init_hw(gp, 1);
+		netif_device_attach(dev);
+		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+			enable_irq(gp->pdev->irq);
+	}
+	up(&gp->pm_sem);
+
 	return 0;
 }
+#endif /* CONFIG_PM */
 
 static struct net_device_stats *gem_get_stats(struct net_device *dev)
 {
@@ -1861,9 +2313,9 @@
 		writel(rxcfg, gp->regs + MAC_RXCFG);
 	} else {
 		u16 hash_table[16];
-		u32 crc, poly = CRC_POLYNOMIAL_LE;
+		u32 crc;
 		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i, j, bit, byte;
+		int i;
 
 		for (i = 0; i < 16; i++)
 			hash_table[i] = 0;
@@ -1876,17 +2328,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 24;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
@@ -1908,12 +2350,219 @@
 		writel(hash_table[15], gp->regs + MAC_HASH15);
 	}
 
+	/* Hrm... we may walk on the reset task here... */
 	netif_wake_queue(dev);
 }
 
+/* Eventually add support for changing the advertisement
+ * on autoneg.
+ */
+static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
+{
+	struct gem *gp = dev->priv;
+	u16 bmcr;
+	int full_duplex, speed, pause;
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
+		return -EFAULT;
+		
+	switch(ecmd.cmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { cmd: ETHTOOL_GDRVINFO };
+
+		strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
+		strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
+		info.fw_version[0] = '\0';
+		strncpy(info.bus_info, gp->pdev->slot_name, ETHTOOL_BUSINFO_LEN);
+		info.regdump_len = 0; /*SUNGEM_NREGS;*/
+
+		if (copy_to_user(ep_user, &info, sizeof(info)))
+			return -EFAULT;
+
+		return 0;
+	}
+
+	case ETHTOOL_GSET:
+		ecmd.supported =
+			(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+			 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+		if (gp->gigabit_capable)
+			ecmd.supported |=
+				(SUPPORTED_1000baseT_Half |
+				 SUPPORTED_1000baseT_Full);
+
+		/* XXX hardcoded stuff for now */
+		ecmd.port = PORT_MII;
+		ecmd.transceiver = XCVR_EXTERNAL;
+		ecmd.phy_address = 0; /* XXX fixed PHYAD */
+
+		/* Record PHY settings if HW is on. */
+		if (gp->hw_running) {
+			bmcr = phy_read(gp, MII_BMCR);
+			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
+		} else
+			bmcr = 0;
+		if (bmcr & BMCR_ANENABLE) {
+			ecmd.autoneg = AUTONEG_ENABLE;
+			ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+		} else {
+			ecmd.autoneg = AUTONEG_DISABLE;
+			ecmd.speed =
+				(bmcr & BMCR_SPEED100) ?
+				SPEED_100 : SPEED_10;
+			ecmd.duplex =
+				(bmcr & BMCR_FULLDPLX) ?
+				DUPLEX_FULL : DUPLEX_HALF;
+		}
+		if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+
+	case ETHTOOL_SSET:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Verify the settings we care about. */
+		if (ecmd.autoneg != AUTONEG_ENABLE &&
+		    ecmd.autoneg != AUTONEG_DISABLE)
+			return -EINVAL;
+
+		if (ecmd.autoneg == AUTONEG_DISABLE &&
+		    ((ecmd.speed != SPEED_100 &&
+		      ecmd.speed != SPEED_10) ||
+		     (ecmd.duplex != DUPLEX_HALF &&
+		      ecmd.duplex != DUPLEX_FULL)))
+			return -EINVAL;
+
+		/* Apply settings and restart link process */
+		if (gp->hw_running)
+			del_timer(&gp->link_timer);
+		gem_begin_auto_negotiation(gp, &ecmd);
+		return 0;
+
+	case ETHTOOL_NWAY_RST:
+		if ((gp->link_cntl & BMCR_ANENABLE) == 0)
+			return -EINVAL;
+		if (gp->hw_running)
+			del_timer(&gp->link_timer);
+		gem_begin_auto_negotiation(gp, NULL);
+		return 0;
+
+	case ETHTOOL_GWOL:
+	case ETHTOOL_SWOL:
+		break; /* todo */
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { cmd: ETHTOOL_GLINK };
+
+		edata.data = (gp->lstate == link_up);
+		if (copy_to_user(ep_user, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL };
+
+		edata.data = gem_debug;
+		if (copy_to_user(ep_user, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+
+		if (copy_from_user(&edata, ep_user, sizeof(edata)))
+			return -EFAULT;
+		gem_debug = edata.data;
+		return 0;
+	}
+
+#if 0
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs;
+		u32 *regbuf;
+		int r = 0;
+
+		if (copy_from_user(&regs, useraddr, sizeof(regs)))
+			return -EFAULT;
+		
+		if (regs.len > SUNGEM_NREGS) {
+			regs.len = SUNGEM_NREGS;
+		}
+		regs.version = 0;
+		if (copy_to_user(useraddr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		if (!gp->hw_running)
+			return -ENODEV;
+		useraddr += offsetof(struct ethtool_regs, data);
+
+		/* Use kmalloc to avoid bloating the stack */
+		regbuf = kmalloc(4 * SUNGEM_NREGS, GFP_KERNEL);
+		if (!regbuf)
+			return -ENOMEM;
+		spin_lock_irq(&np->lock);
+		gem_get_regs(gp, regbuf);
+		spin_unlock_irq(&np->lock);
+
+		if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32)))
+			r = -EFAULT;
+		kfree(regbuf);
+		return r;
+	}
+#endif	
+	};
+
+	return -EOPNOTSUPP;
+}
+
 static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	return -EINVAL;
+	struct gem *gp = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	int rc = -EOPNOTSUPP;
+	
+	/* Hold the PM semaphore while doing ioctl's or we may collide
+	 * with open/close and power management and oops.
+	 */
+	down(&gp->pm_sem);
+	
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = gem_ethtool_ioctl(dev, ifr->ifr_data);
+		break;
+
+	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
+		data->phy_id = gp->mii_phy_addr;
+		/* Fallthrough... */
+
+	case SIOCGMIIREG:		/* Read MII PHY register. */
+		data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f);
+		rc = 0;
+		break;
+
+	case SIOCSMIIREG:		/* Write MII PHY register. */
+		if (!capable(CAP_NET_ADMIN)) {
+			rc = -EPERM;
+		} else {
+			__phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f);
+			rc = 0;
+		}
+		break;
+	};
+
+	up(&gp->pm_sem);
+	
+	return rc;
 }
 
 static int __devinit gem_get_device_address(struct gem *gp)
@@ -2030,6 +2679,26 @@
 	gp->dev = dev;
 
 	spin_lock_init(&gp->lock);
+	init_MUTEX(&gp->pm_sem);
+
+	init_timer(&gp->link_timer);
+	gp->link_timer.function = gem_link_timer;
+	gp->link_timer.data = (unsigned long) gp;
+
+	init_timer(&gp->pm_timer);
+	gp->pm_timer.function = gem_pm_timer;
+	gp->pm_timer.data = (unsigned long) gp;
+
+	INIT_TQUEUE(&gp->pm_task, gem_pm_task, gp);
+	INIT_TQUEUE(&gp->reset_task, gem_reset_task, gp);
+	
+	/* Default link parameters */
+	if (link_mode >= 0 && link_mode <= 6)
+		gp->link_cntl = link_modes[link_mode];
+	else
+		gp->link_cntl = BMCR_ANENABLE;
+	gp->lstate = link_down;
+	gp->timer_ticks = 0;
 
 	gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len);
 	if (gp->regs == 0UL) {
@@ -2038,9 +2707,26 @@
 		goto err_out_free_mmio_res;
 	}
 
-	/* On Apple's, we might not access the hardware at that point */
+	/* On Apple, we power the chip up now in order for check
+	 * invariants to work, but also because the firmware might
+	 * not have properly shut down the PHY.
+	 */
+#ifdef CONFIG_ALL_PPC
+	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+		gem_apple_powerup(gp);
+		if (gem_check_invariants(gp))
+			goto err_out_iounmap;
+		gem_stop(gp);
+		gp->hw_running = 1;
+		gem_init_phy(gp);
+		gem_begin_auto_negotiation(gp, NULL);
+	}
+#endif
+	/* Non Apple hardware, we just reset the chip and check
+	 * for invariants
+	 */
 	if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
-		gem_stop(gp, gp->regs);
+		gem_stop(gp);
 		if (gem_check_invariants(gp))
 			goto err_out_iounmap;
 		gp->hw_running = 1;
@@ -2074,10 +2760,6 @@
 		       i == 5 ? ' ' : ':');
 	printk("\n");
 
-	init_timer(&gp->link_timer);
-	gp->link_timer.function = gem_link_timer;
-	gp->link_timer.data = (unsigned long) gp;
-
 	dev->open = gem_open;
 	dev->stop = gem_close;
 	dev->hard_start_xmit = gem_start_xmit;
@@ -2095,9 +2777,20 @@
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
+	/* Fire the PM timer that will shut us down in about 10 seconds */
+	gp->pm_timer.expires = jiffies + 10*HZ;
+	add_timer(&gp->pm_timer);
+
 	return 0;
 
 err_out_iounmap:
+	down(&gp->pm_sem);
+	/* Stop the PM timer & task */
+	del_timer_sync(&gp->pm_timer);
+	flush_scheduled_tasks();
+	if (gp->hw_running)
+		gem_shutdown(gp);
+	up(&gp->pm_sem);
 	iounmap((void *) gp->regs);
 
 err_out_free_mmio_res:
@@ -2120,6 +2813,14 @@
 
 		unregister_netdev(dev);
 
+		down(&gp->pm_sem);
+		/* Stop the PM timer & task */
+		del_timer_sync(&gp->pm_timer);
+		flush_scheduled_tasks();
+		if (gp->hw_running)
+			gem_shutdown(gp);
+		up(&gp->pm_sem);
+
 		pci_free_consistent(pdev,
 				    sizeof(struct gem_init_block),
 				    gp->init_block,
@@ -2127,9 +2828,6 @@
 		iounmap((void *) gp->regs);
 		release_mem_region(pci_resource_start(pdev, 0),
 				   pci_resource_len(pdev, 0));
-#ifdef CONFIG_ALL_PPC
-		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
-#endif		
 		kfree(dev);
 
 		pci_set_drvdata(pdev, NULL);
@@ -2140,7 +2838,11 @@
 	name:		GEM_MODULE_NAME,
 	id_table:	gem_pci_tbl,
 	probe:		gem_init_one,
-	remove:		gem_remove_one,
+	remove:		__devexit_p(gem_remove_one),
+#ifdef CONFIG_PM
+	suspend:	gem_suspend,
+	resume:		gem_resume,
+#endif /* CONFIG_PM */
 };
 
 static int __init gem_init(void)
diff -urN linux-2.5.2-pre11/drivers/net/sungem.h linux/drivers/net/sungem.h
--- linux-2.5.2-pre11/drivers/net/sungem.h	Sun Oct 21 10:36:54 2001
+++ linux/drivers/net/sungem.h	Mon Jan 14 18:28:29 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $
+/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -753,64 +753,38 @@
 #define PROM_SIZE	0x0fffffUL	/* Size of ROM			*/
 #define PROM_END	0x200000UL	/* End of ROM			*/
 
-/* MII phy registers */
-#define PHY_CTRL	0x00
-#define PHY_STAT	0x01
-#define PHY_ID0		0x02
-#define PHY_ID1		0x03
-#define PHY_ADV		0x04
-#define PHY_LPA		0x05
-
-#define PHY_CTRL_SPD2	0x0040		/* Gigabit enable? (bcm5411)	*/
-#define PHY_CTRL_FDPLX	0x0100		/* Full duplex			*/
-#define PHY_CTRL_ISO	0x0400		/* Isloate MII from PHY		*/
-#define PHY_CTRL_ANRES	0x0200		/* Auto-negotiation restart	*/
-#define PHY_CTRL_ANENAB	0x1000		/* Auto-negotiation enable	*/
-#define PHY_CTRL_SPD100	0x2000		/* Select 100Mbps		*/
-#define PHY_CTRL_RST	0x8000		/* Reset PHY			*/
-
-#define PHY_STAT_LSTAT	0x0004		/* Link status			*/
-#define PHY_STAT_ANEGC	0x0020		/* Auto-negotiation complete	*/
-
-#define PHY_ADV_10HALF	0x0020
-#define PHY_ADV_10FULL	0x0040
-#define PHY_ADV_100HALF	0x0080
-#define PHY_ADV_100FULL	0x0100
-
-#define PHY_LPA_10HALF	0x0020
-#define PHY_LPA_10FULL	0x0040
-#define PHY_LPA_100HALF	0x0080
-#define PHY_LPA_100FULL	0x0100
-#define PHY_LPA_PAUSE	0x0400
-#define PHY_LPA_FAULT	0x2000
+/* MII definitions missing from mii.h */
+
+#define BMCR_SPD2	0x0040		/* Gigabit enable? (bcm5411)	*/
+#define LPA_PAUSE	0x0400
 
 /* More PHY registers (specific to Broadcom models) */
 
 /* MII BCM5201 MULTIPHY interrupt register */
-#define PHY_BCM5201_INTERRUPT			0x1A
-#define PHY_BCM5201_INTERRUPT_INTENABLE		0x4000
+#define MII_BCM5201_INTERRUPT			0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE		0x4000
 
-#define PHY_BCM5201_AUXMODE2			0x1B
-#define PHY_BCM5201_AUXMODE2_LOWPOWER		0x0008
+#define MII_BCM5201_AUXMODE2			0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER		0x0008
 
-#define PHY_BCM5201_MULTIPHY                    0x1E
+#define MII_BCM5201_MULTIPHY                    0x1E
 
 /* MII BCM5201 MULTIPHY register bits */
-#define PHY_BCM5201_MULTIPHY_SERIALMODE         0x0002
-#define PHY_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+#define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
 
 /* MII BCM5400 1000-BASET Control register */
-#define PHY_BCM5400_GB_CONTROL			0x09
-#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
+#define MII_BCM5400_GB_CONTROL			0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
 
 /* MII BCM5400 AUXCONTROL register */
-#define PHY_BCM5400_AUXCONTROL                  0x18
-#define PHY_BCM5400_AUXCONTROL_PWR10BASET       0x0004
+#define MII_BCM5400_AUXCONTROL                  0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET       0x0004
 
 /* MII BCM5400 AUXSTATUS register */
-#define PHY_BCM5400_AUXSTATUS                   0x19
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
-#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
+#define MII_BCM5400_AUXSTATUS                   0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
 
 /* When it can, GEM internally caches 4 aligned TX descriptors
  * at a time, so that it can use full cacheline DMA reads.
@@ -936,9 +910,21 @@
 
 #define RX_COPY_THRESHOLD  256
 
+#if TX_RING_SIZE < 128
+#define INIT_BLOCK_TX_RING_SIZE		128
+#else
+#define INIT_BLOCK_TX_RING_SIZE		TX_RING_SIZE
+#endif
+
+#if RX_RING_SIZE < 128
+#define INIT_BLOCK_RX_RING_SIZE		128
+#else
+#define INIT_BLOCK_RX_RING_SIZE		RX_RING_SIZE
+#endif
+
 struct gem_init_block {
-	struct gem_txd	txd[TX_RING_SIZE];
-	struct gem_rxd	rxd[RX_RING_SIZE];
+	struct gem_txd	txd[INIT_BLOCK_TX_RING_SIZE];
+	struct gem_rxd	rxd[INIT_BLOCK_RX_RING_SIZE];
 };
 
 enum gem_phy_type {
@@ -958,9 +944,12 @@
 };
 
 enum link_state {
-	aneg_wait,
-	force_wait,
-	aneg_up,
+	link_down = 0,	/* No link, will retry */
+	link_aneg,	/* Autoneg in progress */
+	link_force_try,	/* Try Forced link speed */
+	link_force_ret,	/* Forced mode worked, retrying autoneg */
+	link_force_ok,	/* Stay in forced mode */
+	link_up		/* Link is up */
 };
 
 struct gem {
@@ -973,6 +962,10 @@
 	 * (ie. not power managed)
 	 */
 	int hw_running;
+	int opened;
+	struct semaphore pm_sem;
+	struct tq_struct pm_task;
+	struct timer_list pm_timer;
 
 	struct gem_init_block *init_block;
 
@@ -988,14 +981,22 @@
 	int			rx_pause_off;
 	int			rx_pause_on;
 	int			mii_phy_addr;
+	int			gigabit_capable;
 
+	/* Autoneg & PHY control */
+	int			link_cntl;
+	int			link_advertise;
+	int			link_fcntl;
+	enum link_state		lstate;
+	struct timer_list	link_timer;
+	int			timer_ticks;
+	int			wake_on_lan;
+	struct tq_struct	reset_task;
+	volatile int		reset_task_pending;
+	
 	/* Diagnostic counters and state. */
 	u64 pause_entered;
 	u16 pause_last_time_recvd;
-
-	struct timer_list link_timer;
-	int timer_ticks;
-	enum link_state lstate;
 
 	dma_addr_t gblock_dvma;
 	struct pci_dev *pdev;
diff -urN linux-2.5.2-pre11/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- linux-2.5.2-pre11/drivers/net/sunhme.c	Fri Oct 12 15:35:53 2001
+++ linux/drivers/net/sunhme.c	Mon Jan 14 18:28:29 2002
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1469,9 +1470,6 @@
 	add_timer(&hp->happy_timer);
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static int happy_meal_init(struct happy_meal *hp, int from_irq)
 {
 	unsigned long gregs        = hp->gregs;
@@ -1583,8 +1581,8 @@
 		u16 hash_table[4];
 		struct dev_mc_list *dmi = hp->dev->mc_list;
 		char *addrs;
-		int i, j, bit, byte;
-		u32 crc, poly = CRC_POLYNOMIAL_LE;
+		int i;
+		u32 crc;
 
 		for (i = 0; i < 4; i++)
 			hash_table[i] = 0;
@@ -1596,17 +1594,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
@@ -2385,8 +2373,8 @@
 	unsigned long bregs = hp->bigmacregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	int i;
+	u32 crc;
 
 	/* Lock out others. */
 	netif_stop_queue(dev);
@@ -2412,17 +2400,7 @@
 			if (!(*addrs & 1))
 				continue;
 
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.5.2-pre11/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- linux-2.5.2-pre11/drivers/net/sunlance.c	Tue Oct 30 15:08:11 2001
+++ linux/drivers/net/sunlance.c	Mon Jan 14 18:28:29 2002
@@ -62,12 +62,15 @@
  * 	          Anton Blanchard (anton@progsoc.uts.edu.au)
  * 2.00: 11/9/99: Massive overhaul and port to new SBUS driver interfaces.
  *		  David S. Miller (davem@redhat.com)
+ * 2.01:
+ *      11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
+ *		  
  */
 
 #undef DEBUG_DRIVER
 
 static char version[] =
-	"sunlance.c:v2.00 11/Sep/99 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+	"sunlance.c:v2.01 08/Nov/01 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
 
 static char lancestr[] = "LANCE";
 
@@ -86,6 +89,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -115,9 +119,6 @@
 #define LANCE_LOG_RX_BUFFERS 4
 #endif
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -1181,7 +1182,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 	
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
@@ -1211,19 +1212,7 @@
 		/* multicast address? */
 		if (!(*addrs & 1))
 			continue;
-
-		crc = 0xffffffff;
-		for (byte = 0; byte < 6; byte++) {
-			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-				int test;
-
-				test = ((bit ^ crc) & 0x01);
-				crc >>= 1;
-
-				if (test)
-					crc = crc ^ poly;
-			}
-		}
+		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
 		if (lp->pio_buffer) {
 			u16 tmp = sbus_readw(&mcast_table[crc>>4]);
diff -urN linux-2.5.2-pre11/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- linux-2.5.2-pre11/drivers/net/sunqe.c	Sun Oct 21 10:36:54 2001
+++ linux/drivers/net/sunqe.c	Mon Jan 14 18:28:29 2002
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.52 2001/10/18 08:18:08 davem Exp $
+/* $Id: sunqe.c,v 1.53 2001/12/21 00:54:31 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/crc32.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -494,6 +495,7 @@
 				spin_unlock(&qep->lock);
 			}
 	next:
+			;
 		}
 		qec_status >>= 4;
 		channel++;
@@ -621,9 +623,6 @@
 	return &qep->net_stats;
 }
 
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
-
 static void qe_set_multicast(struct net_device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -631,7 +630,7 @@
 	u8 new_mconfig = qep->mconfig;
 	char *addrs;
 	int i, j, bit, byte;
-	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	u32 crc;
 
 	/* Lock out others. */
 	netif_stop_queue(dev);
@@ -659,18 +658,7 @@
 
 			if (!(*addrs & 1))
 				continue;
-
-			crc = 0xffffffffU;
-			for (byte = 0; byte < 6; byte++) {
-				for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
-					int test;
-
-					test = ((bit ^ crc) & 0x01);
-					crc >>= 1;
-					if (test)
-						crc = crc ^ poly;
-				}
-			}
+			crc = ether_crc_le(6, addrs);
 			crc >>= 26;
 			hash_table[crc >> 4] |= 1 << (crc & 0xf);
 		}
diff -urN linux-2.5.2-pre11/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- linux-2.5.2-pre11/drivers/net/tulip/tulip_core.c	Tue Dec 11 10:47:49 2001
+++ linux/drivers/net/tulip/tulip_core.c	Mon Jan 14 18:28:29 2002
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
@@ -967,41 +968,6 @@
    Note that we only use exclusion around actually queueing the
    new frame, not around filling tp->setup_frame.  This is non-deterministic
    when re-entered but still correct. */
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
-	u32 crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
 
 #undef set_bit_le
 #define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
diff -urN linux-2.5.2-pre11/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- linux-2.5.2-pre11/drivers/net/via-rhine.c	Fri Nov  9 13:45:36 2001
+++ linux/drivers/net/via-rhine.c	Mon Jan 14 18:28:29 2002
@@ -151,6 +151,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1517,26 +1518,6 @@
 	writel(0, ioaddr + RxMissed);
 	readw(ioaddr + RxCRCErrs);
 	readw(ioaddr + RxMissed);
-}
-
-
-/* The big-endian AUTODIN II ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-    }
-    return crc;
 }
 
 static void via_rhine_set_rx_mode(struct net_device *dev)
diff -urN linux-2.5.2-pre11/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- linux-2.5.2-pre11/drivers/net/winbond-840.c	Tue Oct  9 15:13:02 2001
+++ linux/drivers/net/winbond-840.c	Mon Jan 14 18:28:29 2002
@@ -136,6 +136,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/rtnetlink.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
@@ -389,7 +390,6 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void netdev_error(struct net_device *dev, int intr_status);
 static int  netdev_rx(struct net_device *dev);
-static inline unsigned ether_crc(int length, unsigned char *data);
 static u32 __set_rx_mode(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
@@ -1407,21 +1407,6 @@
 	return &np->stats;
 }
 
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-		}
-    }
-    return crc;
-}
 
 static u32 __set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- linux-2.5.2-pre11/drivers/net/yellowfin.c	Fri Oct 19 08:32:28 2001
+++ linux/drivers/net/yellowfin.c	Mon Jan 14 18:28:30 2002
@@ -125,6 +125,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/unaligned.h>
@@ -1338,29 +1339,6 @@
 }
 
 /* Set or clear the multicast filter for this adaptor. */
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
-   N.B. Do not use for bulk data, use a table-based routine instead.
-   This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-
-static inline unsigned ether_crc_le(int length, unsigned char *data)
-{
-	unsigned int crc = 0xffffffff;	/* Initial value. */
-	while(--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 8; --bit >= 0; current_octet >>= 1) {
-			if ((crc ^ current_octet) & 1) {
-				crc >>= 1;
-				crc ^= ethernet_polynomial_le;
-			} else
-				crc >>= 1;
-		}
-	}
-	return crc;
-}
-
 
 static void set_rx_mode(struct net_device *dev)
 {
diff -urN linux-2.5.2-pre11/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h
--- linux-2.5.2-pre11/drivers/s390/block/dasd_int.h	Mon Jan 14 18:28:23 2002
+++ linux/drivers/s390/block/dasd_int.h	Mon Jan 14 18:28:30 2002
@@ -115,7 +115,7 @@
 static inline struct request * 
 dasd_next_request( request_queue_t *queue ) 
 {
-        return blkdev_entry_next_request(&queue->queue_head);
+        return elv_next_request(queue);
 }
 static inline void 
 dasd_dequeue_request( request_queue_t * q, struct request *req )
diff -urN linux-2.5.2-pre11/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- linux-2.5.2-pre11/drivers/s390/block/xpram.c	Sat Dec  8 20:02:47 2001
+++ linux/drivers/s390/block/xpram.c	Mon Jan 14 18:28:30 2002
@@ -771,7 +771,7 @@
 
 		fault=0;
 #if ( XPRAM_VERSION == 24 )
-		current_req = blkdev_entry_next_request (&queue->queue_head);
+		current_req = CURRENT;
 #endif /* V24 */
 		dev_no = DEVICE_NR(current_req->rq_dev); 
 		/* Check if the minor number is in range */
diff -urN linux-2.5.2-pre11/drivers/s390/char/tapedefs.h linux/drivers/s390/char/tapedefs.h
--- linux-2.5.2-pre11/drivers/s390/char/tapedefs.h	Wed Jul 25 14:12:02 2001
+++ linux/drivers/s390/char/tapedefs.h	Mon Jan 14 18:28:30 2002
@@ -41,7 +41,7 @@
 static inline struct request * 
 tape_next_request( request_queue_t *queue ) 
 {
-        return blkdev_entry_next_request(&queue->queue_head);
+        return elv_next_request(queue);
 }
 static inline void 
 tape_dequeue_request( request_queue_t * q, struct request *req )
diff -urN linux-2.5.2-pre11/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- linux-2.5.2-pre11/drivers/sbus/audio/audio.c	Wed Oct 10 23:42:46 2001
+++ linux/drivers/sbus/audio/audio.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.62 2001/10/08 22:19:50 davem Exp $
+/* $Id: audio.c,v 1.63 2002/01/08 16:00:21 davem Exp $
  * drivers/sbus/audio/audio.c
  *
  * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -202,7 +202,7 @@
 {
         unsigned int mask = 0;
         struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
 
         poll_wait(file, &drv->input_read_wait, wait);
@@ -221,7 +221,7 @@
                                size_t count, loff_t *ppos)
 {
         struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
         int bytes_to_copy, bytes_read = 0, err;
 
@@ -296,7 +296,7 @@
                                 size_t count, loff_t *ppos)
 {
         struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
         int bytes_written = 0, bytes_to_copy, err;
   
@@ -396,7 +396,7 @@
 static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
                                   unsigned int cmd, unsigned int *arg)
 {
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
         unsigned long i = 0, j = 0, l = 0, m = 0;
         unsigned int k = 0;
@@ -647,7 +647,7 @@
 			    unsigned int cmd, unsigned long arg)
 {
 	int retval = 0, i, j, k;
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct audio_info ainfo;
 	audio_buf_info binfo;
 	count_info cinfo;
@@ -1701,7 +1701,7 @@
 
 static int sparcaudio_open(struct inode * inode, struct file * file)
 {
-        int minor = MINOR(inode->i_rdev);
+        int minor = minor(inode->i_rdev);
 	struct sparcaudio_driver *drv = 
                 drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
 	int err;
@@ -1835,7 +1835,7 @@
 
 static int sparcaudio_release(struct inode * inode, struct file * file)
 {
-        struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >>
+        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
                                                  SPARCAUDIO_DEVICE_SHIFT)];
 
 	lock_kernel();
diff -urN linux-2.5.2-pre11/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- linux-2.5.2-pre11/drivers/sbus/char/aurora.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/sbus/char/aurora.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/*	$Id: aurora.c,v 1.18 2001/10/26 17:59:31 davem Exp $
+/*	$Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $
  *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *	Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
@@ -1427,7 +1427,7 @@
 	printk("aurora_open: start\n");
 #endif
 	
-	board = AURORA_BOARD(MINOR(tty->device));
+	board = AURORA_BOARD(minor(tty->device));
 	if (board > AURORA_NBOARD ||
 	    !(aurora_board[board].flags & AURORA_BOARD_PRESENT)) {
 #ifdef AURORA_DEBUG
@@ -1438,7 +1438,7 @@
 	}
 	
 	bp = &aurora_board[board];
-	port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(MINOR(tty->device));
+	port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(minor(tty->device));
 	if (aurora_paranoia_check(port, tty->device, "aurora_open")) {
 #ifdef AURORA_DEBUG
 		printk("aurora_open: error paranoia check\n");
diff -urN linux-2.5.2-pre11/drivers/sbus/char/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c
--- linux-2.5.2-pre11/drivers/sbus/char/cpwatchdog.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/cpwatchdog.c	Mon Jan 14 18:28:30 2002
@@ -297,7 +297,7 @@
 
 static int wd_open(struct inode *inode, struct file *f)
 {
-	switch(MINOR(inode->i_rdev))
+	switch(minor(inode->i_rdev))
 	{
 		case WD0_MINOR:
 			f->private_data = &wd_dev.watchdog[WD0_ID];
diff -urN linux-2.5.2-pre11/drivers/sbus/char/display7seg.c linux/drivers/sbus/char/display7seg.c
--- linux-2.5.2-pre11/drivers/sbus/char/display7seg.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/display7seg.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: display7seg.c,v 1.5 2001/10/08 22:19:51 davem Exp $
+/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
  *
  * display7seg - Driver implementation for the 7-segment display
  * present on Sun Microsystems CP1400 and CP1500
@@ -89,7 +89,7 @@
 
 static int d7s_open(struct inode *inode, struct file *f)
 {
-	if (D7S_MINOR != MINOR(inode->i_rdev))
+	if (D7S_MINOR != minor(inode->i_rdev))
 		return -ENODEV;
 
 	MOD_INC_USE_COUNT;
@@ -98,7 +98,7 @@
 
 static int d7s_release(struct inode *inode, struct file *f)
 {
-	if (D7S_MINOR != MINOR(inode->i_rdev))
+	if (D7S_MINOR != minor(inode->i_rdev))
 		return -ENODEV;
 	
 	MOD_DEC_USE_COUNT;
@@ -125,7 +125,7 @@
 	__u8 regs = readb(d7s_regs);
 	__u8 ireg = 0;
 
-	if (D7S_MINOR != MINOR(inode->i_rdev))
+	if (D7S_MINOR != minor(inode->i_rdev))
 		return -ENODEV;
 
 	switch (cmd) {
diff -urN linux-2.5.2-pre11/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- linux-2.5.2-pre11/drivers/sbus/char/sab82532.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/sbus/char/sab82532.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.65 2001/10/13 08:27:50 davem Exp $
+/* $Id: sab82532.c,v 1.66 2002/01/08 16:00:16 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -1913,7 +1913,7 @@
 	printk("sab82532_open: count = %d\n", info->count);
 #endif
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 
@@ -2200,7 +2200,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.65 $";
+	char *revision = "$Revision: 1.66 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2540,7 +2540,7 @@
 static kdev_t
 sab82532_console_device(struct console *con)
 {
-	return MKDEV(TTY_MAJOR, 64 + con->index);
+	return mk_kdev(TTY_MAJOR, 64 + con->index);
 }
 
 static int
diff -urN linux-2.5.2-pre11/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- linux-2.5.2-pre11/drivers/sbus/char/su.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/sbus/char/su.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.54 2001/11/07 14:52:30 davem Exp $
+/* $Id: su.c,v 1.55 2002/01/08 16:00:16 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2061,7 +2061,7 @@
 	int 			retval, line;
 	unsigned long		page;
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 	info = su_table + line;
@@ -2252,7 +2252,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.54 $";
+	char *revision = "$Revision: 1.55 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2857,7 +2857,7 @@
 static kdev_t
 serial_console_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, 64 + c->index);
+	return mk_kdev(TTY_MAJOR, 64 + c->index);
 }
 
 /*
diff -urN linux-2.5.2-pre11/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- linux-2.5.2-pre11/drivers/sbus/char/sunserial.c	Thu Apr 19 08:38:49 2001
+++ linux/drivers/sbus/char/sunserial.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.79 2001/04/18 21:06:17 davem Exp $
+/* $Id: sunserial.c,v 1.81 2002/01/05 01:13:43 davem Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -urN linux-2.5.2-pre11/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- linux-2.5.2-pre11/drivers/sbus/char/zs.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/sbus/char/zs.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.68 2001/10/25 18:48:03 davem Exp $
+/* $Id: zs.c,v 1.70 2002/01/08 16:00:16 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -224,7 +224,7 @@
 static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct sun_serial *info,
-					dev_t device, const char *routine)
+					kdev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
 	static const char *badmagic =
@@ -233,11 +233,11 @@
 		"Warning: null sun_serial for (%d, %d) in %s\n";
 
 	if (!info) {
-		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		printk(badinfo, major(device), minor(device), routine);
 		return 1;
 	}
 	if (info->magic != SERIAL_MAGIC) {
-		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		printk(badmagic, major(device), minor(device), routine);
 		return 1;
 	}
 #endif
@@ -486,10 +486,19 @@
 static void receive_chars(struct sun_serial *info, struct pt_regs *regs)
 {
 	struct tty_struct *tty = info->tty;
-	unsigned char ch, stat;
-	int do_queue_task = 1;
+	int do_queue_task = 0;
+
+	while (1) {
+		unsigned char ch, r1;
+
+		r1 = read_zsreg(info->zs_channel, R1);
+		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+			sbus_writeb(ERR_RES, &info->zs_channel->control);
+			ZSDELAY();
+			ZS_WSYNC(info->zs_channel);
+			ZSLOG(REGCTRL, ERR_RES, 1);
+		}
 
-	do {
 		ch = sbus_readb(&info->zs_channel->data);
 		ZSLOG(REGDATA, ch, 0);
 		ch &= info->parity_mask;
@@ -498,17 +507,17 @@
 		/* If this is the console keyboard, we need to handle
 		 * L1-A's here.
 		 */
-		if(info->cons_keyb) {
-			if(ch == SUNKBD_RESET) {
+		if (info->cons_keyb) {
+			if (ch == SUNKBD_RESET) {
 				l1a_state.kbd_id = 1;
 				l1a_state.l1_down = 0;
-			} else if(l1a_state.kbd_id) {
+			} else if (l1a_state.kbd_id) {
 				l1a_state.kbd_id = 0;
-			} else if(ch == SUNKBD_L1) {
+			} else if (ch == SUNKBD_L1) {
 				l1a_state.l1_down = 1;
-			} else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+			} else if (ch == (SUNKBD_L1|SUNKBD_UP)) {
 				l1a_state.l1_down = 0;
-			} else if(ch == SUNKBD_A && l1a_state.l1_down) {
+			} else if (ch == SUNKBD_A && l1a_state.l1_down) {
 				/* whee... */
 				batten_down_hatches();
 				/* Continue execution... */
@@ -517,16 +526,14 @@
 				return;
 			}
 			sunkbd_inchar(ch, regs);
-			do_queue_task = 0;
 			goto next_char;
 		}
-		if(info->cons_mouse) {
+		if (info->cons_mouse) {
 			sun_mouse_inbyte(ch, 0);
-			do_queue_task = 0;
 			goto next_char;
 		}
-		if(info->is_cons) {
-			if(ch == 0) {
+		if (info->is_cons) {
+			if (ch == 0) {
 				/* whee, break received */
 				batten_down_hatches();
 				/* Continue execution... */
@@ -538,32 +545,42 @@
 		 * documentation for remote target debugging and
 		 * arch/sparc/kernel/sparc-stub.c to see how all this works.
 		 */
-		if((info->kgdb_channel) && (ch =='\003')) {
+		if (info->kgdb_channel && (ch =='\003')) {
 			breakpoint();
 			return;
 		}
 #endif
-		if(!tty)
+		if (!tty)
 			return;
 
+		do_queue_task++;
+
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			break;
 
 		tty->flip.count++;
-		*tty->flip.flag_buf_ptr++ = 0;
+		if (r1 & PAR_ERR)
+			*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+		else if (r1 & Rx_OVR)
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+		else if (r1 & CRC_ERR)
+			*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+		else
+			*tty->flip.flag_buf_ptr++ = 0;
 		*tty->flip.char_buf_ptr++ = ch;
 
 	next_char:
-		/* Check if we have another character... */
-		stat = sbus_readb(&info->zs_channel->control);
-		ZSDELAY();
-		ZSLOG(REGCTRL, stat, 0);
-		if (!(stat & Rx_CH_AV))
-			break;
+		{
+			unsigned char stat;
 
-		/* ... and see if it is clean. */
-		stat = read_zsreg(info->zs_channel, R1);
-	} while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR)));
+			/* Check if we have another character... */
+			stat = sbus_readb(&info->zs_channel->control);
+			ZSDELAY();
+			ZSLOG(REGCTRL, stat, 0);
+			if (!(stat & Rx_CH_AV))
+				break;
+		}
+	}
 
 	if (do_queue_task != 0)
 		queue_task(&tty->flip.tqueue, &tq_timer);
@@ -580,7 +597,7 @@
 		return;
 	}
 
-	if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
+	if ((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
 		/* That's peculiar... */
 		sbus_writeb(RES_Tx_P, &info->zs_channel->control);
 		ZSDELAY();
@@ -597,7 +614,7 @@
 	if (info->xmit_cnt < WAKEUP_CHARS)
 		zs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
-	if(info->xmit_cnt <= 0) {
+	if (info->xmit_cnt <= 0) {
 		sbus_writeb(RES_Tx_P, &info->zs_channel->control);
 		ZSDELAY();
 		ZS_WSYNC(info->zs_channel);
@@ -619,14 +636,14 @@
 	ZS_WSYNC(info->zs_channel);
 	ZSLOG(REGCTRL, RES_EXT_INT, 1);
 #if 0
-	if(status & DCD) {
-		if((info->tty->termios->c_cflag & CRTSCTS) &&
-		   ((info->curregs[3] & AUTO_ENAB)==0)) {
+	if (status & DCD) {
+		if ((info->tty->termios->c_cflag & CRTSCTS) &&
+		    ((info->curregs[3] & AUTO_ENAB)==0)) {
 			info->curregs[3] |= AUTO_ENAB;
 			write_zsreg(info->zs_channel, 3, info->curregs[3]);
 		}
 	} else {
-		if((info->curregs[3] & AUTO_ENAB)) {
+		if ((info->curregs[3] & AUTO_ENAB)) {
 			info->curregs[3] &= ~AUTO_ENAB;
 			write_zsreg(info->zs_channel, 3, info->curregs[3]);
 		}
@@ -636,7 +653,7 @@
 	 * 'break asserted' status change interrupt, call
 	 * the boot prom.
 	 */
-	if(status & BRK_ABRT) {
+	if (status & BRK_ABRT) {
 		if (info->break_abort)
 			batten_down_hatches();
 		if (info->cons_mouse)
@@ -649,110 +666,49 @@
 	return;
 }
 
-static void special_receive(struct sun_serial *info)
-{
-	struct tty_struct *tty = info->tty;
-	unsigned char ch, stat;
-
-	stat = read_zsreg(info->zs_channel, R1);
-	if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-		ch = sbus_readb(&info->zs_channel->data);
-		ZSDELAY();
-		ZSLOG(REGDATA, ch, 0);
-	}
-
-	if (!tty)
-		goto clear;
-
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-		goto done;
-
-	tty->flip.count++;
-	if(stat & PAR_ERR)
-		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
-	else if(stat & Rx_OVR)
-		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-	else if(stat & CRC_ERR)
-		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
-
-done:
-	queue_task(&tty->flip.tqueue, &tq_timer);
-clear:
-	sbus_writeb(ERR_RES, &info->zs_channel->control);
-	ZSDELAY();
-	ZS_WSYNC(info->zs_channel);
-	ZSLOG(REGCTRL, ERR_RES, 1);
-}
-
-
 /*
  * This is the serial driver's generic interrupt routine
  */
 void zs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct sun_serial *info;
-	unsigned char zs_intreg;
 	int i;
 
 	info = (struct sun_serial *)dev_id;
 	ZSLOG(REGIRQ, 0, 0);
 	for (i = 0; i < NUM_SERIAL; i++) {
-		zs_intreg = read_zsreg(info->zs_next->zs_channel, 2);
-		zs_intreg &= STATUS_MASK;
-
-		/* NOTE: The read register 2, which holds the irq status,
-		 *       does so for both channels on each chip.  Although
-		 *       the status value itself must be read from the B
-		 *       channel and is only valid when read from channel B.
-		 *       When read from channel A, read register 2 contains
-		 *       the value written to write register 2.
-		 */
+		unsigned char r3 = read_zsreg(info->zs_channel, 3);
 
 		/* Channel A -- /dev/ttya or /dev/kbd, could be the console */
-		if (zs_intreg == CHA_Rx_AVAIL) {
-			receive_chars(info, regs);
-			return;
-		}
-		if(zs_intreg == CHA_Tx_EMPTY) {
-			transmit_chars(info);
-			return;
-		}
-		if (zs_intreg == CHA_EXT_STAT) {
-			status_handle(info);
-			return;
-		}
-		if (zs_intreg == CHA_SPECIAL) {
-			special_receive(info);
-			return;
+		if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
+			sbus_writeb(RES_H_IUS, &info->zs_channel->control);
+			ZSDELAY();
+			ZS_WSYNC(info->zs_channel);
+			ZSLOG(REGCTRL, RES_H_IUS, 1);
+			if (r3 & CHARxIP)
+				receive_chars(info, regs);
+			if (r3 & CHAEXT)
+				status_handle(info);
+			if (r3 & CHATxIP)
+				transmit_chars(info);
 		}
 
 		/* Channel B -- /dev/ttyb or /dev/mouse, could be the console */
-		if(zs_intreg == CHB_Rx_AVAIL) {
-			receive_chars(info->zs_next, regs);
-			return;
-		}
-		if(zs_intreg == CHB_Tx_EMPTY) {
-			transmit_chars(info->zs_next);
-			return;
+		info = info->zs_next;
+		if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
+			sbus_writeb(RES_H_IUS, &info->zs_channel->control);
+			ZSDELAY();
+			ZS_WSYNC(info->zs_channel);
+			ZSLOG(REGCTRL, RES_H_IUS, 1);
+			if (r3 & CHBRxIP)
+				receive_chars(info, regs);
+			if (r3 & CHBEXT)
+				status_handle(info);
+			if (r3 & CHBTxIP)
+				transmit_chars(info);
 		}
-		if (zs_intreg == CHB_EXT_STAT) {
-			status_handle(info->zs_next);
-			return;
-		}
-
-		/* NOTE: The default value for the IRQ status in read register
-		 *       2 in channel B is CHB_SPECIAL, so we need to look at
-		 *       read register 3 in channel A to check if this is a
-		 *       real interrupt, or just the default value.
-		 *       Yes... broken hardware...
-		 */
 
-		zs_intreg = read_zsreg(info->zs_channel, 3);
-		if (zs_intreg & CHBRxIP) {
-			special_receive(info->zs_next);
-			return;
-		}
-		info = info->zs_next->zs_next;
+		info = info->zs_next;
 	}
 }
 
@@ -1847,7 +1803,7 @@
 	struct sun_serial *info;
 	int retval, line;
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 
 	/* The zilog lines for the mouse/keyboard must be
 	 * opened using their respective drivers.
@@ -1931,7 +1887,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.68 $";
+	char *revision = "$Revision: 1.70 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2467,8 +2423,7 @@
 	/* Grab IRQ line before poking the chips so we do
 	 * not lose any interrupts.
 	 */
-	if (request_irq(zilog_irq, zs_interrupt,
-			(SA_INTERRUPT | SA_STATIC_ALLOC),
+	if (request_irq(zilog_irq, zs_interrupt, SA_SHIRQ,
 			"Zilog8530", zs_chain)) {
 		prom_printf("Unable to attach zs intr\n");
 		prom_halt();
@@ -2761,7 +2716,7 @@
 
 static kdev_t zs_console_device(struct console *con)
 {
-	return MKDEV(TTY_MAJOR, 64 + con->index);
+	return mk_kdev(TTY_MAJOR, 64 + con->index);
 }
 
 static int __init zs_console_setup(struct console *con, char *options)
diff -urN linux-2.5.2-pre11/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- linux-2.5.2-pre11/drivers/sbus/sbus.c	Sun Mar 25 18:14:21 2001
+++ linux/drivers/sbus/sbus.c	Mon Jan 14 18:28:30 2002
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.95 2001/03/15 02:11:10 davem Exp $
+/* $Id: sbus.c,v 1.98 2002/01/05 01:13:43 davem Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -231,6 +231,7 @@
 				return;
 			}
 			regs[regnum].which_io = ranges[rngnum].ot_parent_space;
+			regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
 			regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
 		}
 	}
diff -urN linux-2.5.2-pre11/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- linux-2.5.2-pre11/drivers/scsi/advansys.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/advansys.c	Mon Jan 14 18:28:30 2002
@@ -8392,8 +8392,8 @@
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" unchecked_isa_dma %d, use_clustering %d, loaded_as_module %d\n",
-        shp->unchecked_isa_dma, shp->use_clustering, shp->loaded_as_module);
+" unchecked_isa_dma %d, use_clustering %d\n",
+        shp->unchecked_isa_dma, shp->use_clustering);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
@@ -9411,9 +9411,8 @@
         s->dma_channel, s->this_id, s->can_queue);
 
     printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
-        s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
-        s->loaded_as_module);
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+        s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
 
     if (ASC_NARROW_BOARD(boardp)) {
         asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
diff -urN linux-2.5.2-pre11/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- linux-2.5.2-pre11/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Jan 14 18:28:30 2002
@@ -130,6 +130,7 @@
 
 #include <linux/mm.h>		/* For fetching system memory size */
 #include <linux/blk.h>
+#include <scsi/scsicam.h>
 
 /*
  * To generate the correct addresses for the controller to issue
diff -urN linux-2.5.2-pre11/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- linux-2.5.2-pre11/drivers/scsi/aic7xxx/aic7xxx_osm.h	Tue Nov 27 09:23:27 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon Jan 14 18:28:30 2002
@@ -713,20 +713,20 @@
 static __inline void
 ahc_lockinit(struct ahc_softc *ahc)
 {
-	spin_lock_init(&ahc->platform_data->host->host_lock);
+	spin_lock_init(ahc->platform_data->host->host_lock);
 }
 
 static __inline void
 ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
 {
 	*flags = 0;
-	spin_lock_irqsave(&ahc->platform_data->host->host_lock, *flags);
+	spin_lock_irqsave(ahc->platform_data->host->host_lock, *flags);
 }
 
 static __inline void
 ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
 {
-	spin_unlock_irqrestore(&ahc->platform_data->host->host_lock, *flags);
+	spin_unlock_irqrestore(ahc->platform_data->host->host_lock, *flags);
 }
 
 static __inline void
@@ -741,7 +741,7 @@
 	struct Scsi_Host *host = ahc->platform_data->host;
 
 	*flags = 0;
-	spin_lock_irqsave(&host->host_lock, *flags);
+	spin_lock_irqsave(host->host_lock, *flags);
 }
 
 static __inline void
@@ -749,7 +749,7 @@
 {
 	struct Scsi_Host *host = ahc->platform_data->host;
 
-	spin_unlock_irqrestore(&host->host_lock, *flags);
+	spin_unlock_irqrestore(host->host_lock, *flags);
 }
 
 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
diff -urN linux-2.5.2-pre11/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- linux-2.5.2-pre11/drivers/scsi/constants.c	Thu Oct 25 13:53:50 2001
+++ linux/drivers/scsi/constants.c	Mon Jan 14 18:28:30 2002
@@ -5,7 +5,6 @@
  *
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/config.h>
diff -urN linux-2.5.2-pre11/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- linux-2.5.2-pre11/drivers/scsi/hosts.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/hosts.c	Mon Jan 14 18:28:30 2002
@@ -24,7 +24,6 @@
  *  hosts currently present in the system.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/blk.h>
 #include <linux/kernel.h>
@@ -55,13 +54,6 @@
  *  number it is during detection.
  */
 
-/* This is a placeholder for controllers that are not configured into
- * the system - we do this to ensure that the controller numbering is
- * always consistent, no matter how the kernel is configured. */
-
-#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
-			   NULL, NULL, 0, 0, 0, 0, 0, 0}
-
 /*
  *  When figure is run, we don't want to link to any object code.  Since
  *  the macro for each host will contain function pointers, we cannot
@@ -157,17 +149,14 @@
 	    flag_new = 0;
 	    retval->host_no = shn->host_no;
 	    shn->host_registered = 1;
-	    shn->loaded_as_module = 1;
 	    break;
 	}
     }
-    spin_lock_init(&retval->host_lock);
+    spin_lock_init(&retval->default_lock);
+    scsi_assign_lock(retval, &retval->default_lock);
     atomic_set(&retval->host_active,0);
     retval->host_busy = 0;
     retval->host_failed = 0;
-    if(j > 0xffff) panic("Too many extra bytes requested\n");
-    retval->extra_bytes = j;
-    retval->loaded_as_module = 1;
     if (flag_new) {
 	shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
         if (!shn) {
@@ -181,7 +170,6 @@
 	shn->name[hname_len] = 0;
 	shn->host_no = max_scsi_hosts++;
 	shn->host_registered = 1;
-	shn->loaded_as_module = 1;
 	shn->next = NULL;
 	if (scsi_host_no_list) {
 	    for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
diff -urN linux-2.5.2-pre11/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- linux-2.5.2-pre11/drivers/scsi/hosts.h	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/hosts.h	Mon Jan 14 18:28:30 2002
@@ -312,7 +312,8 @@
     struct Scsi_Host      * next;
     Scsi_Device           * host_queue;
 
-    spinlock_t		  host_lock;
+    spinlock_t		  default_lock;
+    spinlock_t		  *host_lock;
 
     struct task_struct    * ehandler;  /* Error recovery thread. */
     struct semaphore      * eh_wait;   /* The error recovery thread waits on
@@ -329,7 +330,6 @@
     volatile unsigned short host_failed; /* commands that failed. */
     
 /* public: */
-    unsigned short extra_bytes;
     unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
     int resetting; /* if set, it means that last_reset is a valid value */
     unsigned long last_reset;
@@ -386,10 +386,6 @@
     unsigned unchecked_isa_dma:1;
     unsigned use_clustering:1;
     unsigned highmem_io:1;
-    /*
-     * True if this host was loaded as a loadable module
-     */
-    unsigned loaded_as_module:1;
 
     /*
      * Host has rejected a command because it was busy.
@@ -451,7 +447,6 @@
     char * name;
     unsigned short host_no;
     unsigned short host_registered;
-    unsigned loaded_as_module;
     } Scsi_Host_Name;
 	
 extern Scsi_Host_Name * scsi_host_no_list;
@@ -471,9 +466,13 @@
 unsigned int scsi_init(void);
 extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
 extern void scsi_unregister(struct Scsi_Host * i);
-
 extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt);
 extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt);
+
+static inline void scsi_assign_lock(struct Scsi_Host *host, spinlock_t *lock)
+{
+	host->host_lock = lock;
+}
 
 static inline void scsi_set_pci_device(struct Scsi_Host *SHpnt,
                                        struct pci_dev *pdev)
diff -urN linux-2.5.2-pre11/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- linux-2.5.2-pre11/drivers/scsi/ide-scsi.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/ide-scsi.c	Mon Jan 14 18:28:30 2002
@@ -292,9 +292,9 @@
 		}
 	}
 	host = pc->scsi_cmd->host;
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	pc->done(pc->scsi_cmd);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 	idescsi_free_bio (rq->bio);
 	kfree(pc); kfree(rq);
 	scsi->pc = NULL;
@@ -805,9 +805,9 @@
 	rq->special = (char *) pc;
 	rq->bio = idescsi_dma_bio (drive, pc);
 	rq->flags = REQ_SPECIAL;
-	spin_unlock(&cmd->host->host_lock);
+	spin_unlock_irq(cmd->host->host_lock);
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
-	spin_lock_irq(&cmd->host->host_lock);
+	spin_lock_irq(cmd->host->host_lock);
 	return 0;
 abort:
 	if (pc) kfree (pc);
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux-2.5.2-pre11/drivers/scsi/scsi.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsi.c	Mon Jan 14 18:28:30 2002
@@ -75,8 +75,6 @@
 #include <linux/kmod.h>
 #endif
 
-#undef USE_STATIC_SCSI_MEMORY
-
 struct proc_dir_entry *proc_scsi;
 
 #ifdef CONFIG_PROC_FS
@@ -195,16 +193,23 @@
 {
 	request_queue_t *q = &SDpnt->request_queue;
 
-	blk_init_queue(q, scsi_request_fn, &SHpnt->host_lock);
+	/*
+	 * tell block layer about assigned host_lock for this host
+	 */
+	blk_init_queue(q, scsi_request_fn, SHpnt->host_lock);
+
 	q->queuedata = (void *) SDpnt;
 
 	/* Hardware imposed limit. */
 	blk_queue_max_hw_segments(q, SHpnt->sg_tablesize);
-	blk_queue_max_sectors(q, SHpnt->max_sectors);
 
-	/* scsi_alloc_sgtable max */
+	/*
+	 * scsi_alloc_sgtable max
+	 */
 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 
+	blk_queue_max_sectors(q, SHpnt->max_sectors);
+
 	if (!SHpnt->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 }
@@ -647,7 +652,7 @@
 
 	host = SCpnt->host;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	/* Assign a unique nonzero serial_number. */
 	if (++serial_number == 0)
@@ -698,9 +703,9 @@
 		 * length exceeds what the host adapter can handle.
 		 */
 		if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) {
-			spin_lock_irqsave(&host->host_lock, flags);
+			spin_lock_irqsave(host->host_lock, flags);
 			rtn = host->hostt->queuecommand(SCpnt, scsi_done);
-			spin_unlock_irqrestore(&host->host_lock, flags);
+			spin_unlock_irqrestore(host->host_lock, flags);
 			if (rtn != 0) {
 				scsi_delete_timer(SCpnt);
 				scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
@@ -711,20 +716,20 @@
 			SCSI_LOG_MLQUEUE(3,
 				printk("queuecommand : command too long.\n"));
 			SCpnt->result = (DID_ABORT << 16);
-			spin_lock_irqsave(&host->host_lock, flags);
+			spin_lock_irqsave(host->host_lock, flags);
 			scsi_done(SCpnt);
-			spin_unlock_irqrestore(&host->host_lock, flags);
+			spin_unlock_irqrestore(host->host_lock, flags);
 			rtn = 1;
 		}
 	} else {
 		int temp;
 
 		SCSI_LOG_MLQUEUE(3, printk("command() :  routine at %p\n", host->hostt->command));
-                spin_lock_irqsave(&host->host_lock, flags);
+                spin_lock_irqsave(host->host_lock, flags);
 		temp = host->hostt->command(SCpnt);
 		SCpnt->result = temp;
 #ifdef DEBUG_DELAY
-                spin_unlock_irqrestore(&host->host_lock, flags);
+                spin_unlock_irqrestore(host->host_lock, flags);
 		clock = jiffies + 4 * HZ;
 		while (time_before(jiffies, clock)) {
 			barrier();
@@ -732,10 +737,10 @@
 		}
 		printk("done(host = %d, result = %04x) : routine at %p\n",
 		       host->host_no, temp, host->hostt->command);
-                spin_lock_irqsave(&host->host_lock, flags);
+                spin_lock_irqsave(host->host_lock, flags);
 #endif
 		scsi_done(SCpnt);
-                spin_unlock_irqrestore(&host->host_lock, flags);
+                spin_unlock_irqrestore(host->host_lock, flags);
 	}
 	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
 	return rtn;
@@ -805,7 +810,7 @@
 	Scsi_Device * SDpnt = SRpnt->sr_device;
 	struct Scsi_Host *host = SDpnt->host;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	SCSI_LOG_MLQUEUE(4,
 			 {
@@ -902,7 +907,7 @@
 {
 	struct Scsi_Host *host = SCpnt->host;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	SCpnt->owner = SCSI_OWNER_MIDLEVEL;
 	SRpnt->sr_command = SCpnt;
@@ -992,7 +997,7 @@
 {
 	struct Scsi_Host *host = SCpnt->host;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	SCpnt->pid = scsi_pid++;
 	SCpnt->owner = SCSI_OWNER_MIDLEVEL;
@@ -1346,7 +1351,7 @@
 	host = SCpnt->host;
 	device = SCpnt->device;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
         /*
          * We need to protect the decrement, as otherwise a race condition
@@ -1355,10 +1360,10 @@
          * one execution context, but the device and host structures are
          * shared.
          */
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	host->host_busy--;	/* Indicate that we are free */
 	device->device_busy--;	/* Decrement device usage counter. */
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 
         /*
          * Clear the flags which say that the device/host is no longer
@@ -1512,7 +1517,6 @@
 	    shn->name[len] = 0;
 	    shn->host_no = n;
 	    shn->host_registered = 0;
-	    shn->loaded_as_module = 1; /* numbers shouldn't be freed in any case */
 	    shn->next = NULL;
 	    if (scsi_host_no_list) {
 		for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next)
@@ -1968,12 +1972,6 @@
 			}
 		}
 	}
-#if defined(USE_STATIC_SCSI_MEMORY)
-	printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-	       (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-	       (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
 
 	if (out_of_space) {
 		scsi_unregister_host(tpnt);	/* easiest way to clean up?? */
@@ -2163,13 +2161,6 @@
 		printk(KERN_INFO "scsi : %d host%s left.\n", next_scsi_host,
 		       (next_scsi_host == 1) ? "" : "s");
 
-#if defined(USE_STATIC_SCSI_MEMORY)
-	printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-	       (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-	       (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
-
 	/*
 	 * Remove it from the linked list and /proc if all
 	 * hosts were successfully removed (ie preset == 0)
@@ -2403,35 +2394,6 @@
 				       SCpnt->cmnd[0],
 				       SCpnt->sense_buffer[2],
 				       SCpnt->result);
-			}
-		}
-	}
-
-	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
-			/* Now dump the request lists for each block device */
-			printk(KERN_INFO "Dump of pending block device requests\n");
-			for (i = 0; i < MAX_BLKDEV; i++) {
-				struct list_head * queue_head;
-
-				queue_head = &blk_dev[i].request_queue.queue_head;
-				if (!list_empty(queue_head)) {
-					struct request *req;
-					struct list_head * entry;
-
-					printk(KERN_INFO "%d: ", i);
-					entry = queue_head->next;
-					do {
-						req = blkdev_entry_to_request(entry);
-						printk("(%s %d %ld %ld %ld) ",
-						   kdevname(req->rq_dev),
-						       req->cmd,
-						       req->sector,
-						       req->nr_sectors,
-						req->current_nr_sectors);
-					} while ((entry = entry->next) != queue_head);
-					printk("\n");
-				}
 			}
 		}
 	}
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_error.c	Wed Dec 12 13:41:03 2001
+++ linux/drivers/scsi/scsi_error.c	Mon Jan 14 18:28:30 2002
@@ -8,7 +8,6 @@
  *
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -583,7 +582,7 @@
 	unsigned long flags;
 	struct Scsi_Host *host = SCpnt->host;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 retry:
 	/*
@@ -605,9 +604,9 @@
 		SCpnt->host->eh_action = &sem;
 		SCpnt->request.rq_status = RQ_SCSI_BUSY;
 
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		host->hostt->queuecommand(SCpnt, scsi_eh_done);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 
 		down(&sem);
 
@@ -630,10 +629,10 @@
 			 * abort a timed out command or not.  Not sure how
 			 * we should treat them differently anyways.
 			 */
-			spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(SCpnt->host->host_lock, flags);
 			if (SCpnt->host->hostt->eh_abort_handler)
 				SCpnt->host->hostt->eh_abort_handler(SCpnt);
-			spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			
 			SCpnt->request.rq_status = RQ_SCSI_DONE;
 			SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
@@ -650,9 +649,9 @@
 		 * timeout protection here, since we would end up waiting in
 		 * the actual low level driver, we don't know how to wake it up.
 		 */
-		spin_lock_irqsave(&host->host_lock, flags);
+		spin_lock_irqsave(host->host_lock, flags);
 		temp = host->hostt->command(SCpnt);
-		spin_unlock_irqrestore(&host->host_lock, flags);
+		spin_unlock_irqrestore(host->host_lock, flags);
 
 		SCpnt->result = temp;
 		/* Fall through to code below to examine status. */
@@ -772,9 +771,9 @@
 
 	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 	return rtn;
 }
 
@@ -804,9 +803,9 @@
 	}
 	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 
 	if (rtn == SUCCESS)
 		SCpnt->eh_state = SUCCESS;
@@ -837,9 +836,9 @@
 		return FAILED;
 	}
 
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 
 	if (rtn == SUCCESS)
 		SCpnt->eh_state = SUCCESS;
@@ -883,9 +882,9 @@
 	if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
 		return FAILED;
 	}
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 
 	if (rtn == SUCCESS)
 		SCpnt->eh_state = SUCCESS;
@@ -1226,7 +1225,7 @@
 	Scsi_Device *SDpnt;
 	unsigned long flags;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	/*
 	 * Next free up anything directly waiting upon the host.  This will be
@@ -1243,7 +1242,7 @@
 	 * now that error recovery is done, we will need to ensure that these
 	 * requests are started.
 	 */
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
 		request_queue_t *q = &SDpnt->request_queue;
 
@@ -1256,7 +1255,7 @@
 
 		q->request_fn(q);
 	}
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 /*
@@ -1303,7 +1302,7 @@
 	Scsi_Cmnd *SCdone;
 	int timed_out;
 
-	ASSERT_LOCK(&host->host_lock, 0);
+	ASSERT_LOCK(host->host_lock, 0);
 
 	SCdone = NULL;
 
@@ -1844,11 +1843,7 @@
          * If the HA was compiled into the kernel, then we don't listen
          * to any signals.
          */
-        if( host->loaded_as_module ) {
 	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
-	} else {
-	siginitsetinv(&current->blocked, 0);
-        }
 
 	lock_kernel();
 
@@ -1894,10 +1889,8 @@
 		 * semaphores isn't unreasonable.
 		 */
 		down_interruptible(&sem);
-		if( host->loaded_as_module ) {
-			if (signal_pending(current))
-				break;
-                }
+		if (signal_pending(current))
+			break;
 
 		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));
 
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_ioctl.c	Sun Dec 16 12:20:21 2001
+++ linux/drivers/scsi/scsi_ioctl.c	Mon Jan 14 18:28:30 2002
@@ -4,7 +4,6 @@
  * - get rid of some verify_areas and use __copy*user and __get/put_user
  *   for the ones that remain
  */
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <asm/io.h>
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_lib.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsi_lib.c	Mon Jan 14 18:28:30 2002
@@ -17,7 +17,6 @@
  * go through and retrofit queueing functions into all 30 some-odd drivers.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -365,7 +364,7 @@
 	 * If there are blocks left over at the end, set up the command
 	 * to queue the remainder of them.
 	 */
-	if (end_that_request_first(req, 1, sectors)) {
+	if (end_that_request_first(req, uptodate, sectors)) {
 		if (!requeue)
 			return SCpnt;
 
@@ -444,7 +443,7 @@
 {
 	struct request *req = &SCpnt->request;
 
-	ASSERT_LOCK(&SCpnt->host->host_lock, 0);
+	ASSERT_LOCK(SCpnt->host->host_lock, 0);
 
 	/*
 	 * Free up any indirection buffers we allocated for DMA purposes. 
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_merge.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsi_merge.c	Mon Jan 14 18:28:30 2002
@@ -15,7 +15,6 @@
  * be handled all at once by a host adapter.
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_proc.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/scsi/scsi_proc.c	Mon Jan 14 18:28:30 2002
@@ -17,7 +17,6 @@
  */
 
 #include <linux/config.h>	/* for CONFIG_PROC_FS */
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/string.h>
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_queue.c linux/drivers/scsi/scsi_queue.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_queue.c	Wed Dec 12 13:41:09 2001
+++ linux/drivers/scsi/scsi_queue.c	Mon Jan 14 18:28:30 2002
@@ -10,7 +10,6 @@
  *  we attempt to remove commands from the queue and retry them.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -137,10 +136,10 @@
 	 * Decrement the counters, since these commands are no longer
 	 * active on the host/device.
 	 */
-	spin_lock_irqsave(&cmd->host->host_lock, flags);
+	spin_lock_irqsave(cmd->host->host_lock, flags);
 	cmd->host->host_busy--;
 	cmd->device->device_busy--;
-	spin_unlock_irqrestore(&cmd->host->host_lock, flags);
+	spin_unlock_irqrestore(cmd->host->host_lock, flags);
 
 	/*
 	 * Insert this command at the head of the queue for it's device.
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_scan.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsi_scan.c	Mon Jan 14 18:28:30 2002
@@ -8,7 +8,6 @@
  *  clearer.
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -urN linux-2.5.2-pre11/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- linux-2.5.2-pre11/drivers/scsi/scsi_syms.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsi_syms.c	Mon Jan 14 18:28:30 2002
@@ -2,7 +2,6 @@
  * We should not even be trying to compile this if we are not doing
  * a module.
  */
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 
diff -urN linux-2.5.2-pre11/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- linux-2.5.2-pre11/drivers/scsi/scsicam.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/scsi/scsicam.c	Mon Jan 14 18:28:30 2002
@@ -10,7 +10,6 @@
  * For more information, please consult the SCSI-CAM draft.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/fs.h>
diff -urN linux-2.5.2-pre11/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- linux-2.5.2-pre11/drivers/scsi/sym53c8xx.c	Sun Dec 16 12:20:21 2001
+++ linux/drivers/scsi/sym53c8xx.c	Mon Jan 14 18:28:30 2002
@@ -643,9 +643,9 @@
 #define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
 
 #define	NCR_LOCK_SCSI_DONE(host, flags) \
-		spin_lock_irqsave(&((host)->host_lock), flags)
+		spin_lock_irqsave(((host)->host_lock), flags)
 #define	NCR_UNLOCK_SCSI_DONE(host, flags) \
-		spin_unlock_irqrestore(&((host)->host_lock), flags)
+		spin_unlock_irqrestore(((host)->host_lock), flags)
 
 #else
 
diff -urN linux-2.5.2-pre11/drivers/scsi/sym53c8xx_2/sym_glue.c linux/drivers/scsi/sym53c8xx_2/sym_glue.c
--- linux-2.5.2-pre11/drivers/scsi/sym53c8xx_2/sym_glue.c	Sun Dec 16 12:20:21 2001
+++ linux/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon Jan 14 18:28:30 2002
@@ -138,11 +138,11 @@
 #define	SYM_LOCK_DRIVER(flags)    spin_lock_irqsave(&sym53c8xx_lock, flags)
 #define	SYM_UNLOCK_DRIVER(flags)  spin_unlock_irqrestore(&sym53c8xx_lock,flags)
 
-#define SYM_INIT_LOCK_HCB(np)		spin_lock_init(&np->s.host->host_lock);
+#define SYM_INIT_LOCK_HCB(np)		spin_lock_init((np)->s.host->host_lock);
 #define	SYM_LOCK_HCB(np, flags)		\
-			spin_lock_irqsave(&np->s.host->host_lock, flags)
+			spin_lock_irqsave((np)->s.host->host_lock, flags)
 #define	SYM_UNLOCK_HCB(np, flags)	\
-			spin_unlock_irqrestore(&np->s.host->host_lock, flags)
+			spin_unlock_irqrestore((np)->s.host->host_lock, flags)
 
 /*
  *  These simple macros limit expression involving 
diff -urN linux-2.5.2-pre11/drivers/sound/trident.c linux/drivers/sound/trident.c
--- linux-2.5.2-pre11/drivers/sound/trident.c	Tue Nov 13 09:19:41 2001
+++ linux/drivers/sound/trident.c	Mon Jan 14 18:28:30 2002
@@ -187,6 +187,7 @@
 #define TRIDENT_STATE_MAGIC	0x63657373 /* "cess" */
 
 #define TRIDENT_DMA_MASK	0x3fffffff /* DMA buffer mask for pci_alloc_consist */
+#define ALI_DMA_MASK		0xffffffff /* ALI Tridents lack the 30-bit limitation */
 
 #define NR_HW_CH		32
 
@@ -2555,7 +2556,7 @@
 static int trident_open(struct inode *inode, struct file *file)
 {
 	int i = 0;
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct trident_card *card = devs;
 	struct trident_state *state = NULL;
 	struct dmabuf *dmabuf = NULL;
@@ -3750,7 +3751,7 @@
 static int trident_open_mixdev(struct inode *inode, struct file *file)
 {
 	int i = 0;
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct trident_card *card = devs;
 
 	for (card = devs; card != NULL; card = card->next)
@@ -3948,13 +3949,20 @@
 	u16 temp;
 	struct pci_dev *pci_dev_m1533 = NULL;
 	int rc = -ENODEV;
+	u64 dma_mask;
 
 	if (pci_enable_device(pci_dev))
 		goto out;
 
-	if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) {
+	if (pci_dev->device == PCI_DEVICE_ID_ALI_5451)
+		dma_mask = ALI_DMA_MASK;
+	else
+		dma_mask = TRIDENT_DMA_MASK;
+	if (pci_set_dma_mask(pci_dev, dma_mask)) {
 		printk(KERN_ERR "trident: architecture does not support"
-		       " 30bit PCI busmaster DMA\n");
+		       " %s PCI busmaster DMA\n",
+		       pci_dev->device == PCI_DEVICE_ID_ALI_5451 ?
+		       "32-bit" : "30-bit");
 		goto out;
 	}
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
diff -urN linux-2.5.2-pre11/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.5.2-pre11/drivers/sound/ymfpci.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/sound/ymfpci.c	Mon Jan 14 18:28:30 2002
@@ -1,6 +1,8 @@
 /*
  *  Copyright 1999 Jaroslav Kysela <perex@suse.cz>
  *  Copyright 2000 Alan Cox <alan@redhat.com>
+ *  Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
+ *  Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
  *
  *  Yamaha YMF7xx driver.
  *
@@ -37,8 +39,16 @@
  *  - Remove prog_dmabuf from read/write, leave it in open.
  *  - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
  *    native synthesizer through a playback slot.
- *  - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
- *  - Make the thing big endian compatible. ALSA has it done.
+ *  - 2001/11/29 ac97_save_state
+ *    Talk to Kai to remove ac97_save_state before it's too late!
+ *  - Second AC97
+ *  - Restore S/PDIF - Toshibas have it.
+ *
+ * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
+ * unconventional. However, given how small our fragments can be,
+ * a little uncached access is perhaps better than endless flushing.
+ * On i386 and other I/O-coherent architectures pci_alloc_consistent
+ * is entirely harmless.
  */
 
 #include <linux/config.h>
@@ -155,7 +165,7 @@
 			schedule_timeout(1);
 		}
 	} while (end_time - (signed long)jiffies >= 0);
-	printk("ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
+	printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
 	    secondary, ymfpci_readw(codec, reg));
 	return -EBUSY;
 }
@@ -173,19 +183,19 @@
 
 static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
 {
-	ymfpci_t *codec = dev->private_data;
+	ymfpci_t *unit = dev->private_data;
+	int i;
 
-	if (ymfpci_codec_ready(codec, 0, 0))
+	if (ymfpci_codec_ready(unit, 0, 0))
 		return ~0;
-	ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
-	if (ymfpci_codec_ready(codec, 0, 0))
+	ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+	if (ymfpci_codec_ready(unit, 0, 0))
 		return ~0;
-	if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) {
-		int i;
+	if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
 		for (i = 0; i < 600; i++)
-			ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+			ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
 	}
-	return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+	return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
 }
 
 /*
@@ -279,18 +289,22 @@
 #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
 
-/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Allocate DMA buffer
+ */
+static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
 {
 	void *rawbuf = NULL;
+	dma_addr_t dma_addr;
 	int order;
-	struct page * map,  * mapend;
+	struct page *map, *mapend;
 
 	/* alloc as big a chunk as we can */
-	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
+		rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
+		if (rawbuf)
 			break;
-
+	}
 	if (!rawbuf)
 		return -ENOMEM;
 
@@ -301,6 +315,7 @@
 
 	dmabuf->ready  = dmabuf->mapped = 0;
 	dmabuf->rawbuf = rawbuf;
+	dmabuf->dma_addr = dma_addr;
 	dmabuf->buforder = order;
 
 	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
@@ -311,8 +326,10 @@
 	return 0;
 }
 
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf)
+/*
+ * Free DMA buffer
+ */
+static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
 {
 	struct page *map, *mapend;
 
@@ -321,7 +338,9 @@
 		mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
 		for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
 			clear_bit(PG_reserved, &map->flags);
-		free_pages((unsigned long)dmabuf->rawbuf,dmabuf->buforder);
+
+		pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
+		    dmabuf->rawbuf, dmabuf->dma_addr);
 	}
 	dmabuf->rawbuf = NULL;
 	dmabuf->mapped = dmabuf->ready = 0;
@@ -347,7 +366,7 @@
 
 	/* allocate DMA buffer if not allocated yet */
 	if (!dmabuf->rawbuf)
-		if ((ret = alloc_dmabuf(dmabuf)))
+		if ((ret = alloc_dmabuf(state->unit, dmabuf)))
 			return ret;
 
 	/*
@@ -404,7 +423,7 @@
 	dmabuf->ready = 1;
 
 #if 0
-	printk("prog_dmabuf: rate %d format 0x%x,"
+	printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
 	    " numfrag %d fragsize %d dmasize %d\n",
 	       state->format.rate, state->format.format, dmabuf->numfrag,
 	       dmabuf->fragsize, dmabuf->dmasize);
@@ -587,7 +606,8 @@
 	if (ypcm->running) {
 		YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
 		   voice->number, codec->active_bank, dmabuf->count,
-		   voice->bank[0].start, voice->bank[1].start);
+		   le32_to_cpu(voice->bank[0].start),
+		   le32_to_cpu(voice->bank[1].start));
 		silence = (ymf_pcm_format_width(state->format.format) == 16) ?
 		    0 : 0x80;
 		/* We need actual left-hand-side redzone size here. */
@@ -595,7 +615,7 @@
 		redzone <<= (state->format.shift + 1);
 		swptr = dmabuf->swptr;
 
-		pos = voice->bank[codec->active_bank].start;
+		pos = le32_to_cpu(voice->bank[codec->active_bank].start);
 		pos <<= state->format.shift;
 		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */
 			printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
@@ -615,7 +635,7 @@
 		dmabuf->hwptr = pos;
 
 		if (dmabuf->count == 0) {
-			printk("ymfpci%d: %d: strain: hwptr %d\n",
+			printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
 			    codec->dev_audio, voice->number, dmabuf->hwptr);
 			ymf_playback_trigger(codec, ypcm, 0);
 		}
@@ -633,7 +653,7 @@
 				/*
 				 * Lost interrupt or other screwage.
 				 */
-				printk("ymfpci%d: %d: lost: delta %d"
+				printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
 				    " hwptr %d swptr %d distance %d count %d\n",
 				    codec->dev_audio, voice->number, delta,
 				    dmabuf->hwptr, swptr, distance, dmabuf->count);
@@ -641,10 +661,10 @@
 				/*
 				 * Normal end of DMA.
 				 */
-//				printk("ymfpci%d: %d: done: delta %d"
-//				    " hwptr %d swptr %d distance %d count %d\n",
-//				    codec->dev_audio, voice->number, delta,
-//				    dmabuf->hwptr, swptr, distance, dmabuf->count);
+				YMFDBGI("ymfpci%d: %d: done: delta %d"
+				    " hwptr %d swptr %d distance %d count %d\n",
+				    codec->dev_audio, voice->number, delta,
+				    dmabuf->hwptr, swptr, distance, dmabuf->count);
 			}
 			played = dmabuf->count;
 			if (ypcm->running) {
@@ -698,7 +718,7 @@
 		redzone = ymf_calc_lend(state->format.rate);
 		redzone <<= (state->format.shift + 1);
 
-		pos = cap->bank[unit->active_bank].start;
+		pos = le32_to_cpu(cap->bank[unit->active_bank].start);
 		// pos <<= state->format.shift;
 		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */
 			printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
@@ -742,9 +762,11 @@
 		return -EINVAL;
 	}
 	if (cmd != 0) {
-		codec->ctrl_playback[ypcm->voices[0]->number + 1] = virt_to_bus(ypcm->voices[0]->bank);
+		codec->ctrl_playback[ypcm->voices[0]->number + 1] =
+		    cpu_to_le32(ypcm->voices[0]->bank_ba);
 		if (ypcm->voices[1] != NULL)
-			codec->ctrl_playback[ypcm->voices[1]->number + 1] = virt_to_bus(ypcm->voices[1]->bank);
+			codec->ctrl_playback[ypcm->voices[1]->number + 1] =
+			    cpu_to_le32(ypcm->voices[1]->bank_ba);
 		ypcm->running = 1;
 	} else {
 		codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
@@ -810,6 +832,7 @@
 	u32 lpfK = ymfpci_calc_lpfK(rate);
 	ymfpci_playback_bank_t *bank;
 	int nbank;
+	unsigned le_0x40000000 = cpu_to_le32(0x40000000);
 
 	format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
 	if (stereo)
@@ -818,24 +841,24 @@
 		end >>= 1;
 	for (nbank = 0; nbank < 2; nbank++) {
 		bank = &voice->bank[nbank];
-		bank->format = format;
+		bank->format = cpu_to_le32(format);
 		bank->loop_default = 0;	/* 0-loops forever, otherwise count */
-		bank->base = addr;
+		bank->base = cpu_to_le32(addr);
 		bank->loop_start = 0;
-		bank->loop_end = end;
+		bank->loop_end = cpu_to_le32(end);
 		bank->loop_frac = 0;
-		bank->eg_gain_end = 0x40000000;
-		bank->lpfQ = lpfQ;
+		bank->eg_gain_end = le_0x40000000;
+		bank->lpfQ = cpu_to_le32(lpfQ);
 		bank->status = 0;
 		bank->num_of_frames = 0;
 		bank->loop_count = 0;
 		bank->start = 0;
 		bank->start_frac = 0;
 		bank->delta =
-		bank->delta_end = delta;
+		bank->delta_end = cpu_to_le32(delta);
 		bank->lpfK =
-		bank->lpfK_end = lpfK;
-		bank->eg_gain = 0x40000000;
+		bank->lpfK_end = cpu_to_le32(lpfK);
+		bank->eg_gain = le_0x40000000;
 		bank->lpfD1 =
 		bank->lpfD2 = 0;
 
@@ -855,31 +878,31 @@
 				bank->left_gain = 
 				bank->right_gain =
 				bank->left_gain_end =
-				bank->right_gain_end = 0x40000000;
+				bank->right_gain_end = le_0x40000000;
 			} else {
 				bank->eff2_gain =
 				bank->eff2_gain_end =
 				bank->eff3_gain =
-				bank->eff3_gain_end = 0x40000000;
+				bank->eff3_gain_end = le_0x40000000;
 			}
 		} else {
 			if (!spdif) {
 				if ((voice->number & 1) == 0) {
 					bank->left_gain =
-					bank->left_gain_end = 0x40000000;
+					bank->left_gain_end = le_0x40000000;
 				} else {
-					bank->format |= 1;
+					bank->format |= cpu_to_le32(1);
 					bank->right_gain =
-					bank->right_gain_end = 0x40000000;
+					bank->right_gain_end = le_0x40000000;
 				}
 			} else {
 				if ((voice->number & 1) == 0) {
 					bank->eff2_gain =
-					bank->eff2_gain_end = 0x40000000;
+					bank->eff2_gain_end = le_0x40000000;
 				} else {
-					bank->format |= 1;
+					bank->format |= cpu_to_le32(1);
 					bank->eff3_gain =
-					bank->eff3_gain_end = 0x40000000;
+					bank->eff3_gain_end = le_0x40000000;
 				}
 			}
 		}
@@ -920,7 +943,7 @@
 		ymf_pcm_init_voice(ypcm->voices[nvoice],
 		    state->format.voices == 2, state->format.rate,
 		    ymf_pcm_format_width(state->format.format) == 16,
-		    virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize,
+		    ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
 		    ypcm->spdif);
 	}
 	return 0;
@@ -969,9 +992,9 @@
 	}
 	for (nbank = 0; nbank < 2; nbank++) {
 		bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
-		bank->base = virt_to_bus(ypcm->dmabuf.rawbuf);
+		bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
 		// bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
-		bank->loop_end = ypcm->dmabuf.dmasize;
+		bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
 		bank->start = 0;
 		bank->num_of_loops = 0;
 	}
@@ -1442,13 +1465,14 @@
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
 	struct ymf_dmabuf *dmabuf;
+	int redzone;
 	unsigned long flags;
 	unsigned int mask = 0;
 
 	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &state->wpcm.dmabuf.wait, wait);
-	// if (file->f_mode & FMODE_READ)
-	// 	poll_wait(file, &dmabuf->wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &state->rpcm.dmabuf.wait, wait);
 
 	spin_lock_irqsave(&state->unit->reg_lock, flags);
 	if (file->f_mode & FMODE_READ) {
@@ -1457,12 +1481,21 @@
 			mask |= POLLIN | POLLRDNORM;
 	}
 	if (file->f_mode & FMODE_WRITE) {
+		redzone = ymf_calc_lend(state->format.rate);
+		redzone <<= state->format.shift;
+		redzone *= 3;
+
 		dmabuf = &state->wpcm.dmabuf;
 		if (dmabuf->mapped) {
 			if (dmabuf->count >= (signed)dmabuf->fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+			/*
+			 * Don't select unless a full fragment is available.
+			 * Otherwise artsd does GETOSPACE, sees 0, and loops.
+			 */
+			if (dmabuf->count + redzone + dmabuf->fragsize
+			     <= dmabuf->dmasize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
@@ -1497,6 +1530,7 @@
 		return -EAGAIN;
 	dmabuf->mapped = 1;
 
+/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
 	return 0;
 }
 
@@ -1508,13 +1542,16 @@
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
+	int redzone;
 	int val;
 
 	switch (cmd) {
 	case OSS_GETVERSION:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
 		return put_user(SOUND_VERSION, (int *)arg);
 
 	case SNDCTL_DSP_RESET:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state);
 			dmabuf = &state->wpcm.dmabuf;
@@ -1536,6 +1573,7 @@
 		return 0;
 
 	case SNDCTL_DSP_SYNC:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			dmabuf = &state->wpcm.dmabuf;
 			if (file->f_flags & O_NONBLOCK) {
@@ -1554,6 +1592,7 @@
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
 		if (val >= 8000 && val <= 48000) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1585,6 +1624,7 @@
 	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state); 
 			dmabuf = &state->wpcm.dmabuf;
@@ -1606,24 +1646,31 @@
 		return 0;
 
 	case SNDCTL_DSP_GETBLKSIZE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
 		if (file->f_mode & FMODE_WRITE) {
 			if ((val = prog_dmabuf(state, 0)))
 				return val;
-			return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
+			val = state->wpcm.dmabuf.fragsize;
+			YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+			return put_user(val, (int *)arg);
 		}
 		if (file->f_mode & FMODE_READ) {
 			if ((val = prog_dmabuf(state, 1)))
 				return val;
-			return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
+			val = state->rpcm.dmabuf.fragsize;
+			YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+			return put_user(val, (int *)arg);
 		}
 		return -EINVAL;
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
 		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Select sample format */
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
 		if (val == AFMT_S16_LE || val == AFMT_U8) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1649,6 +1696,7 @@
 	case SNDCTL_DSP_CHANNELS:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
 		if (val != 0) {
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
@@ -1676,6 +1724,7 @@
 		return put_user(state->format.voices, (int *)arg);
 
 	case SNDCTL_DSP_POST:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
 		/*
 		 * Quoting OSS PG:
 		 *    The ioctl SNDCTL_DSP_POST is a lightweight version of
@@ -1697,6 +1746,10 @@
 	case SNDCTL_DSP_SETFRAGMENT:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+		    cmd,
+		    (val >> 16) & 0xFFFF, val & 0xFFFF,
+		    (val >> 16) & 0xFFFF, val & 0xFFFF);
 		dmabuf = &state->wpcm.dmabuf;
 		dmabuf->ossfragshift = val & 0xffff;
 		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
@@ -1707,20 +1760,25 @@
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		dmabuf = &state->wpcm.dmabuf;
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
+		redzone = ymf_calc_lend(state->format.rate);
+		redzone <<= state->format.shift;
+		redzone *= 3;
 		spin_lock_irqsave(&state->unit->reg_lock, flags);
 		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
 		abinfo.fragstotal = dmabuf->numfrag;
 		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETISPACE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
 		dmabuf = &state->rpcm.dmabuf;
@@ -1735,15 +1793,18 @@
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_NONBLOCK:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
 		file->f_flags |= O_NONBLOCK;
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
 		/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
 			    (int *)arg); */
 		return put_user(0, (int *)arg);
 
 	case SNDCTL_DSP_GETIPTR:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
 		dmabuf = &state->rpcm.dmabuf;
@@ -1751,13 +1812,13 @@
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
 		cinfo.ptr = dmabuf->hwptr;
-		/* XXX fishy - breaks invariant  count=hwptr-swptr */
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+		    cinfo.ptr, cinfo.bytes);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETOPTR:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		dmabuf = &state->wpcm.dmabuf;
@@ -1765,22 +1826,25 @@
 		cinfo.bytes = dmabuf->total_bytes;
 		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
 		cinfo.ptr = dmabuf->hwptr;
-		/* XXX fishy - breaks invariant  count=swptr-hwptr */
-		if (dmabuf->mapped)
-			dmabuf->count &= dmabuf->fragsize-1;
 		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+		YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+		    cinfo.ptr, cinfo.bytes);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
 
-	case SNDCTL_DSP_SETDUPLEX:	/* XXX TODO */
-		return -EINVAL;
+	case SNDCTL_DSP_SETDUPLEX:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
+		return 0;		/* Always duplex */
 
 	case SOUND_PCM_READ_RATE:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
 		return put_user(state->format.rate, (int *)arg);
 
 	case SOUND_PCM_READ_CHANNELS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
 		return put_user(state->format.voices, (int *)arg);
 
 	case SOUND_PCM_READ_BITS:
+		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
 		return put_user(AFMT_S16_LE, (int *)arg);
 
 	case SNDCTL_DSP_MAPINBUF:
@@ -1796,6 +1860,7 @@
 		 * Some programs mix up audio devices and ioctls
 		 * or perhaps they expect "universal" ioctls,
 		 * for instance we get SNDCTL_TMR_CONTINUE here.
+		 * (mpg123 -g 100 ends here too - to be fixed.)
 		 */
 		YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
 		break;
@@ -1866,8 +1931,8 @@
 	}
 
 #if 0 /* test if interrupts work */
-	ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */
-	ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
+	ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */
+	ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
 	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
 #endif
 	up(&unit->open_sem);
@@ -1880,8 +1945,8 @@
 	 * a nestable exception, but here it is not nestable due to semaphore.
 	 * XXX Doubtful technique of self-describing objects....
 	 */
-	dealloc_dmabuf(&state->wpcm.dmabuf);
-	dealloc_dmabuf(&state->rpcm.dmabuf);
+	dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+	dealloc_dmabuf(unit, &state->rpcm.dmabuf);
 	ymf_pcm_free_substream(&state->wpcm);
 	ymf_pcm_free_substream(&state->rpcm);
 
@@ -1895,13 +1960,13 @@
 static int ymf_release(struct inode *inode, struct file *file)
 {
 	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	ymfpci_t *codec = state->unit;
+	ymfpci_t *unit = state->unit;
 
 #if 0 /* test if interrupts work */
-	ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
+	ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
 #endif
 
-	down(&codec->open_sem);
+	down(&unit->open_sem);
 
 	/*
 	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
@@ -1909,8 +1974,8 @@
 	 */
 	ymf_wait_dac(state);
 	ymf_stop_adc(state);		/* fortunately, it's immediate */
-	dealloc_dmabuf(&state->wpcm.dmabuf);
-	dealloc_dmabuf(&state->rpcm.dmabuf);
+	dealloc_dmabuf(unit, &state->wpcm.dmabuf);
+	dealloc_dmabuf(unit, &state->rpcm.dmabuf);
 	ymf_pcm_free_substream(&state->wpcm);
 	ymf_pcm_free_substream(&state->rpcm);
 
@@ -1918,7 +1983,7 @@
 	file->private_data = NULL;	/* Can you tell I programmed Solaris */
 	kfree(state);
 
-	up(&codec->open_sem);
+	up(&unit->open_sem);
 
 	return 0;
 }
@@ -1928,10 +1993,10 @@
  */
 static int ymf_open_mixdev(struct inode *inode, struct file *file)
 {
-	int i;
 	int minor = minor(inode->i_rdev);
 	struct list_head *list;
 	ymfpci_t *unit;
+	int i;
 
 	list_for_each(list, &ymf_devs) {
 		unit = list_entry(list, ymfpci_t, ymf_devs);
@@ -1988,23 +2053,21 @@
 
 static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
 {
-	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct ymf_dmabuf *dmabuf;
 	struct list_head *p;
 	struct ymf_state *state;
 	struct ac97_codec *codec;
+	int i;
 
 	spin_lock_irqsave(&unit->reg_lock, flags);
 
 	unit->suspended = 1;
 
 	for (i = 0; i < NR_AC97; i++) {
-		codec = unit->ac97_codec[i];
-		if (!codec)
-			continue;
-		ac97_save_state(codec);
+		if ((codec = unit->ac97_codec[i]) != NULL)
+			ac97_save_state(codec);
 	}
 
 	list_for_each(p, &unit->states) {
@@ -2031,12 +2094,12 @@
 
 static int ymf_resume(struct pci_dev *pcidev)
 {
-	int i;
 	struct ymf_unit *unit = pci_get_drvdata(pcidev);
 	unsigned long flags;
 	struct list_head *p;
 	struct ymf_state *state;
 	struct ac97_codec *codec;
+	int i;
 
 	ymfpci_aclink_reset(unit->pci);
 	ymfpci_codec_ready(unit, 0, 1);		/* prints diag if not ready. */
@@ -2057,10 +2120,8 @@
 	}
 
 	for (i = 0; i < NR_AC97; i++) {
-		codec = unit->ac97_codec[i];
-		if (!codec)
-			continue;
-		ac97_restore_state(codec);
+		if ((codec = unit->ac97_codec[i]) != NULL)
+			ac97_restore_state(codec);
 	}
 
 	unit->suspended = 0;
@@ -2160,12 +2221,15 @@
 {
 	u8 cmd;
 
+	/*
+	 * In the 744, 754 only 0x01 exists, 0x02 is undefined.
+	 * It does not seem to hurt to trip both regardless of revision.
+	 */
 	pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
-	if (cmd & 0x03) {
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
-		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-	}
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
+	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
+
 	pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
 	pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
 }
@@ -2241,29 +2305,39 @@
 
 static int ymfpci_memalloc(ymfpci_t *codec)
 {
-	long size, playback_ctrl_size;
+	unsigned int playback_ctrl_size;
+	unsigned int bank_size_playback;
+	unsigned int bank_size_capture;
+	unsigned int bank_size_effect;
+	unsigned int size;
+	unsigned int off;
+	char *ptr;
+	dma_addr_t pba;
 	int voice, bank;
-	u8 *ptr;
 
 	playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
-	codec->bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
-	codec->bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
-	codec->bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
+	bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
+	bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
+	bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
 	codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
 
 	size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
-	    ((codec->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
-	    ((codec->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
-	    ((codec->bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
+	    ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
+	    ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
+	    ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
 	    codec->work_size;
 
-	ptr = (u8 *)kmalloc(size + 0x00ff, GFP_KERNEL);
+	ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
 	if (ptr == NULL)
 		return -ENOMEM;
-
-	codec->work_ptr = ptr;
-	ptr += 0x00ff;
-	(long)ptr &= ~0x00ff;
+	codec->dma_area_va = ptr;
+	codec->dma_area_ba = pba;
+	codec->dma_area_size = size + 0xff;
+
+	if ((off = ((uint) ptr) & 0xff) != 0) {
+		ptr += 0x100 - off;
+		pba += 0x100 - off;
+	}
 
 	/*
 	 * Hardware requires only ptr[playback_ctrl_size] zeroed,
@@ -2271,34 +2345,49 @@
 	 */
 	memset(ptr, 0, size);
 
-	codec->bank_base_playback = ptr;
 	codec->ctrl_playback = (u32 *)ptr;
-	codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;
+	codec->ctrl_playback_ba = pba;
+	codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
 	ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+	pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
+
+	off = 0;
 	for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
-		for (bank = 0; bank < 2; bank++) {
-			codec->bank_playback[voice][bank] = (ymfpci_playback_bank_t *)ptr;
-			ptr += codec->bank_size_playback;
-		}
 		codec->voices[voice].number = voice;
-		codec->voices[voice].bank = codec->bank_playback[voice][0];
-	}
-	ptr += (codec->bank_size_playback + 0x00ff) & ~0x00ff;
-	codec->bank_base_capture = ptr;
+		codec->voices[voice].bank =
+		    (ymfpci_playback_bank_t *) (ptr + off);
+		codec->voices[voice].bank_ba = pba + off;
+		off += 2 * bank_size_playback;		/* 2 banks */
+	}
+	off = (off + 0xff) & ~0xff;
+	ptr += off;
+	pba += off;
+
+	off = 0;
+	codec->bank_base_capture = pba;
 	for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
 		for (bank = 0; bank < 2; bank++) {
-			codec->bank_capture[voice][bank] = (ymfpci_capture_bank_t *)ptr;
-			ptr += codec->bank_size_capture;
-		}
-	ptr += (codec->bank_size_capture + 0x00ff) & ~0x00ff;
-	codec->bank_base_effect = ptr;
+			codec->bank_capture[voice][bank] =
+			    (ymfpci_capture_bank_t *) (ptr + off);
+			off += bank_size_capture;
+		}
+	off = (off + 0xff) & ~0xff;
+	ptr += off;
+	pba += off;
+
+	off = 0;
+	codec->bank_base_effect = pba;
 	for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
 		for (bank = 0; bank < 2; bank++) {
-			codec->bank_effect[voice][bank] = (ymfpci_effect_bank_t *)ptr;
-			ptr += codec->bank_size_effect;
-		}
-	ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff;
-	codec->work_base = ptr;
+			codec->bank_effect[voice][bank] =
+			    (ymfpci_effect_bank_t *) (ptr + off);
+			off += bank_size_effect;
+		}
+	off = (off + 0xff) & ~0xff;
+	ptr += off;
+	pba += off;
+
+	codec->work_base = pba;
 
 	return 0;
 }
@@ -2310,16 +2399,17 @@
 	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
 	ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
 	ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
-	kfree(codec->work_ptr);
+	pci_free_consistent(codec->pci,
+	    codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
 }
 
 static void ymf_memload(ymfpci_t *unit)
 {
 
-	ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback));
-	ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture));
-	ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect));
-	ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base));
+	ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
+	ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
+	ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
+	ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
 	ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
 
 	/* S/PDIF output initialization */
@@ -2357,7 +2447,7 @@
 	codec->codec_write = ymfpci_codec_write;
 
 	if (ac97_probe_codec(codec) == 0) {
-		printk("ymfpci: ac97_probe_codec failed\n");
+		printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
 		goto out_kfree;
 	}
 
@@ -2398,6 +2488,7 @@
 static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
 	u16 ctrl;
+	unsigned long base;
 	ymfpci_t *codec;
 
 	int err;
@@ -2406,6 +2497,7 @@
 		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
 		return err;
 	}
+	base = pci_resource_start(pcidev, 0);
 
 	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "ymfpci: no core\n");
@@ -2420,16 +2512,21 @@
 	codec->pci = pcidev;
 
 	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-	codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
-	if (codec->reg_area_virt == NULL) {
-		printk(KERN_ERR "ymfpci: unable to map registers\n");
+
+	if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
+		printk(KERN_ERR "ymfpci: unable to request mem region\n");
 		goto out_free;
 	}
 
+	if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
+		printk(KERN_ERR "ymfpci: unable to map registers\n");
+		goto out_release_region;
+	}
+
 	pci_set_master(pcidev);
 
 	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
-	    (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
+	    (char *)ent->driver_data, base, pcidev->irq);
 
 	ymfpci_aclink_reset(pcidev);
 	if (ymfpci_codec_ready(codec, 0, 1) < 0)
@@ -2459,8 +2556,7 @@
 
 	/* register /dev/dsp */
 	if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
-		printk(KERN_ERR "ymfpci%d: unable to register dsp\n",
-		    codec->dev_audio);
+		printk(KERN_ERR "ymfpci: unable to register dsp\n");
 		goto out_free_irq;
 	}
 
@@ -2478,7 +2574,7 @@
 	codec->opl3_data.irq     = -1;
 
 	codec->mpu_data.io_base  = codec->iomidi;
-	codec->mpu_data.irq      = -1;	/* XXX Make it ours. */
+	codec->mpu_data.irq      = -1;	/* May be different from our PCI IRQ. */
 
 	if (codec->iomidi) {
 		if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
@@ -2506,6 +2602,8 @@
 	ymfpci_writel(codec, YDSXGR_STATUS, ~0);
  out_unmap:
 	iounmap(codec->reg_area_virt);
+ out_release_region:
+	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
  out_free:
 	kfree(codec);
 	return -ENODEV;
@@ -2529,6 +2627,7 @@
 	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
 	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
 	iounmap(codec->reg_area_virt);
+	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
 #ifdef CONFIG_SOUND_YMFPCI_LEGACY
 	if (codec->iomidi) {
 		unload_uart401(&codec->mpu_data);
diff -urN linux-2.5.2-pre11/drivers/sound/ymfpci.h linux/drivers/sound/ymfpci.h
--- linux-2.5.2-pre11/drivers/sound/ymfpci.h	Sun Aug 12 10:51:42 2001
+++ linux/drivers/sound/ymfpci.h	Mon Jan 14 18:28:30 2002
@@ -227,6 +227,7 @@
 	char use, pcm, synth, midi;	// bool
 	ymfpci_playback_bank_t *bank;
 	struct ymf_pcm *ypcm;
+	dma_addr_t bank_ba;
 };
 
 struct ymf_capture {
@@ -239,19 +240,17 @@
 struct ymf_unit {
 	u8 rev;				/* PCI revision */
 	void *reg_area_virt;
-	void *work_ptr;
-
-	unsigned int bank_size_playback;
-	unsigned int bank_size_capture;
-	unsigned int bank_size_effect;
+	void *dma_area_va;
+	dma_addr_t dma_area_ba;
+	unsigned int dma_area_size;
+
+	dma_addr_t bank_base_capture;
+	dma_addr_t bank_base_effect;
+	dma_addr_t work_base;
 	unsigned int work_size;
 
-	void *bank_base_playback;
-	void *bank_base_capture;
-	void *bank_base_effect;
-	void *work_base;
-
 	u32 *ctrl_playback;
+	dma_addr_t ctrl_playback_ba;
 	ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
 	ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
 	ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
@@ -286,10 +285,11 @@
 };
 
 struct ymf_dmabuf {
-
-	/* OSS buffer management stuff */
+	dma_addr_t dma_addr;
 	void *rawbuf;
 	unsigned buforder;
+
+	/* OSS buffer management stuff */
 	unsigned numfrag;
 	unsigned fragshift;
 
diff -urN linux-2.5.2-pre11/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c
--- linux-2.5.2-pre11/drivers/telephony/phonedev.c	Fri Sep  7 09:28:37 2001
+++ linux/drivers/telephony/phonedev.c	Mon Jan 14 18:28:30 2002
@@ -46,7 +46,7 @@
 
 static int phone_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
+	unsigned int minor = minor(inode->i_rdev);
 	int err = 0;
 	struct phone_device *p;
 	struct file_operations *old_fops, *new_fops = NULL;
diff -urN linux-2.5.2-pre11/drivers/usb/Makefile.lib linux/drivers/usb/Makefile.lib
--- linux-2.5.2-pre11/drivers/usb/Makefile.lib	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/Makefile.lib	Mon Jan 14 18:28:30 2002
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_CATC)		+= crc32.o
diff -urN linux-2.5.2-pre11/drivers/usb/catc.c linux/drivers/usb/catc.c
--- linux-2.5.2-pre11/drivers/usb/catc.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/usb/catc.c	Mon Jan 14 18:28:31 2002
@@ -39,6 +39,7 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
@@ -531,13 +532,9 @@
 
 static void catc_multicast(unsigned char *addr, u8 *multicast)
 {
-	unsigned int crc = 0xffffffff;
-	u8 byte, idx, bit;
-
-        for (idx = 0; idx < 6; idx++)
-                for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)
-                        crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);
+	u32 crc;
 
+	crc = ether_crc_le(6, addr);
 	multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
 }
 
diff -urN linux-2.5.2-pre11/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- linux-2.5.2-pre11/drivers/usb/hcd/ehci-hcd.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/usb/hcd/ehci-hcd.c	Mon Jan 14 18:28:31 2002
@@ -743,7 +743,7 @@
 static int __init init (void) 
 {
 	dbg (DRIVER_INFO);
-	dbg ("block sizes: qh %d qtd %d itd %d sitd %d",
+	dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd",
 		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
 		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
 
diff -urN linux-2.5.2-pre11/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- linux-2.5.2-pre11/drivers/usb/hcd/ehci-sched.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/usb/hcd/ehci-sched.c	Mon Jan 14 18:28:31 2002
@@ -381,7 +381,7 @@
 			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
-				if (unlikely ((int)ehci->pshadow [frame].ptr)) {
+				if (unlikely ((long)ehci->pshadow [frame].ptr)) {
 // FIXME -- just link to the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
 					BUG ();
diff -urN linux-2.5.2-pre11/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- linux-2.5.2-pre11/drivers/usb/hcd.c	Mon Jan 14 18:28:23 2002
+++ linux/drivers/usb/hcd.c	Mon Jan 14 18:28:31 2002
@@ -624,7 +624,7 @@
 #ifndef __sparc__
 	sprintf (buf, "%d", dev->irq);
 #else
-	bufp = __irq_itoa(irq);
+	bufp = __irq_itoa(dev->irq);
 #endif
 	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
 			!= 0) {
diff -urN linux-2.5.2-pre11/drivers/video/aty/mach64_accel.c linux/drivers/video/aty/mach64_accel.c
--- linux-2.5.2-pre11/drivers/video/aty/mach64_accel.c	Tue Jul 31 14:43:29 2001
+++ linux/drivers/video/aty/mach64_accel.c	Mon Jan 14 18:28:31 2002
@@ -326,7 +326,7 @@
 		     fbcon_cfb##width##_clear_margins(conp, p, bottom_only), \
 		     int bottom_only) \
  \
-const struct display_switch fbcon_aty##width## = { \
+const struct display_switch fbcon_aty##width = { \
     setup:		fbcon_cfb##width##_setup, \
     bmove:		fbcon_aty_bmove, \
     clear:		fbcon_aty_clear, \
diff -urN linux-2.5.2-pre11/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- linux-2.5.2-pre11/drivers/video/sbusfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/sbusfb.c	Mon Jan 14 18:28:31 2002
@@ -1019,7 +1019,7 @@
 	fix->type = FB_TYPE_PACKED_PIXELS;
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
 	
-	fb->info.node = -1;
+	fb->info.node = NODEV;
 	fb->info.fbops = &sbusfb_ops;
 	fb->info.disp = disp;
 	strcpy(fb->info.fontname, fontname);
diff -urN linux-2.5.2-pre11/fs/Makefile.lib linux/fs/Makefile.lib
--- linux-2.5.2-pre11/fs/Makefile.lib	Wed Dec 31 16:00:00 1969
+++ linux/fs/Makefile.lib	Mon Jan 14 18:28:31 2002
@@ -0,0 +1,2 @@
+obj-$(CONFIG_FS_JFFS2)		+= crc32.o
+obj-$(CONFIG_EFI_PARTITION)	+= crc32.o
diff -urN linux-2.5.2-pre11/fs/affs/file.c linux/fs/affs/file.c
--- linux-2.5.2-pre11/fs/affs/file.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/affs/file.c	Mon Jan 14 18:28:31 2002
@@ -401,6 +401,7 @@
 err_alloc:
 	brelse(ext_bh);
 	bh_result->b_state &= ~(1UL << BH_Mapped);
+	bh_result->b_bdev = NULL;
 	// unlock cache
 	affs_unlock_ext(inode);
 	return -ENOSPC;
diff -urN linux-2.5.2-pre11/fs/block_dev.c linux/fs/block_dev.c
--- linux-2.5.2-pre11/fs/block_dev.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/block_dev.c	Mon Jan 14 18:28:31 2002
@@ -128,6 +128,7 @@
 		return -EIO;
 
 	bh->b_dev = inode->i_rdev;
+	bh->b_bdev = inode->i_bdev;
 	bh->b_blocknr = iblock;
 	bh->b_state |= 1UL << BH_Mapped;
 	return 0;
diff -urN linux-2.5.2-pre11/fs/buffer.c linux/fs/buffer.c
--- linux-2.5.2-pre11/fs/buffer.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/buffer.c	Mon Jan 14 18:28:31 2002
@@ -83,7 +83,7 @@
 static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
 static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
 
-static int grow_buffers(kdev_t dev, unsigned long block, int size);
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size);
 static void __refile_buffer(struct buffer_head *);
 
 /* This is used by some architectures to estimate available memory. */
@@ -557,9 +557,9 @@
 	spin_unlock(&lru_list_lock);
 }
 
-struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block, int size)
 {
-	struct buffer_head *bh, **p = &hash(dev, block);
+	struct buffer_head *bh, **p = &hash(to_kdev_t(bdev->bd_dev), block);
 
 	read_lock(&hash_table_lock);
 
@@ -572,7 +572,7 @@
 			continue;
 		if (bh->b_size != size)
 			continue;
-		if (!kdev_same(bh->b_dev, dev))
+		if (bh->b_bdev != bdev)
 			continue;
 		get_bh(bh);
 		break;
@@ -1024,15 +1024,14 @@
  */
 struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size)
 {
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	for (;;) {
 		struct buffer_head * bh;
 
-		bh = get_hash_table(dev, block, size);
+		bh = __get_hash_table(bdev, block, size);
 		if (bh)
 			return bh;
 
-		if (!grow_buffers(dev, block, size))
+		if (!grow_buffers(bdev, block, size))
 			free_more_memory();
 	}
 }
@@ -1202,6 +1201,7 @@
 		kmem_cache_free(bh_cachep, bh);
 	} else {
 		bh->b_dev = B_FREE;
+		bh->b_bdev = NULL;
 		bh->b_blocknr = -1;
 		bh->b_this_page = NULL;
 
@@ -1305,6 +1305,7 @@
 			goto no_grow;
 
 		bh->b_dev = NODEV;
+		bh->b_bdev = NULL;
 		bh->b_this_page = head;
 		head = bh;
 
@@ -1366,6 +1367,7 @@
 	if (buffer_mapped(bh)) {
 		mark_buffer_clean(bh);
 		lock_buffer(bh);
+		bh->b_bdev = NULL;
 		clear_bit(BH_Uptodate, &bh->b_state);
 		clear_bit(BH_Mapped, &bh->b_state);
 		clear_bit(BH_Req, &bh->b_state);
@@ -1487,7 +1489,7 @@
 {
 	struct buffer_head *old_bh;
 
-	old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+	old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
 	if (old_bh) {
 		mark_buffer_clean(old_bh);
 		wait_on_buffer(old_bh);
@@ -2119,7 +2121,7 @@
  * FIXME: we need a swapper_inode->get_block function to remove
  *        some of the bmap kludges and interface ugliness here.
  */
-int brw_page(int rw, struct page *page, kdev_t dev, sector_t b[], int size)
+int brw_page(int rw, struct page *page, struct block_device *bdev, sector_t b[], int size)
 {
 	struct buffer_head *head, *bh;
 
@@ -2134,7 +2136,8 @@
 	do {
 		lock_buffer(bh);
 		bh->b_blocknr = *(b++);
-		bh->b_dev = dev;
+		bh->b_bdev = bdev;
+		bh->b_dev = to_kdev_t(bdev->bd_dev);
 		set_bit(BH_Mapped, &bh->b_state);
 		set_buffer_async_io(bh);
 		bh = bh->b_this_page;
@@ -2234,7 +2237,7 @@
 	return NULL;
 }
 
-static void hash_page_buffers(struct page *page, kdev_t dev, int block, int size)
+static void hash_page_buffers(struct page *page, struct block_device *bdev, int block, int size)
 {
 	struct buffer_head *head = page->buffers;
 	struct buffer_head *bh = head;
@@ -2248,7 +2251,8 @@
 	do {
 		if (!(bh->b_state & (1 << BH_Mapped))) {
 			init_buffer(bh, NULL, NULL);
-			bh->b_dev = dev;
+			bh->b_bdev = bdev;
+			bh->b_dev = to_kdev_t(bdev->bd_dev);
 			bh->b_blocknr = block;
 			bh->b_state = uptodate;
 		}
@@ -2267,15 +2271,14 @@
  * Try to increase the number of buffers available: the size argument
  * is used to determine what kind of buffers we want.
  */
-static int grow_buffers(kdev_t dev, unsigned long block, int size)
+static int grow_buffers(struct block_device *bdev, unsigned long block, int size)
 {
 	struct page * page;
-	struct block_device *bdev;
 	unsigned long index;
 	int sizebits;
 
 	/* Size must be multiple of hard sectorsize */
-	if (size & (get_hardsect_size(dev)-1))
+	if (size & (get_hardsect_size(to_kdev_t(bdev->bd_dev))-1))
 		BUG();
 	/* Size must be within 512 bytes and PAGE_SIZE */
 	if (size < 512 || size > PAGE_SIZE)
@@ -2289,22 +2292,14 @@
 	index = block >> sizebits;
 	block = index << sizebits;
 
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", kdevname(dev));
-		BUG();
-	}
-
 	/* Create a page with the proper size buffers.. */
 	page = grow_dev_page(bdev, index, size);
 
-	/* This is "wrong" - talk to Al Viro */
-	atomic_dec(&bdev->bd_count);
 	if (!page)
 		return 0;
 
 	/* Hash in the buffers on the hash list */
-	hash_page_buffers(page, dev, block, size);
+	hash_page_buffers(page, bdev, block, size);
 	UnlockPage(page);
 	page_cache_release(page);
 
diff -urN linux-2.5.2-pre11/fs/coda/inode.c linux/fs/coda/inode.c
--- linux-2.5.2-pre11/fs/coda/inode.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/coda/inode.c	Mon Jan 14 18:28:31 2002
@@ -151,8 +151,8 @@
 	    goto error;
 	} 
 
-	printk("coda_read_super: rootinode is %ld dev %d\n", 
-	       root->i_ino, root->i_dev);
+	printk("coda_read_super: rootinode is %ld dev %x\n", 
+	       root->i_ino, kdev_val(root->i_dev));
 	sb->s_root = d_alloc_root(root);
         return sb;
 
diff -urN linux-2.5.2-pre11/fs/coda/pioctl.c linux/fs/coda/pioctl.c
--- linux-2.5.2-pre11/fs/coda/pioctl.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/coda/pioctl.c	Mon Jan 14 18:28:31 2002
@@ -81,7 +81,7 @@
 	}
 	
 	CDEBUG(D_PIOCTL, "target ino: 0x%ld, dev: 0x%x\n",
-	       target_inode->i_ino, target_inode->i_dev);
+	       target_inode->i_ino, kdev_val(target_inode->i_dev));
 
 	/* return if it is not a Coda inode */
 	if ( target_inode->i_sb != inode->i_sb ) {
diff -urN linux-2.5.2-pre11/fs/dcache.c linux/fs/dcache.c
--- linux-2.5.2-pre11/fs/dcache.c	Mon Dec 10 14:13:25 2001
+++ linux/fs/dcache.c	Mon Jan 14 18:28:31 2002
@@ -1262,7 +1262,7 @@
 		panic("Cannot create buffer head SLAB cache");
 
 	names_cachep = kmem_cache_create("names_cache", 
-			PATH_MAX + 1, 0, 
+			PATH_MAX, 0, 
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!names_cachep)
 		panic("Cannot create names SLAB cache");
diff -urN linux-2.5.2-pre11/fs/devfs/base.c linux/fs/devfs/base.c
--- linux-2.5.2-pre11/fs/devfs/base.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/devfs/base.c	Mon Jan 14 18:28:31 2002
@@ -601,6 +601,9 @@
 	       Only return old entry in <devfs_mk_dir> if a directory.
 	       Defined macros for error and debug messages.
   v1.8
+    20020113   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed (rare, old) race in <devfs_lookup>.
+  v1.9
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -633,7 +636,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.8 (20011226)"
+#define DEVFS_VERSION            "1.9 (20020113)"
 
 #define DEVFS_NAME "devfs"
 
@@ -894,8 +897,8 @@
     {
 	devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
 			       DEVFS_SPECIAL_BLK,
-			       mk_kdev(de->u.fcb.u.device.major,
-				      de->u.fcb.u.device.minor) );
+			       mk_kdev (de->u.fcb.u.device.major,
+					de->u.fcb.u.device.minor) );
     }
     WRITE_ENTRY_MAGIC (de, 0);
 #ifdef CONFIG_DEVFS_DEBUG
@@ -1552,7 +1555,7 @@
     if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
 	 (flags & DEVFS_FL_AUTO_DEVNUM) )
     {
-	if ( kdev_none( devnum = devfs_alloc_devnum (devtype) ) )
+	if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
 	{
 	    PRINTK ("(%s): exhausted %s device numbers\n",
 		    name, S_ISCHR (mode) ? "char" : "block");
@@ -1564,14 +1567,14 @@
     if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
     {
 	PRINTK ("(%s): could not prepare leaf\n", name);
-	if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+	if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
 	return NULL;
     }
     if ( S_ISCHR (mode) || S_ISBLK (mode) )
     {
 	de->u.fcb.u.device.major = major;
 	de->u.fcb.u.device.minor = minor;
-	de->u.fcb.autogen = kdev_none(devnum) ? FALSE : TRUE;
+	de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
     }
     else if ( !S_ISREG (mode) )
     {
@@ -1601,7 +1604,7 @@
     {
 	PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
 	devfs_put (dir);
-	if (!kdev_none(devnum)) devfs_dealloc_devnum (devtype, devnum);
+	if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
 	return NULL;
     }
     DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",
@@ -2378,7 +2381,7 @@
  *	@buf: A working area that will be used. This must not go out of scope
  *            until devfsd is idle again.
  *
- *	Returns 0 on success, else a negative error code.
+ *	Returns 0 on success (event was queued), else a negative error code.
  */
 
 static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
@@ -2397,7 +2400,7 @@
     if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
 			    current->euid, current->egid, fs_info, 0) )
 	return -ENOENT;
-    /*  Possible success  */
+    /*  Possible success: event has been queued  */
     return 0;
 }   /*  End Function try_modload  */
 
@@ -2413,7 +2416,7 @@
 {
     int tmp;
     int retval = 0;
-    kdev_t dev = mk_kdev(de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
+    kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
     struct block_device_operations *bdops;
     extern int warn_no_part;
 
@@ -2599,15 +2602,15 @@
     inode->i_rdev = NODEV;
     if ( S_ISCHR (de->mode) )
     {
-	inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
-			       de->u.fcb.u.device.minor);
+	inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+				 de->u.fcb.u.device.minor);
 	inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
 	is_fcb = TRUE;
     }
     else if ( S_ISBLK (de->mode) )
     {
-	inode->i_rdev = mk_kdev(de->u.fcb.u.device.major,
-			       de->u.fcb.u.device.minor);
+	inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
+				 de->u.fcb.u.device.minor);
 	if (bd_acquire (inode) == 0)
 	{
 	    if (!inode->i_bdev->bd_op && de->u.fcb.ops)
@@ -2861,34 +2864,55 @@
     return 0;
 }   /*  End Function devfs_d_delete  */
 
+struct devfs_lookup_struct
+{
+    devfs_handle_t de;
+    wait_queue_head_t wait_queue;
+};
+
 static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
 {
     struct inode *dir = dentry->d_parent->d_inode;
     struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+    struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
+    DECLARE_WAITQUEUE (wait, current);
 
     if ( !dentry->d_inode && is_devfsd_or_child (fs_info) )
     {
-	devfs_handle_t de;
-	devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
+	devfs_handle_t de = lookup_info->de;
 	struct inode *inode;
 
-	DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n",
-		 dentry->d_name.name, dentry, current->comm);
-	read_lock (&parent->u.dir.lock);
-	de = _devfs_search_dir (parent, dentry->d_name.name,
-				dentry->d_name.len);
-	read_unlock (&parent->u.dir.lock);
-	if (de == NULL) return 1;
+	DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p de: %p by: \"%s\"\n",
+		 dentry->d_name.name, dentry, de, current->comm);
+	if (de == NULL)
+	{
+	    read_lock (&parent->u.dir.lock);
+	    de = _devfs_search_dir (parent, dentry->d_name.name,
+				    dentry->d_name.len);
+	    read_unlock (&parent->u.dir.lock);
+	    if (de == NULL) return 1;
+	    lookup_info->de = de;
+	}
 	/*  Create an inode, now that the driver information is available  */
 	inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
-	devfs_put (de);
 	if (!inode) return 1;
-	DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p  de: %p\n",
-		 de->name, de->inode.ino, inode, de);
+	DPRINTK (DEBUG_I_LOOKUP,
+		 "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+		 de->name, de->inode.ino, inode, de, current->comm);
 	d_instantiate (dentry, inode);
 	return 1;
     }
-    if ( wait_for_devfsd_finished (fs_info) ) dentry->d_op = &devfs_dops;
+    if (lookup_info == NULL) return 1;  /*  Early termination  */
+    read_lock (&parent->u.dir.lock);
+    if (dentry->d_fsdata)
+    {
+	add_wait_queue (&lookup_info->wait_queue, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	read_unlock (&parent->u.dir.lock);
+	schedule ();
+    }
+    else read_unlock (&parent->u.dir.lock);
     return 1;
 }   /*  End Function devfs_d_revalidate_wait  */
 
@@ -2897,9 +2921,12 @@
 
 static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
 {
+    struct devfs_entry tmp;  /*  Must stay in scope until devfsd idle again  */
+    struct devfs_lookup_struct lookup_info;
     struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct devfs_entry *parent, *de;
     struct inode *inode;
+    struct dentry *retval = NULL;
 
     /*  Set up the dentry operations before anything else, to ensure cleaning
 	up on any error  */
@@ -2921,60 +2948,61 @@
 				dentry->d_name.len);
 	read_unlock (&parent->u.dir.lock);
     }
+    lookup_info.de = de;
+    init_waitqueue_head (&lookup_info.wait_queue);
+    dentry->d_fsdata = &lookup_info;
     if (de == NULL)
     {   /*  Try with devfsd. For any kind of failure, leave a negative dentry
 	    so someone else can deal with it (in the case where the sysadmin
 	    does a mknod()). It's important to do this before hashing the
 	    dentry, so that the devfsd queue is filled before revalidates
 	    can start  */
-	struct devfs_entry tmp;
-
 	if (try_modload (parent, fs_info,
 			 dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
-	{
+	{   /*  Lookup event was not queued to devfsd  */
 	    d_add (dentry, NULL);
 	    return NULL;
 	}
-	/*  devfsd claimed success  */
-	dentry->d_op = &devfs_wait_dops;
-	d_add (dentry, NULL);  /*  Open the floodgates  */
-	/*  Unlock directory semaphore, which will release any waiters. They
-	    will get the hashed dentry, and may be forced to wait for
-	    revalidation  */
-	up (&dir->i_sem);
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
-	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
-	/*  If someone else has been so kind as to make the inode, we go home
-	    early  */
-	if (dentry->d_inode) return NULL;
+    }
+    dentry->d_op = &devfs_wait_dops;
+    d_add (dentry, NULL);  /*  Open the floodgates  */
+    /*  Unlock directory semaphore, which will release any waiters. They
+	will get the hashed dentry, and may be forced to wait for
+	revalidation  */
+    up (&dir->i_sem);
+    wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
+    down (&dir->i_sem);      /*  Grab it again because them's the rules  */
+    de = lookup_info.de;
+    /*  If someone else has been so kind as to make the inode, we go home
+	early  */
+    if (dentry->d_inode) goto out;
+    if (de == NULL)
+    {
 	read_lock (&parent->u.dir.lock);
 	de = _devfs_search_dir (parent, dentry->d_name.name,
 				dentry->d_name.len);
 	read_unlock (&parent->u.dir.lock);
-	if (de == NULL) return NULL;
+	if (de == NULL) goto out;
 	/*  OK, there's an entry now, but no VFS inode yet  */
     }
-    else
-    {
-	dentry->d_op = &devfs_wait_dops;
-	d_add (dentry, NULL);  /*  Open the floodgates  */
-    }
     /*  Create an inode, now that the driver information is available  */
     inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
-    devfs_put (de);
-    if (!inode) return ERR_PTR (-ENOMEM);
-    DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p  de: %p\n",
-	     de->name, de->inode.ino, inode, de);
-    d_instantiate (dentry, inode);
-    if (dentry->d_op == &devfs_wait_dops)
-    {   /*  Unlock directory semaphore, which will release any waiters. They
-	    will get the hashed dentry, and may be forced to wait for
-	    revalidation  */
-	up (&dir->i_sem);
-	devfs_d_revalidate_wait (dentry, 0);  /*  I might have to wait too   */
-	down (&dir->i_sem);      /*  Grab it again because them's the rules  */
+    if (!inode)
+    {
+	retval = ERR_PTR (-ENOMEM);
+	goto out;
     }
-    return NULL;
+    DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
+	     de->name, de->inode.ino, inode, de, current->comm);
+    d_instantiate (dentry, inode);
+out:
+    dentry->d_op = &devfs_dops;
+    dentry->d_fsdata = NULL;
+    write_lock (&parent->u.dir.lock);
+    wake_up (&lookup_info.wait_queue);
+    write_unlock (&parent->u.dir.lock);
+    devfs_put (de);
+    return retval;
 }   /*  End Function devfs_lookup  */
 
 static int devfs_unlink (struct inode *dir, struct dentry *dentry)
diff -urN linux-2.5.2-pre11/fs/devpts/root.c linux/fs/devpts/root.c
--- linux-2.5.2-pre11/fs/devpts/root.c	Fri Aug 11 14:29:02 2000
+++ linux/fs/devpts/root.c	Mon Jan 14 18:28:31 2002
@@ -101,7 +101,6 @@
 	int i;
 	const char *p;
 
-	dentry->d_inode = NULL;	/* Assume failure */
 	dentry->d_op    = &devpts_dentry_operations;
 
 	if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
@@ -127,11 +126,10 @@
 	if ( entry >= sbi->max_ptys )
 		return NULL;
 
-	dentry->d_inode = sbi->inodes[entry];
-	if ( dentry->d_inode )
-		atomic_inc(&dentry->d_inode->i_count);
+	if ( sbi->inodes[entry] )
+		atomic_inc(&sbi->inodes[entry]->i_count);
 	
-	d_add(dentry, dentry->d_inode);
+	d_add(dentry, sbi->inodes[entry]);
 
 	return NULL;
 }
diff -urN linux-2.5.2-pre11/fs/driverfs/inode.c linux/fs/driverfs/inode.c
--- linux-2.5.2-pre11/fs/driverfs/inode.c	Thu Nov 29 16:55:11 2001
+++ linux/fs/driverfs/inode.c	Mon Jan 14 18:28:31 2002
@@ -374,7 +374,7 @@
 
 	entry = (struct driver_file_entry *)dentry->d_fsdata;
 	if (entry)
-		kfree(dentry);
+		kfree(entry);
 	return 0;
 }
 
diff -urN linux-2.5.2-pre11/fs/fat/cache.c linux/fs/fat/cache.c
--- linux-2.5.2-pre11/fs/fat/cache.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/fat/cache.c	Mon Jan 14 18:28:31 2002
@@ -189,7 +189,7 @@
 
 	for (walk = fat_cache; walk; walk = walk->next) {
 		if (walk->sb)
-			printk("<%s,%d>(%d,%d) ", walk->sb->s_dev->s_id,
+			printk("<%s,%d>(%d,%d) ", walk->sb->s_id,
 			       walk->start_cluster, walk->file_cluster,
 			       walk->disk_cluster);
 		else printk("-- ");
diff -urN linux-2.5.2-pre11/fs/fat/inode.c linux/fs/fat/inode.c
--- linux-2.5.2-pre11/fs/fat/inode.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/fat/inode.c	Mon Jan 14 18:28:31 2002
@@ -407,7 +407,7 @@
 	}
 	inode->i_blksize = 1 << sbi->cluster_bits;
 	inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
-			   & ~(inode->i_blksize - 1)) / 512;
+			   & ~(inode->i_blksize - 1)) >> 9;
 	MSDOS_I(inode)->i_logstart = 0;
 	MSDOS_I(inode)->mmu_private = inode->i_size;
 
@@ -949,7 +949,7 @@
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = 1 << sbi->cluster_bits;
 	inode->i_blocks = ((inode->i_size + inode->i_blksize - 1)
-			   & ~(inode->i_blksize - 1)) / 512;
+			   & ~(inode->i_blksize - 1)) >> 9;
 	inode->i_mtime = inode->i_atime =
 		date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
 	inode->i_ctime =
diff -urN linux-2.5.2-pre11/fs/inode.c linux/fs/inode.c
--- linux-2.5.2-pre11/fs/inode.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/inode.c	Mon Jan 14 18:28:31 2002
@@ -1082,7 +1082,7 @@
 				}
 				inodes_stat.nr_unused++;
 				spin_unlock(&inode_lock);
-				if (!sb || sb->s_flags & MS_ACTIVE)
+				if (!sb || (sb->s_flags & MS_ACTIVE))
 					return;
 				write_inode_now(inode, 1);
 				spin_lock(&inode_lock);
diff -urN linux-2.5.2-pre11/fs/intermezzo/cache.c linux/fs/intermezzo/cache.c
--- linux-2.5.2-pre11/fs/intermezzo/cache.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/cache.c	Mon Jan 14 18:28:31 2002
@@ -46,7 +46,7 @@
 
 static inline int presto_cache_hash(kdev_t dev)
 {
-        return (CACHES_MASK) & ((0x000F & (dev)) + ((0x0F00 & (dev)) >>8));
+        return (CACHES_MASK) & ((0x000F & (kdev_val(dev))) + ((0x0F00 & (kdev_val(dev))) >>8));
 }
 
 inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
@@ -73,7 +73,7 @@
         lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
         while ( (tmp = lh->next) != lh ) {
                 cache = list_entry(tmp, struct presto_cache, cache_chain);
-                if ( cache->cache_dev == dev ) {
+                if ( kdev_same(cache->cache_dev, dev) ) {
                         return cache;
                 }
         }
@@ -90,7 +90,7 @@
         cache = presto_find_cache(inode->i_dev);
         if ( !cache ) {
                 printk("WARNING: no presto cache for dev %x, ino %ld\n",
-                       inode->i_dev, inode->i_ino);
+                       kdev_val(inode->i_dev), inode->i_ino);
                 EXIT;
                 return NULL;
         }
@@ -174,7 +174,7 @@
         cache = presto_get_cache(inode);
         if ( !cache )
                 return 0;
-        return (inode->i_dev == cache->cache_dev);
+        return (kdev_same(inode->i_dev, cache->cache_dev));
 }
 
 /* setup a cache structure when we need one */
diff -urN linux-2.5.2-pre11/fs/intermezzo/presto.c linux/fs/intermezzo/presto.c
--- linux-2.5.2-pre11/fs/intermezzo/presto.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/intermezzo/presto.c	Mon Jan 14 18:28:31 2002
@@ -71,8 +71,8 @@
         cache = presto_get_cache(inode);
         CDEBUG(D_PSDEV, "\n");
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
-                       inode->i_dev, inode->i_ino);
+                printk("PRESTO: BAD: cannot find cache for dev %x, ino %ld\n",
+                       kdev_val(inode->i_dev), inode->i_ino);
                 EXIT;
                 return -1;
         }
diff -urN linux-2.5.2-pre11/fs/intermezzo/psdev.c linux/fs/intermezzo/psdev.c
--- linux-2.5.2-pre11/fs/intermezzo/psdev.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/intermezzo/psdev.c	Mon Jan 14 18:28:31 2002
@@ -43,14 +43,15 @@
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/tty.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/termios.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
+#include <asm/ioctls.h>
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_upcall.h>
@@ -290,7 +291,7 @@
                 }
 
                 len = readmount.io_len;
-                minor = MINOR(dev);
+                minor = minor(dev);
                 PRESTO_ALLOC(tmp, char *, len);
                 if (!tmp) {
                         EXIT;
@@ -627,7 +628,7 @@
                         EXIT;
                         return error;
                 }
-                minor = MINOR(dev);
+                minor = minor(dev);
                 if (cmd == PRESTO_SETOPT)
                         error = dosetopt(minor, &kopt);
 
diff -urN linux-2.5.2-pre11/fs/intermezzo/sysctl.c linux/fs/intermezzo/sysctl.c
--- linux-2.5.2-pre11/fs/intermezzo/sysctl.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/intermezzo/sysctl.c	Mon Jan 14 18:28:31 2002
@@ -161,15 +161,17 @@
 		 * current presto cache.
 		 */
 		int errorval = upc_comms[minor].uc_errorval;
+		kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
 		if (errorval < 0) {
 			if (newval == 0)
-				set_device_ro(-errorval, 0);
+				set_device_ro(kdev, 0);
 			else
 				printk("device %s already read only\n",
-				       kdevname(-errorval));
+				       kdevname(kdev));
 		} else {
+			kdev = mk_kdev(MAJOR(-newval), MINOR(-newval));
 			if (newval < 0)
-				set_device_ro(-newval, 1);
+				set_device_ro(kdev, 1);
 			upc_comms[minor].uc_errorval = newval;
 			CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
 		}
@@ -224,9 +226,10 @@
 #ifdef PSDEV_DEBUG
 	case PSDEV_ERRORVAL: {
 		int errorval = upc_comms[minor].uc_errorval;
-		if (errorval < 0 && is_read_only(-errorval))
+		kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
+		if (errorval < 0 && is_read_only(kdev))
 			printk(KERN_INFO "device %s has been set read-only\n",
-			       kdevname(-errorval));
+			       kdevname(kdev));
 		opt->optval = upc_comms[minor].uc_errorval;
 		break;
 	}
diff -urN linux-2.5.2-pre11/fs/intermezzo/vfs.c linux/fs/intermezzo/vfs.c
--- linux-2.5.2-pre11/fs/intermezzo/vfs.c	Tue Nov 13 09:20:56 2001
+++ linux/fs/intermezzo/vfs.c	Mon Jan 14 18:28:31 2002
@@ -136,7 +136,7 @@
         if (errorval && errorval == (long)value && !is_read_only(dev)) {
                 CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));
                 BLKDEV_FAIL(dev, 1);
-                upc_comms[minor].uc_errorval = -dev;
+                upc_comms[minor].uc_errorval = -kdev_val(dev);
         }
 }
 #else
@@ -602,7 +602,7 @@
                 goto exit_lock;
 
         error = -EXDEV;
-        if (dir->d_inode->i_dev != inode->i_dev)
+        if (!kdev_same(dir->d_inode->i_dev, inode->i_dev))
                 goto exit_lock;
 
         /*
@@ -1609,7 +1609,7 @@
         if (error)
                 return error;
 
-        if (new_dir->i_dev != old_dir->i_dev)
+        if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
@@ -1690,7 +1690,7 @@
         if (error)
                 return error;
 
-        if (new_dir->i_dev != old_dir->i_dev)
+        if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
diff -urN linux-2.5.2-pre11/fs/jbd/journal.c linux/fs/jbd/journal.c
--- linux-2.5.2-pre11/fs/jbd/journal.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jbd/journal.c	Mon Jan 14 18:28:31 2002
@@ -475,6 +475,7 @@
 
 	new_jh->b_transaction = NULL;
 	new_bh->b_size = jh2bh(jh_in)->b_size;
+	new_bh->b_bdev = transaction->t_journal->j_dev;
 	new_bh->b_dev = to_kdev_t(transaction->t_journal->j_dev->bd_dev);
 	new_bh->b_blocknr = blocknr;
 	new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty);
diff -urN linux-2.5.2-pre11/fs/jbd/revoke.c linux/fs/jbd/revoke.c
--- linux-2.5.2-pre11/fs/jbd/revoke.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jbd/revoke.c	Mon Jan 14 18:28:31 2002
@@ -278,7 +278,7 @@
 {
 	struct buffer_head *bh = NULL;
 	journal_t *journal;
-	kdev_t dev;
+	struct block_device *bdev;
 	int err;
 
 	if (bh_in)
@@ -290,11 +290,11 @@
 		return -EINVAL;
 	}
 
-	dev = to_kdev_t(journal->j_fs_dev->bd_dev);
+	bdev = journal->j_fs_dev;
 	bh = bh_in;
 
 	if (!bh) {
-		bh = get_hash_table(dev, blocknr, journal->j_blocksize);
+		bh = __get_hash_table(bdev, blocknr, journal->j_blocksize);
 		if (bh)
 			BUFFER_TRACE(bh, "found on hash");
 	}
@@ -304,7 +304,7 @@
 
 		/* If there is a different buffer_head lying around in
 		 * memory anywhere... */
-		bh2 = get_hash_table(dev, blocknr, journal->j_blocksize);
+		bh2 = __get_hash_table(bdev, blocknr, journal->j_blocksize);
 		if (bh2) {
 			/* ... and it has RevokeValid status... */
 			if ((bh2 != bh) &&
@@ -408,7 +408,7 @@
 	 * state machine will get very upset later on. */
 	if (need_cancel && !bh->b_pprev) {
 		struct buffer_head *bh2;
-		bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+		bh2 = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
 		if (bh2) {
 			clear_bit(BH_Revoked, &bh2->b_state);
 			__brelse(bh2);
diff -urN linux-2.5.2-pre11/fs/jbd/transaction.c linux/fs/jbd/transaction.c
--- linux-2.5.2-pre11/fs/jbd/transaction.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jbd/transaction.c	Mon Jan 14 18:28:31 2002
@@ -1864,6 +1864,7 @@
 	clear_bit(BH_Mapped, &bh->b_state);
 	clear_bit(BH_Req, &bh->b_state);
 	clear_bit(BH_New, &bh->b_state);
+	bh->b_bdev = NULL;
 	return may_free;
 }
 
diff -urN linux-2.5.2-pre11/fs/jffs2/Makefile linux/fs/jffs2/Makefile
--- linux-2.5.2-pre11/fs/jffs2/Makefile	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/Makefile	Mon Jan 14 18:28:31 2002
@@ -12,7 +12,7 @@
 
 COMPR_OBJS	:= compr.o compr_rubin.o compr_rtime.o pushpull.o \
 			compr_zlib.o zlib.o
-JFFS2_OBJS	:= crc32.o dir.o file.o ioctl.o nodelist.o malloc.o \
+JFFS2_OBJS	:= dir.o file.o ioctl.o nodelist.o malloc.o \
 	read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
 	symlink.o build.o erase.o background.o
 
diff -urN linux-2.5.2-pre11/fs/jffs2/crc32.c linux/fs/jffs2/crc32.c
--- linux-2.5.2-pre11/fs/jffs2/crc32.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/crc32.c	Wed Dec 31 16:00:00 1969
@@ -1,97 +0,0 @@
-/*
- *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
- *  code or tables extracted from it, as desired without restriction.
- *
- *  First, the polynomial itself and its table of feedback terms.  The
- *  polynomial is
- *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
- *
- *  Note that we take it "backwards" and put the highest-order term in
- *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
- *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
- *  the MSB being 1
- *
- *  Note that the usual hardware shift register implementation, which
- *  is what we're using (we're merely optimizing it by doing eight-bit
- *  chunks at a time) shifts bits into the lowest-order term.  In our
- *  implementation, that means shifting towards the right.  Why do we
- *  do it this way?  Because the calculated CRC must be transmitted in
- *  order from highest-order term to lowest-order term.  UARTs transmit
- *  characters in order from LSB to MSB.  By storing the CRC this way
- *  we hand it to the UART in the order low-byte to high-byte; the UART
- *  sends each low-bit to hight-bit; and the result is transmission bit
- *  by bit from highest- to lowest-order term without requiring any bit
- *  shuffling on our part.  Reception works similarly
- *
- *  The feedback terms table consists of 256, 32-bit entries.  Notes
- *
- *      The table can be generated at runtime if desired; code to do so
- *      is shown later.  It might not be obvious, but the feedback
- *      terms simply represent the results of eight shift/xor opera
- *      tions for all combinations of data and CRC register values
- *
- *      The values must be right-shifted by eight bits by the "updcrc
- *      logic; the shift must be unsigned (bring in zeroes).  On some
- *      hardware you could probably optimize the shift in assembler by
- *      using byte-swap instructions
- *      polynomial $edb88320
- */
-
-/* $Id: crc32.c,v 1.3 2001/02/07 16:45:32 dwmw2 Exp $ */
-
-#include "crc32.h"
-
-const __u32 crc32_table[256] = {
-	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
-	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
-	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
-	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
-	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
-	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
-	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
-	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
-	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
-	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
-	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
-	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
-	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
-	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
-	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
-	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
-	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
-	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
-	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
-	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
-	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
-	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
-	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
-	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
-	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
-	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
-	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
-	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
-	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
-	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
-	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
-	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
-	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
-	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
-	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
-	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
-	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
-	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
-	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
-	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
-	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
-	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
-	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
-	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
-	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
-	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
-	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
-	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
-	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
-	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
-	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
-	0x2d02ef8dL
-};
diff -urN linux-2.5.2-pre11/fs/jffs2/crc32.h linux/fs/jffs2/crc32.h
--- linux-2.5.2-pre11/fs/jffs2/crc32.h	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/crc32.h	Wed Dec 31 16:00:00 1969
@@ -1,21 +0,0 @@
-#ifndef CRC32_H
-#define CRC32_H
-
-/* $Id: crc32.h,v 1.3 2001/02/26 14:44:37 dwmw2 Exp $ */
-
-#include <linux/types.h>
-
-extern const __u32 crc32_table[256];
-
-/* Return a 32-bit CRC of the contents of the buffer. */
-
-static inline __u32 
-crc32(__u32 val, const void *ss, int len)
-{
-	const unsigned char *s = ss;
-        while (--len >= 0)
-                val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
-        return val;
-}
-
-#endif
diff -urN linux-2.5.2-pre11/fs/jffs2/dir.c linux/fs/jffs2/dir.c
--- linux-2.5.2-pre11/fs/jffs2/dir.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jffs2/dir.c	Mon Jan 14 18:28:31 2002
@@ -38,11 +38,11 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
+#include <linux/crc32.h>
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/jffs2_fs_sb.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 static int jffs2_readdir (struct file *, void *, filldir_t);
 
diff -urN linux-2.5.2-pre11/fs/jffs2/erase.c linux/fs/jffs2/erase.c
--- linux-2.5.2-pre11/fs/jffs2/erase.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/erase.c	Mon Jan 14 18:28:31 2002
@@ -39,8 +39,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/jffs2.h>
 #include <linux/interrupt.h>
+#include <linux/crc32.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 struct erase_priv_struct {
 	struct jffs2_eraseblock *jeb;
diff -urN linux-2.5.2-pre11/fs/jffs2/file.c linux/fs/jffs2/file.c
--- linux-2.5.2-pre11/fs/jffs2/file.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jffs2/file.c	Mon Jan 14 18:28:31 2002
@@ -40,9 +40,9 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/crc32.h>
 #include <linux/jffs2.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
diff -urN linux-2.5.2-pre11/fs/jffs2/gc.c linux/fs/jffs2/gc.c
--- linux-2.5.2-pre11/fs/jffs2/gc.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jffs2/gc.c	Mon Jan 14 18:28:31 2002
@@ -42,8 +42,8 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/pagemap.h>
+#include <linux/crc32.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
 					struct inode *inode, struct jffs2_full_dnode *fd);
diff -urN linux-2.5.2-pre11/fs/jffs2/read.c linux/fs/jffs2/read.c
--- linux-2.5.2-pre11/fs/jffs2/read.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/read.c	Mon Jan 14 18:28:31 2002
@@ -37,10 +37,10 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/crc32.h>
 #include <linux/jffs2.h>
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
 {
diff -urN linux-2.5.2-pre11/fs/jffs2/readinode.c linux/fs/jffs2/readinode.c
--- linux-2.5.2-pre11/fs/jffs2/readinode.c	Fri Sep 14 14:04:07 2001
+++ linux/fs/jffs2/readinode.c	Mon Jan 14 18:28:31 2002
@@ -41,10 +41,10 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
+#include <linux/crc32.h>
 #include <linux/mtd/mtd.h>
 #include <linux/jffs2.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 
 D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
diff -urN linux-2.5.2-pre11/fs/jffs2/scan.c linux/fs/jffs2/scan.c
--- linux-2.5.2-pre11/fs/jffs2/scan.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/scan.c	Mon Jan 14 18:28:31 2002
@@ -39,8 +39,8 @@
 #include <linux/jffs2.h>
 #include <linux/mtd/mtd.h>
 #include <linux/pagemap.h>
+#include <linux/crc32.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 
 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
diff -urN linux-2.5.2-pre11/fs/jffs2/write.c linux/fs/jffs2/write.c
--- linux-2.5.2-pre11/fs/jffs2/write.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/jffs2/write.c	Mon Jan 14 18:28:31 2002
@@ -37,10 +37,10 @@
 
 #include <linux/kernel.h>
 #include <linux/fs.h>
+#include <linux/crc32.h>
 #include <linux/jffs2.h>
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
-#include "crc32.h"
 
 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
    fill in the raw_inode while you're at it. */
diff -urN linux-2.5.2-pre11/fs/namei.c linux/fs/namei.c
--- linux-2.5.2-pre11/fs/namei.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/namei.c	Mon Jan 14 18:28:31 2002
@@ -99,16 +99,17 @@
  * kernel data space before using them..
  *
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
+ * PATH_MAX includes the nul terminator --RR.
  */
 static inline int do_getname(const char *filename, char *page)
 {
 	int retval;
-	unsigned long len = PATH_MAX + 1;
+	unsigned long len = PATH_MAX;
 
 	if ((unsigned long) filename >= TASK_SIZE) {
 		if (!segment_eq(get_fs(), KERNEL_DS))
 			return -EFAULT;
-	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX + 1)
+	} else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
 		len = TASK_SIZE - (unsigned long) filename;
 
 	retval = strncpy_from_user((char *)page, filename, len);
diff -urN linux-2.5.2-pre11/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c
--- linux-2.5.2-pre11/fs/openpromfs/inode.c	Sun Nov 11 10:13:25 2001
+++ linux/fs/openpromfs/inode.c	Mon Jan 14 18:28:31 2002
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.14 2001/02/13 01:17:17 davem Exp $
+/* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
diff -urN linux-2.5.2-pre11/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- linux-2.5.2-pre11/fs/partitions/msdos.c	Thu Oct 11 08:07:07 2001
+++ linux/fs/partitions/msdos.c	Mon Jan 14 18:28:31 2002
@@ -166,7 +166,7 @@
 			add_gd_partition(hd, *current_minor, next, size);
 #if CONFIG_BLK_DEV_MD
 			if (SYS_IND(p) == LINUX_RAID_PARTITION) {
-			    md_autodetect_dev(MKDEV(hd->major,*current_minor));
+			    md_autodetect_dev(mk_kdev(hd->major,*current_minor));
 			}
 #endif
 
@@ -580,7 +580,7 @@
 				NR_SECTS(p)*sector_size);
 #if CONFIG_BLK_DEV_MD
 		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
-			md_autodetect_dev(MKDEV(hd->major,minor));
+			md_autodetect_dev(mk_kdev(hd->major,minor));
 		}
 #endif
 		if (is_extended_partition(p)) {
diff -urN linux-2.5.2-pre11/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- linux-2.5.2-pre11/fs/reiserfs/bitmap.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/reiserfs/bitmap.c	Mon Jan 14 18:28:31 2002
@@ -168,7 +168,7 @@
       block_to_try = (i * (s->s_blocksize << 3)) + j; 
 
       /* the block is not in the journal, we can proceed */
-      if (!(reiserfs_in_journal(s, s->s_dev, block_to_try, s->s_blocksize, for_unformatted, &next_block_to_try))) {
+      if (!(reiserfs_in_journal(s, block_to_try, for_unformatted, &next_block_to_try))) {
 	*bmap_nr = i;
 	*offset = j;
 	return 1;
diff -urN linux-2.5.2-pre11/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- linux-2.5.2-pre11/fs/reiserfs/journal.c	Mon Jan 14 18:28:24 2002
+++ linux/fs/reiserfs/journal.c	Mon Jan 14 18:28:31 2002
@@ -414,12 +414,15 @@
 }
 
 /* return a cnode with same dev, block number and size in table, or null if not found */
-static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserfs_journal_cnode **table,
-                                   				  kdev_t dev,long bl,int size) {
+static inline struct reiserfs_journal_cnode *
+get_journal_hash_dev(struct super_block *sb,
+		     struct reiserfs_journal_cnode **table,
+		     long bl)
+{
   struct reiserfs_journal_cnode *cn ;
-  cn = journal_hash(table, dev, bl) ;
+  cn = journal_hash(table, sb, bl) ;
   while(cn) {
-    if ((cn->blocknr == bl) && (kdev_same(cn->dev, dev)))
+    if (cn->blocknr == bl && cn->sb == sb)
       return cn ;
     cn = cn->hnext ;
   }
@@ -430,7 +433,7 @@
 static inline struct reiserfs_journal_cnode *get_journal_hash(struct super_block *p_s_sb, struct buffer_head *bh) {
   struct reiserfs_journal_cnode *cn ;
   if (bh) {
-    cn =  get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_dev, bh->b_blocknr, bh->b_size) ;
+    cn =  get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_blocknr);
   }
   else {
     return (struct reiserfs_journal_cnode *)0 ;
@@ -502,8 +505,8 @@
 ** reject it on the next call to reiserfs_in_journal
 **
 */
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, 
-                        unsigned long bl, int size, int search_all, 
+int reiserfs_in_journal(struct super_block *p_s_sb,
+                        unsigned long bl, int search_all, 
 			unsigned long *next_zero_bit) {
   struct reiserfs_journal_cnode *cn ;
   struct reiserfs_list_bitmap *jb ;
@@ -540,12 +543,12 @@
   }
 
   /* is it in any old transactions? */
-  if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {
+  if (search_all && (cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bl))) {
     return 1; 
   }
 
   /* is it in the current transaction.  This should never happen */
-  if ((cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, dev,bl,size))) {
+  if ((cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, bl))) {
     return 1; 
   }
 
@@ -559,13 +562,13 @@
 inline void insert_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_cnode *cn) {
   struct reiserfs_journal_cnode *cn_orig ;
 
-  cn_orig = journal_hash(table, cn->dev, cn->blocknr) ;
+  cn_orig = journal_hash(table, cn->sb, cn->blocknr) ;
   cn->hnext = cn_orig ;
   cn->hprev = NULL ;
   if (cn_orig) {
     cn_orig->hprev = cn ;
   }
-  journal_hash(table, cn->dev, cn->blocknr) =  cn ;
+  journal_hash(table, cn->sb, cn->blocknr) =  cn ;
 }
 
 /* lock the current transaction */
@@ -760,12 +763,12 @@
 ** returns NULL if it can't find anything 
 */
 static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journal_cnode *cn) {
-  kdev_t dev = cn->dev;
+  struct super_block *sb = cn->sb;
   unsigned long blocknr = cn->blocknr ;
 
   cn = cn->hprev ;
   while(cn) {
-    if (kdev_same(cn->dev, dev) && cn->blocknr == blocknr && cn->jlist) {
+    if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist) {
       return cn->jlist ;
     }
     cn = cn->hprev ;
@@ -773,6 +776,8 @@
   return NULL ;
 }
 
+void remove_journal_hash(struct super_block *, struct reiserfs_journal_cnode **,
+struct reiserfs_journal_list *, unsigned long, int);
 
 /*
 ** once all the real blocks have been flushed, it is safe to remove them from the
@@ -780,12 +785,11 @@
 ** block to be reallocated for data blocks if it had been deleted.
 */
 static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl, int debug) {
-  struct buffer_head fake_bh ;
   struct reiserfs_journal_cnode *cn, *last ;
   cn = jl->j_realblock ;
 
   /* which is better, to lock once around the whole loop, or
-  ** to lock for each call to remove_from_journal_list?
+  ** to lock for each call to remove_journal_hash?
   */
   while(cn) {
     if (cn->blocknr != 0) {
@@ -793,10 +797,8 @@
         printk("block %lu, bh is %d, state %d\n", cn->blocknr, cn->bh ? 1: 0, 
 	        cn->state) ;
       }
-      fake_bh.b_blocknr = cn->blocknr ;
-      fake_bh.b_dev = cn->dev ;
       cn->state = 0 ;
-      remove_from_journal_list(p_s_sb, jl, &fake_bh, 1) ;
+      remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, jl, cn->blocknr, 1) ;
     }
     last = cn ;
     cn = cn->next ;
@@ -1178,7 +1180,7 @@
                 mark_buffer_notjournal_dirty(cn->bh) ;
                 while(walk_cn) {
                     if (walk_cn->bh && walk_cn->blocknr == blocknr && 
-                         kdev_same(walk_cn->dev, cn->dev)) {
+                         walk_cn->sb == cn->sb) {
                         if (walk_cn->jlist) {
                             atomic_dec(&(walk_cn->jlist->j_nonzerolen)) ;
                         }
@@ -1267,21 +1269,21 @@
 ** removes any nodes in table with name block and dev as bh.
 ** only touchs the hnext and hprev pointers.
 */
-void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_list *jl,struct buffer_head *bh,
-                         int remove_freed){
+void remove_journal_hash(struct super_block *sb,
+			struct reiserfs_journal_cnode **table,
+			struct reiserfs_journal_list *jl,
+			unsigned long block, int remove_freed)
+{
   struct reiserfs_journal_cnode *cur ;
   struct reiserfs_journal_cnode **head ;
 
-  if (!bh)
-    return ;
-
-  head= &(journal_hash(table, bh->b_dev, bh->b_blocknr)) ;
+  head= &(journal_hash(table, sb, block)) ;
   if (!head) {
     return ;
   }
   cur = *head ;
   while(cur) {
-    if (cur->blocknr == bh->b_blocknr && kdev_same(cur->dev, bh->b_dev) && (jl == NULL || jl == cur->jlist) && 
+    if (cur->blocknr == block && cur->sb == sb && (jl == NULL || jl == cur->jlist) && 
         (!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) {
       if (cur->hnext) {
         cur->hnext->hprev = cur->hprev ;
@@ -1292,7 +1294,7 @@
 	*head = cur->hnext ;
       }
       cur->blocknr = 0 ;
-      cur->dev = NODEV ;
+      cur->sb = NULL ;
       cur->state = 0 ;
       if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */
 	atomic_dec(&(cur->jlist->j_nonzerolen)) ;
@@ -2184,7 +2186,7 @@
 
     cn->bh = bh ;
     cn->blocknr = bh->b_blocknr ;
-    cn->dev = bh->b_dev ;
+    cn->sb = p_s_sb;
     cn->jlist = NULL ;
     insert_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, cn) ;
     if (!count_already_incd) {
@@ -2215,7 +2217,7 @@
       buffer_journal_dirty(bh)) {
     return journal_mark_dirty(th, p_s_sb, bh) ;
   }
-  if (get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_dev,bh->b_blocknr,bh->b_size)) {
+  if (get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_blocknr)) {
     return journal_mark_dirty(th, p_s_sb, bh) ;
   }
   mark_buffer_dirty(bh) ;
@@ -2238,7 +2240,7 @@
   struct reiserfs_journal_cnode *cn ;
   int ret = 0;
 
-  cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+  cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, blocknr) ;
   if (!cn || !cn->bh) {
     return ret ;
   }
@@ -2255,7 +2257,8 @@
   if (cn == SB_JOURNAL(p_s_sb)->j_last) {
     SB_JOURNAL(p_s_sb)->j_last = cn->prev ;
   }
-  remove_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh, 0) ; 
+  if (bh)
+	remove_journal_hash(p_s_sb, SB_JOURNAL(p_s_sb)->j_hash_table, NULL, bh->b_blocknr, 0) ; 
   mark_buffer_not_journaled(bh) ; /* don't log this one */
 
   if (!already_cleaned) {
@@ -2273,12 +2276,6 @@
   return ret ;
 }
 
-/* removes from a specific journal list hash */
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
-  remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ;
-  return 0 ;
-}
-
 /*
 ** for any cnode in a journal list, it can only be dirtied of all the
 ** transactions that include it are commited to disk.
@@ -2290,7 +2287,7 @@
 **
 */
 static int can_dirty(struct reiserfs_journal_cnode *cn) {
-  kdev_t dev = cn->dev ;
+  struct super_block *sb = cn->sb;
   unsigned long blocknr = cn->blocknr  ;
   struct reiserfs_journal_cnode *cur = cn->hprev ;
   int can_dirty = 1 ;
@@ -2300,7 +2297,7 @@
   ** to disk right now.
   */
   while(cur && can_dirty) {
-    if (cur->jlist && cur->bh && cur->blocknr && kdev_same(cur->dev, dev) && 
+    if (cur->jlist && cur->bh && cur->blocknr && cur->sb == sb && 
         cur->blocknr == blocknr) {
       can_dirty = 0 ;
     }
@@ -2313,7 +2310,7 @@
   while(cur && can_dirty) {
     if (cur->jlist && cur->jlist->j_len > 0 && 
         atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh && 
-        cur->blocknr && kdev_same(cur->dev, dev) && cur->blocknr == blocknr) {
+        cur->blocknr && cur->sb == sb && cur->blocknr == blocknr) {
       can_dirty = 0 ;
     }
     cur = cur->hnext ;
@@ -2578,9 +2575,9 @@
     cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
 
     /* find all older transactions with this block, make sure they don't try to write it out */
-    cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ;
+    cn = get_journal_hash_dev(p_s_sb,SB_JOURNAL(p_s_sb)->j_list_hash_table,  blocknr) ;
     while (cn) {
-      if (kdev_same(p_s_sb->s_dev, cn->dev) && blocknr == cn->blocknr) {
+      if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
 	set_bit(BLOCK_FREED, &cn->state) ;
 	if (cn->bh) {
 	  if (!cleaned) {
@@ -2821,7 +2818,7 @@
       }
       jl_cn->blocknr = cn->bh->b_blocknr ; 
       jl_cn->state = 0 ;
-      jl_cn->dev = cn->bh->b_dev ; 
+      jl_cn->sb = p_s_sb ;
       jl_cn->bh = cn->bh ;
       jl_cn->jlist = SB_JOURNAL_LIST(p_s_sb) + SB_JOURNAL_LIST_INDEX(p_s_sb) ;
       insert_journal_hash(SB_JOURNAL(p_s_sb)->j_list_hash_table, jl_cn) ; 
diff -urN linux-2.5.2-pre11/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- linux-2.5.2-pre11/fs/reiserfs/tail_conversion.c	Tue Oct 30 15:11:34 2001
+++ linux/fs/reiserfs/tail_conversion.c	Mon Jan 14 18:28:31 2002
@@ -142,6 +142,7 @@
     clear_bit(BH_Mapped, &bh->b_state) ;
     clear_bit(BH_Req, &bh->b_state) ;
     clear_bit(BH_New, &bh->b_state) ;
+    bh->b_bdev = NULL;
     unlock_buffer(bh) ;
   }
 }
diff -urN linux-2.5.2-pre11/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- linux-2.5.2-pre11/include/asm-sparc/bitops.h	Tue Oct 30 15:08:11 2001
+++ linux/include/asm-sparc/bitops.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.65 2001/10/30 04:08:26 davem Exp $
+/* $Id: bitops.h,v 1.67 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.5.2-pre11/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- linux-2.5.2-pre11/include/asm-sparc/io.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc/io.h	Mon Jan 14 18:28:32 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: io.h,v 1.29 2001/11/10 09:28:34 davem Exp $
+ * $Id: io.h,v 1.30 2001/12/21 01:23:21 davem Exp $
  */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
@@ -11,8 +11,7 @@
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
 
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 
 static __inline__ u32 flip_dword (u32 d)
 {
diff -urN linux-2.5.2-pre11/include/asm-sparc/keyboard.h linux/include/asm-sparc/keyboard.h
--- linux-2.5.2-pre11/include/asm-sparc/keyboard.h	Mon Jan 14 18:28:25 2002
+++ linux/include/asm-sparc/keyboard.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: keyboard.h,v 1.7 2001/08/18 09:40:46 davem Exp $
+/* $Id: keyboard.h,v 1.8 2002/01/08 16:00:20 davem Exp $
  * linux/include/asm-sparc/keyboard.h
  *
  * sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
diff -urN linux-2.5.2-pre11/include/asm-sparc/mmu_context.h linux/include/asm-sparc/mmu_context.h
--- linux-2.5.2-pre11/include/asm-sparc/mmu_context.h	Thu Aug 10 13:30:05 2000
+++ linux/include/asm-sparc/mmu_context.h	Mon Jan 14 18:28:32 2002
@@ -5,6 +5,29 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be clear. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+
+static inline int sched_find_first_zero_bit(unsigned long *b)
+{
+	unsigned int rt;
+
+	rt = b[0] & b[1] & b[2] & b[3];
+	if (unlikely(rt != 0xffffffff))
+		return find_first_zero_bit(b, MAX_RT_PRIO);
+
+	if (b[4] != ~0)
+		return ffz(b[4]) + MAX_RT_PRIO;
+	return ffz(b[5]) + 32 + MAX_RT_PRIO;
+}
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
diff -urN linux-2.5.2-pre11/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h
--- linux-2.5.2-pre11/include/asm-sparc/oplib.h	Mon Aug 28 21:20:03 2000
+++ linux/include/asm-sparc/oplib.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.21 2000/08/26 02:38:04 anton Exp $
+/* $Id: oplib.h,v 1.23 2001/12/21 00:54:31 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -298,15 +298,7 @@
 
 /* Dorking with Bus ranges... */
 
-/* Adjust reg values with the passed ranges. */
-extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
-			     struct linux_prom_ranges *rangep, int nranges);
-
-/* Adjust child ranges with the passed parent ranges. */
-extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
-			       struct linux_prom_ranges *pranges, int npranges);
-
-/* Apply promlib probed OBIO ranges to registers. */
+/* Apply promlib probes OBIO ranges to registers. */
 extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
 
 /* Apply ranges of any prom node (and optionally parent node as well) to registers. */
diff -urN linux-2.5.2-pre11/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- linux-2.5.2-pre11/include/asm-sparc/pci.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc/pci.h	Mon Jan 14 18:28:32 2002
@@ -26,6 +26,7 @@
 
 /* Dynamic DMA mapping stuff.
  */
+#define PCI_DMA_BUS_IS_PHYS	(0)
 
 #include <asm/scatterlist.h>
 
diff -urN linux-2.5.2-pre11/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- linux-2.5.2-pre11/include/asm-sparc/smp.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc/smp.h	Mon Jan 14 18:28:32 2002
@@ -190,8 +190,6 @@
 #define MBOX_IDLECPU2         0xFD
 #define MBOX_STOPCPU2         0xFE
 
-#define PROC_CHANGE_PENALTY     15
-
 #endif /* !(CONFIG_SMP) */
 
 #define NO_PROC_ID            0xFF
diff -urN linux-2.5.2-pre11/include/asm-sparc/smplock.h linux/include/asm-sparc/smplock.h
--- linux-2.5.2-pre11/include/asm-sparc/smplock.h	Thu Mar 23 12:50:09 2000
+++ linux/include/asm-sparc/smplock.h	Mon Jan 14 18:28:32 2002
@@ -3,31 +3,35 @@
  *
  * Default SMP lock implementation
  */
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
-#define kernel_locked()		spin_is_locked(&kernel_flag)
+#define kernel_locked()			\
+	(spin_is_locked(&kernel_flag) &&\
+	 (current->lock_depth >= 0))
 
 /*
  * Release global kernel lock and global interrupt lock
  */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
+#define release_kernel_lock(task, cpu)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0)) {	\
+		spin_unlock(&kernel_flag);	\
+		release_irqlock(cpu);		\
+		__sti();			\
+	}					\
 } while (0)
 
 /*
  * Re-acquire the kernel lock
  */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
+#define reacquire_kernel_lock(task)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0))	\
+		spin_lock(&kernel_flag);	\
 } while (0)
 
 
@@ -38,14 +42,14 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
-{
-	if (!++current->lock_depth)
-		spin_lock(&kernel_flag);
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	if (--current->lock_depth < 0)
-		spin_unlock(&kernel_flag);
-}
+#define lock_kernel()				\
+do {						\
+	if (!++current->lock_depth)		\
+		spin_lock(&kernel_flag);	\
+} while(0)
+
+#define unlock_kernel()				\
+do {						\
+	if (--current->lock_depth < 0)		\
+		spin_unlock(&kernel_flag);	\
+} while(0)
diff -urN linux-2.5.2-pre11/include/asm-sparc/string.h linux/include/asm-sparc/string.h
--- linux-2.5.2-pre11/include/asm-sparc/string.h	Wed May  3 01:47:57 2000
+++ linux/include/asm-sparc/string.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.35 2000/05/02 01:47:01 davem Exp $
+/* $Id: string.h,v 1.36 2001/12/21 00:54:31 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -126,9 +126,11 @@
 })
 
 #define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *,const void *,__kernel_size_t);
 
 /* Now the str*() stuff... */
 #define __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
 
 #define __HAVE_ARCH_STRNCMP
 
diff -urN linux-2.5.2-pre11/include/asm-sparc/types.h linux/include/asm-sparc/types.h
--- linux-2.5.2-pre11/include/asm-sparc/types.h	Mon Jan 31 23:37:19 2000
+++ linux/include/asm-sparc/types.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: types.h,v 1.12 2000/01/29 02:23:25 anton Exp $ */
+/* $Id: types.h,v 1.13 2001/12/21 01:22:59 davem Exp $ */
 #ifndef _SPARC_TYPES_H
 #define _SPARC_TYPES_H
 
@@ -46,6 +46,7 @@
 #define BITS_PER_LONG 32
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- linux-2.5.2-pre11/include/asm-sparc64/bitops.h	Wed Jun 20 21:00:55 2001
+++ linux/include/asm-sparc64/bitops.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.36 2001/06/14 12:34:49 davem Exp $
+/* $Id: bitops.h,v 1.38 2001/11/19 18:36:34 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,9 +13,9 @@
 extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
 extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
 
-#define test_and_set_bit(nr,addr)	(___test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr)	(___test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr)	(___test_and_change_bit(nr,addr)!=0)
+#define test_and_set_bit(nr,addr)	({___test_and_set_bit(nr,addr)!=0;})
+#define test_and_clear_bit(nr,addr)	({___test_and_clear_bit(nr,addr)!=0;})
+#define test_and_change_bit(nr,addr)	({___test_and_change_bit(nr,addr)!=0;})
 #define set_bit(nr,addr)		((void)___test_and_set_bit(nr,addr))
 #define clear_bit(nr,addr)		((void)___test_and_clear_bit(nr,addr))
 #define change_bit(nr,addr)		((void)___test_and_change_bit(nr,addr))
@@ -214,8 +214,8 @@
 extern long ___test_and_set_le_bit(int nr, volatile void *addr);
 extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
 
-#define test_and_set_le_bit(nr,addr)	(___test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr)	(___test_and_clear_le_bit(nr,addr)!=0)
+#define test_and_set_le_bit(nr,addr)	({___test_and_set_le_bit(nr,addr)!=0;})
+#define test_and_clear_le_bit(nr,addr)	({___test_and_clear_le_bit(nr,addr)!=0;})
 #define set_le_bit(nr,addr)		((void)___test_and_set_le_bit(nr,addr))
 #define clear_le_bit(nr,addr)		((void)___test_and_clear_le_bit(nr,addr))
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- linux-2.5.2-pre11/include/asm-sparc64/elf.h	Fri Sep  7 11:01:20 2001
+++ linux/include/asm-sparc64/elf.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.30 2001/08/30 23:35:38 kanoj Exp $ */
+/* $Id: elf.h,v 1.31 2002/01/08 16:00:20 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -75,24 +75,7 @@
 	else						\
 		flags &= ~SPARC_FLAG_32BIT;		\
 	if (flags != current->thread.flags) {		\
-		unsigned long pgd_cache = 0UL;		\
-		if (flags & SPARC_FLAG_32BIT) {		\
-		  pgd_t *pgd0 = &current->mm->pgd[0];	\
-		  if (pgd_none (*pgd0)) {		\
-		    pmd_t *page = pmd_alloc_one_fast(NULL, 0);	\
-		    if (!page)				\
-		      page = pmd_alloc_one(NULL, 0);	\
-                    pgd_set(pgd0, page);		\
-		  }					\
-		  pgd_cache = pgd_val(*pgd0) << 11UL;	\
-		}					\
-		__asm__ __volatile__(			\
-			"stxa\t%0, [%1] %2\n\t"		\
-			"membar #Sync"			\
-			: /* no outputs */		\
-			: "r" (pgd_cache),		\
-			  "r" (TSB_REG),		\
-			  "i" (ASI_DMMU));		\
+		/* flush_thread will update pgd cache */\
 		current->thread.flags = flags;		\
 	}						\
 							\
diff -urN linux-2.5.2-pre11/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- linux-2.5.2-pre11/include/asm-sparc64/io.h	Sun Dec 16 12:20:21 2001
+++ linux/include/asm-sparc64/io.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.46 2001/12/13 04:16:52 davem Exp $ */
+/* $Id: io.h,v 1.47 2001/12/13 10:36:02 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/keyboard.h linux/include/asm-sparc64/keyboard.h
--- linux-2.5.2-pre11/include/asm-sparc64/keyboard.h	Mon Jan 14 18:28:25 2002
+++ linux/include/asm-sparc64/keyboard.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: keyboard.h,v 1.5 2001/08/18 09:40:46 davem Exp $
+/* $Id: keyboard.h,v 1.6 2002/01/08 16:00:20 davem Exp $
  * linux/include/asm-sparc64/keyboard.h
  *
  * Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
diff -urN linux-2.5.2-pre11/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- linux-2.5.2-pre11/include/asm-sparc64/mmu_context.h	Tue Aug 28 07:09:44 2001
+++ linux/include/asm-sparc64/mmu_context.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.51 2001/08/17 04:55:09 kanoj Exp $ */
+/* $Id: mmu_context.h,v 1.52 2002/01/11 08:45:38 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -26,6 +26,27 @@
 #include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be clear. It's guaranteed that at least one of the 168
+ * bits is cleared.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
+# error update this function.
+#endif
+
+static inline int sched_find_first_zero_bit(unsigned long *b)
+{
+	unsigned long rt;
+
+	rt = b[0] & b[1];
+	if (unlikely(rt != 0xffffffffffffffff))
+		return find_first_zero_bit(b, MAX_RT_PRIO);
+
+	return ffz(b[2]) + MAX_RT_PRIO;
+}
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
diff -urN linux-2.5.2-pre11/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- linux-2.5.2-pre11/include/asm-sparc64/oplib.h	Mon May 22 09:50:54 2000
+++ linux/include/asm-sparc64/oplib.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.13 2000/05/09 17:40:15 davem Exp $
+/* $Id: oplib.h,v 1.14 2001/12/19 00:29:51 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -326,20 +326,6 @@
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
 
-/* Dorking with Bus ranges... */
-
-/* Adjust reg values with the passed ranges. */
-extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
-			     struct linux_prom_ranges *rangep, int nranges);
-
-/* Adjust child ranges with the passed parent ranges. */
-extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
-			       struct linux_prom_ranges *pranges, int npranges);
-
-/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent, 
-				      struct linux_prom_registers *sbusregs, int nregs);
-				      
 extern long p1275_cmd (char *, long, ...);
 				   
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- linux-2.5.2-pre11/include/asm-sparc64/page.h	Thu Aug 10 12:43:12 2000
+++ linux/include/asm-sparc64/page.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.36 2000/08/10 01:04:53 davem Exp $ */
+/* $Id: page.h,v 1.38 2001/11/30 01:04:10 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -18,13 +18,20 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
+#define BUG() do {					\
+	do_BUG(__FILE__, __LINE__);			\
+	__builtin_trap();				\
+} while (0)
+#else
 #define BUG()		__builtin_trap()
+#endif
+
 #define PAGE_BUG(page)	BUG()
 
 extern void _clear_page(void *page);
-extern void _copy_page(void *to, void *from);
 #define clear_page(X)	_clear_page((void *)(X))
-#define copy_page(X,Y)	_copy_page((void *)(X), (void *)(Y))
 extern void clear_user_page(void *page, unsigned long vaddr);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- linux-2.5.2-pre11/include/asm-sparc64/processor.h	Wed Oct 10 23:42:47 2001
+++ linux/include/asm-sparc64/processor.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $
+/* $Id: processor.h,v 1.80 2001/11/17 00:10:48 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -66,6 +66,15 @@
 	unsigned long gsr[7];
 	unsigned long xfsr[7];
 
+#ifdef CONFIG_DEBUG_SPINLOCK
+	/* How many spinlocks held by this thread.
+	 * Used with spin lock debugging to catch tasks
+	 * sleeping illegally with locks held.
+	 */
+	int smp_lock_count;
+	unsigned int smp_lock_pc;
+#endif
+
 	struct reg_window reg_window[NSWINS];
 	unsigned long rwbuf_stkptrs[NSWINS];
 	
@@ -88,6 +97,7 @@
 #define FAULT_CODE_ITLB		0x04	/* Miss happened in I-TLB		*/
 #define FAULT_CODE_WINFIXUP	0x08	/* Miss happened during spill/fill	*/
 
+#ifndef CONFIG_DEBUG_SPINLOCK
 #define INIT_THREAD  {					\
 /* ksp, wstate, cwp, flags, current_ds, */ 		\
    0,   0,      0,   0,     KERNEL_DS,			\
@@ -104,6 +114,24 @@
 /* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
    0,          0,          0,		 0,            0, \
 }
+#else /* CONFIG_DEBUG_SPINLOCK */
+#define INIT_THREAD  {					\
+/* ksp, wstate, cwp, flags, current_ds, */ 		\
+   0,   0,      0,   0,     KERNEL_DS,			\
+/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
+   0,       0,       0,          0,			\
+/* fault_address, fpsaved, __pad2, kregs, */		\
+   0,             { 0 },   0,      0,			\
+/* utraps, gsr,   xfsr,  smp_lock_count, smp_lock_pc, */\
+   0,	   { 0 }, { 0 }, 0,		 0,		\
+/* reg_window */					\
+   { { { 0, }, { 0, } }, }, 				\
+/* rwbuf_stkptrs */					\
+   { 0, 0, 0, 0, 0, 0, 0, },				\
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+   0,          0,          0,		 0,            0, \
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCK) */
 
 #ifdef __KERNEL__
 #if PAGE_SHIFT == 13
diff -urN linux-2.5.2-pre11/include/asm-sparc64/rwsem.h linux/include/asm-sparc64/rwsem.h
--- linux-2.5.2-pre11/include/asm-sparc64/rwsem.h	Thu Apr 26 22:17:26 2001
+++ linux/include/asm-sparc64/rwsem.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: rwsem.h,v 1.4 2001/04/26 02:36:36 davem Exp $
+/* $Id: rwsem.h,v 1.5 2001/11/18 00:12:56 davem Exp $
  * rwsem.h: R/W semaphores implemented using CAS
  *
  * Written by David S. Miller (davem@redhat.com), 2001.
@@ -59,7 +59,7 @@
 		" add		%%g7, 1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -92,7 +92,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bne,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -122,7 +122,7 @@
 		"bne,pn		%%icc, 1b\n\t"
 		" cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection	2\n"
 		"3:\tsethi	%%hi(%2), %%g1\n\t"
@@ -160,7 +160,7 @@
 		" sub		%%g7, %%g1, %%g7\n\t"
 		"cmp		%%g7, 0\n\t"
 		"bl,pn		%%icc, 3f\n\t"
-		" membar	#StoreStore\n"
+		" membar	#StoreLoad | #StoreStore\n"
 		"2:\n\t"
 		".subsection 2\n"
 		"3:\tmov	%0, %%g5\n\t"
@@ -189,7 +189,7 @@
 		"cas		[%2], %%g5, %%g7\n\t"
 		"cmp		%%g5, %%g7\n\t"
 		"bne,pn		%%icc, 1b\n\t"
-		" nop\n\t"
+		" membar	#StoreLoad | #StoreStore\n\t"
 		"mov		%%g7, %0\n\t"
 		: "=&r" (tmp)
 		: "0" (tmp), "r" (sem)
@@ -208,7 +208,7 @@
 
 again:
 	__asm__ __volatile__("cas	[%2], %3, %0\n\t"
-			     "membar	#StoreStore | #StoreLoad"
+			     "membar	#StoreLoad | #StoreStore"
 			     : "=&r" (prev)
 			     : "0" (new), "r" (sem), "r" (old)
 			     : "memory");
diff -urN linux-2.5.2-pre11/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- linux-2.5.2-pre11/include/asm-sparc64/semaphore.h	Sun May 20 11:32:08 2001
+++ linux/include/asm-sparc64/semaphore.h	Mon Jan 14 18:28:32 2002
@@ -75,7 +75,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
@@ -120,7 +120,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 cmp	%%g7, 1\n"
 "	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreStore\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%2, %%g5\n"
@@ -173,7 +173,7 @@
 "	cmp	%%g5, %%g7\n"
 "	bne,pn	%%icc, 1b\n"
 "	 mov	0, %0\n"
-"	membar	#StoreStore\n"
+"	membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 	: "=&r" (ret)
 	: "r" (sem)
@@ -207,7 +207,7 @@
 "	bne,pn	%%icc, 1b\n"
 "	 addcc	%%g7, 1, %%g0\n"
 "	ble,pn	%%icc, 3f\n"
-"	 nop\n"
+"	 membar	#StoreLoad | #StoreStore\n"
 "2:\n"
 "	.subsection 2\n"
 "3:	mov	%0, %%g5\n"
diff -urN linux-2.5.2-pre11/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- linux-2.5.2-pre11/include/asm-sparc64/smp.h	Thu Apr 26 22:17:26 2001
+++ linux/include/asm-sparc64/smp.h	Mon Jan 14 18:28:32 2002
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <linux/cache.h>
 #include <asm/asi.h>
 #include <asm/starfire.h>
 #include <asm/spitfire.h>
@@ -34,7 +35,7 @@
 /* Per processor Sparc parameters we need. */
 
 /* Keep this a multiple of 64-bytes for cache reasons. */
-struct cpuinfo_sparc {
+typedef struct {
 	/* Dcache line 1 */
 	unsigned int	__pad0;		/* bh_count moved to irq_stat for consistency. KAO */
 	unsigned int	multiplier;
@@ -51,9 +52,9 @@
 
 	/* Dcache lines 3 and 4 */
 	unsigned int	irq_worklists[16];
-};
+} ____cacheline_aligned cpuinfo_sparc;
 
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+extern cpuinfo_sparc cpu_data[NR_CPUS];
 
 /*
  *	Private routines/data
@@ -102,20 +103,22 @@
 	}
 }
 
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current->cpu)
 
 /* This needn't do anything as we do not sleep the cpu
  * inside of the idler task, so an interrupt is not needed
  * to get a clean fast response.
  *
+ * XXX Reverify this assumption... -DaveM
+ *
  * Addendum: We do want it to do something for the signal
  *           delivery case, we detect that by just seeing
  *           if we are trying to send this to an idler or not.
  */
-extern __inline__ void smp_send_reschedule(int cpu)
+static __inline__ void smp_send_reschedule(int cpu)
 {
 	extern void smp_receive_signal(int);
-	if(cpu_data[cpu].idle_volume == 0)
+	if (cpu_data[cpu].idle_volume == 0)
 		smp_receive_signal(cpu);
 }
 
@@ -125,8 +128,6 @@
 extern __inline__ void smp_send_stop(void) { }
 
 #endif /* !(__ASSEMBLY__) */
-
-#define PROC_CHANGE_PENALTY	20
 
 #endif /* !(CONFIG_SMP) */
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/smplock.h linux/include/asm-sparc64/smplock.h
--- linux-2.5.2-pre11/include/asm-sparc64/smplock.h	Thu Mar 23 12:50:09 2000
+++ linux/include/asm-sparc64/smplock.h	Mon Jan 14 18:28:32 2002
@@ -9,26 +9,29 @@
 
 extern spinlock_t kernel_flag;
 
-#define kernel_locked()		spin_is_locked(&kernel_flag)
+#define kernel_locked()			\
+	(spin_is_locked(&kernel_flag) &&\
+	 (current->lock_depth >= 0))
 
 /*
  * Release global kernel lock and global interrupt lock
  */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
+#define release_kernel_lock(task, cpu)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0)) {	\
+		spin_unlock(&kernel_flag);	\
+		release_irqlock(cpu);		\
+		__sti();			\
+	}					\
 } while (0)
 
 /*
  * Re-acquire the kernel lock
  */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
+#define reacquire_kernel_lock(task)		\
+do {						\
+	if (unlikely(task->lock_depth >= 0))	\
+		spin_lock(&kernel_flag);	\
 } while (0)
 
 
@@ -39,14 +42,14 @@
  * so we only need to worry about other
  * CPU's.
  */
-#define lock_kernel() \
-do { \
-	if (!++current->lock_depth) \
-		spin_lock(&kernel_flag); \
+#define lock_kernel()				\
+do {						\
+	if (!++current->lock_depth)		\
+		spin_lock(&kernel_flag);	\
 } while(0)
 
-#define unlock_kernel() \
-do { \
-	if (--current->lock_depth < 0) \
-		spin_unlock(&kernel_flag); \
+#define unlock_kernel()				\
+do {						\
+	if (--current->lock_depth < 0)		\
+		spin_unlock(&kernel_flag);	\
 } while(0)
diff -urN linux-2.5.2-pre11/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- linux-2.5.2-pre11/include/asm-sparc64/spinlock.h	Thu Apr 26 22:17:26 2001
+++ linux/include/asm-sparc64/spinlock.h	Mon Jan 14 18:28:32 2002
@@ -6,11 +6,13 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
+#include <linux/config.h>
+
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
- * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
- * specific makefile and rebuild your kernel.
+ * deadlock situations, set CONFIG_DEBUG_SPINLOCK
+ * and rebuild your kernel.
  */
 
 /* All of these locking primitives are expected to work properly
@@ -26,7 +28,7 @@
  * must be pre-V9 branches.
  */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
@@ -75,7 +77,7 @@
 			     : "memory");
 }
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned char lock;
@@ -101,11 +103,11 @@
 #define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
 #define spin_unlock(lock)	_do_spin_unlock(lock)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
 
-#ifndef SPIN_LOCK_DEBUG
+#ifndef CONFIG_DEBUG_SPINLOCK
 
 typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED	0
@@ -121,7 +123,7 @@
 #define write_lock(p)	__write_lock(p)
 #define write_unlock(p)	__write_unlock(p)
 
-#else /* !(SPIN_LOCK_DEBUG) */
+#else /* !(CONFIG_DEBUG_SPINLOCK) */
 
 typedef struct {
 	unsigned long lock;
@@ -164,7 +166,7 @@
 	__restore_flags(flags); \
 } while(0)
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* CONFIG_DEBUG_SPINLOCK */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -urN linux-2.5.2-pre11/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- linux-2.5.2-pre11/include/asm-sparc64/spitfire.h	Mon Oct  1 09:19:56 2001
+++ linux/include/asm-sparc64/spitfire.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.16 2001/09/24 21:17:57 kanoj Exp $
+/* $Id: spitfire.h,v 1.18 2001/11/29 16:42:10 kanoj Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -32,6 +32,8 @@
 #define VIRT_WATCHPOINT		0x0000000000000038
 #define PHYS_WATCHPOINT		0x0000000000000040
 
+#define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
+
 #ifndef __ASSEMBLY__
 
 enum ultra_tlb_layout {
@@ -43,7 +45,6 @@
 
 #define SPARC64_USE_STICK	(tlb_type == cheetah)
 
-#define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
 #define L1DCACHE_SIZE		0x4000
@@ -357,12 +358,17 @@
  * 2 way assosciative, and holds 512 entries.  The fourth TLB is for
  * instruction accesses to 8K non-locked translations, is 2 way
  * assosciative, and holds 128 entries.
+ *
+ * Cheetah has some bug where bogus data can be returned from
+ * ASI_{D,I}TLB_DATA_ACCESS loads, doing the load twice fixes
+ * the problem for me. -DaveM
  */
 extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry)
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((0 << 16) | (entry << 3)),
 			     "i" (ASI_DTLB_DATA_ACCESS));
@@ -374,7 +380,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((0 << 16) | (entry << 3)),
 			     "i" (ASI_ITLB_DATA_ACCESS));
@@ -430,7 +437,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
 
@@ -461,7 +469,8 @@
 {
 	unsigned long data;
 
-	__asm__ __volatile__("ldxa	[%1] %2, %0"
+	__asm__ __volatile__("ldxa	[%1] %2, %%g0\n\t"
+			     "ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" ((2 << 16) | (entry << 3)),
                                "i" (ASI_ITLB_DATA_ACCESS));
diff -urN linux-2.5.2-pre11/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- linux-2.5.2-pre11/include/asm-sparc64/system.h	Fri Sep  7 11:01:20 2001
+++ linux/include/asm-sparc64/system.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.64 2001/08/30 03:22:00 kanoj Exp $ */
+/* $Id: system.h,v 1.68 2001/11/18 00:12:56 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -145,6 +145,24 @@
 #define flush_register_windows flushw_all
 #define prepare_to_switch flushw_all
 
+#ifndef CONFIG_DEBUG_SPINLOCk
+#define CHECK_LOCKS(PREV)	do { } while(0)
+#else /* CONFIG_DEBUG_SPINLOCk */
+#define CHECK_LOCKS(PREV)						\
+if ((PREV)->thread.smp_lock_count) {					\
+	unsigned long rpc;						\
+	__asm__ __volatile__("mov %%i7, %0" : "=r" (rpc));		\
+	printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n",	\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_count);				\
+	printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n",		\
+	       (PREV)->comm, (PREV)->pid,				\
+	       (PREV)->thread.smp_lock_pc);				\
+	printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n",		\
+	       (PREV)->comm, (PREV)->pid, rpc);				\
+}
+#endif /* !(CONFIG_DEBUG_SPINLOCk) */
+
 	/* See what happens when you design the chip correctly?
 	 *
 	 * We tell gcc we clobber all non-fixed-usage registers except
@@ -155,7 +173,8 @@
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
 #define switch_to(prev, next, last)						\
-do {	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
+do {	CHECK_LOCKS(prev);							\
+	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
 		current->thread.pcr_reg = __tmp;				\
@@ -276,7 +295,7 @@
 __cmpxchg_u32(volatile int *m, int old, int new)
 {
 	__asm__ __volatile__("cas [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
@@ -288,7 +307,7 @@
 __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
 {
 	__asm__ __volatile__("casx [%2], %3, %0\n\t"
-			     "membar #StoreStore | #StoreLoad"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=&r" (new)
 			     : "0" (new), "r" (m), "r" (old)
 			     : "memory");
diff -urN linux-2.5.2-pre11/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- linux-2.5.2-pre11/include/asm-sparc64/ttable.h	Thu Apr 12 12:10:25 2001
+++ linux/include/asm-sparc64/ttable.h	Mon Jan 14 18:28:32 2002
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.16 2001/03/28 10:56:34 davem Exp $ */
+/* $Id: ttable.h,v 1.17 2001/11/28 23:32:16 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -29,6 +29,15 @@
 	 clr	%l6;					\
 	nop;
 
+#define TRAP_7INSNS(routine)				\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etrap;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+
 #define TRAP_SAVEFPU(routine)				\
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, do_fptrap;			\
@@ -43,6 +52,11 @@
 	ba,pt	%xcc, routine;				\
 	 nop;						\
 	nop; nop; nop; nop; nop; nop;
+	
+#define TRAP_NOSAVE_7INSNS(routine)			\
+	ba,pt	%xcc, routine;				\
+	 nop;						\
+	nop; nop; nop; nop; nop;
 	
 #define TRAPTL1(routine)				\
 	sethi	%hi(109f), %g7;				\
diff -urN linux-2.5.2-pre11/include/linux/blkdev.h linux/include/linux/blkdev.h
--- linux-2.5.2-pre11/include/linux/blkdev.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/blkdev.h	Mon Jan 14 18:28:32 2002
@@ -326,10 +326,6 @@
 #define MIN_READAHEAD	3
 
 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-#define blkdev_entry_next_request(entry) blkdev_entry_to_request((entry)->next)
-#define blkdev_entry_prev_request(entry) blkdev_entry_to_request((entry)->prev)
-#define blkdev_next_request(req) blkdev_entry_to_request((req)->queuelist.next)
-#define blkdev_prev_request(req) blkdev_entry_to_request((req)->queuelist.prev)
 
 extern void drive_stat_acct(struct request *, int, int);
 
diff -urN linux-2.5.2-pre11/include/linux/crc32.h linux/include/linux/crc32.h
--- linux-2.5.2-pre11/include/linux/crc32.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/crc32.h	Mon Jan 14 18:28:32 2002
@@ -0,0 +1,17 @@
+/*
+ * crc32.h
+ * See linux/lib/crc32.c for license and changes
+ */
+#ifndef _LINUX_CRC32_H
+#define _LINUX_CRC32_H
+
+#include <linux/types.h>
+
+extern u32  crc32_le(u32 crc, unsigned char const *p, size_t len);
+extern u32  crc32_be(u32 crc, unsigned char const *p, size_t len);
+
+#define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)data, length)
+#define ether_crc_le(length, data) crc32_le(~0, data, length)
+#define ether_crc(length, data)    crc32_be(~0, data, length)
+
+#endif /* _LINUX_CRC32_H */
diff -urN linux-2.5.2-pre11/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.5.2-pre11/include/linux/fs.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/fs.h	Mon Jan 14 18:28:32 2002
@@ -245,6 +245,7 @@
 	unsigned short b_size;		/* block size */
 	unsigned short b_list;		/* List that this buffer appears */
 	kdev_t b_dev;			/* device (B_FREE = free) */
+	struct block_device *b_bdev;
 
 	atomic_t b_count;		/* users using this block */
 	unsigned long b_state;		/* buffer state bitmap (see above) */
@@ -1357,7 +1358,20 @@
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
 extern void file_move(struct file *f, struct list_head *list);
-extern struct buffer_head * get_hash_table(kdev_t, sector_t, int);
+extern struct buffer_head * __get_hash_table(struct block_device *, sector_t, int);
+static inline struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
+{
+	struct block_device *bdev;
+	struct buffer_head *bh;
+	bdev = bdget(kdev_t_to_nr(dev));
+	if (!bdev) {
+		printk("No block device for %s\n", bdevname(dev));
+		BUG();
+	}
+	bh = __get_hash_table(bdev, block, size);
+	atomic_dec(&bdev->bd_count);
+	return bh;
+}
 extern struct buffer_head * __getblk(struct block_device *, sector_t, int);
 static inline struct buffer_head * getblk(kdev_t dev, sector_t block, int size)
 {
@@ -1416,11 +1430,12 @@
 }
 static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
 {
-	return get_hash_table(sb->s_dev, block, sb->s_blocksize);
+	return __get_hash_table(sb->s_bdev, block, sb->s_blocksize);
 }
 static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
 {
 	bh->b_state |= 1 << BH_Mapped;
+	bh->b_bdev = sb->s_bdev;
 	bh->b_dev = sb->s_dev;
 	bh->b_blocknr = block;
 }
@@ -1428,7 +1443,7 @@
 extern void put_unused_buffer_head(struct buffer_head * bh);
 extern struct buffer_head * get_unused_buffer_head(int async);
 
-extern int brw_page(int, struct page *, kdev_t, sector_t [], int);
+extern int brw_page(int, struct page *, struct block_device *, sector_t [], int);
 
 typedef int (get_block_t)(struct inode*,sector_t,struct buffer_head*,int);
 
diff -urN linux-2.5.2-pre11/include/linux/if_arp.h linux/include/linux/if_arp.h
--- linux-2.5.2-pre11/include/linux/if_arp.h	Sun Dec 16 15:44:15 2001
+++ linux/include/linux/if_arp.h	Mon Jan 14 18:28:32 2002
@@ -82,6 +82,7 @@
 	/* 787->799 reserved for fibrechannel media types */
 #define ARPHRD_IEEE802_TR 800		/* Magic type ident for TR	*/
 #define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/
+#define ARPHRD_IEEE80211_PRISM 802	/* IEEE 802.11 + Prism2 header  */
 
 #define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */
 
diff -urN linux-2.5.2-pre11/include/linux/if_bonding.h linux/include/linux/if_bonding.h
--- linux-2.5.2-pre11/include/linux/if_bonding.h	Wed Nov  7 14:39:36 2001
+++ linux/include/linux/if_bonding.h	Mon Jan 14 18:28:32 2002
@@ -79,6 +79,15 @@
 	u32 link_failure_count;
 } slave_t;
 
+/*
+ * Here are the locking policies for the two bonding locks:
+ *
+ * 1) Get bond->lock when reading/writing slave list.
+ * 2) Get bond->ptrlock when reading/writing bond->current_slave.
+ *    (It is unnecessary when the write-lock is put with bond->lock.)
+ * 3) When we lock with bond->ptrlock, we must lock with bond->lock
+ *    beforehand.
+ */
 typedef struct bonding {
 	slave_t *next;
 	slave_t *prev;
diff -urN linux-2.5.2-pre11/include/linux/kbd_kern.h linux/include/linux/kbd_kern.h
--- linux-2.5.2-pre11/include/linux/kbd_kern.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/kbd_kern.h	Mon Jan 14 18:28:32 2002
@@ -1,6 +1,7 @@
 #ifndef _KBD_KERN_H
 #define _KBD_KERN_H
 
+#include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/keyboard.h>
 
diff -urN linux-2.5.2-pre11/include/linux/limits.h linux/include/linux/limits.h
--- linux-2.5.2-pre11/include/linux/limits.h	Wed Jul 28 10:30:10 1999
+++ linux/include/linux/limits.h	Mon Jan 14 18:28:32 2002
@@ -11,7 +11,7 @@
 #define MAX_CANON        255	/* size of the canonical input queue */
 #define MAX_INPUT        255	/* size of the type-ahead buffer */
 #define NAME_MAX         255	/* # chars in a file name */
-#define PATH_MAX        4095	/* # chars in a path name */
+#define PATH_MAX        4096	/* # chars in a path name including nul */
 #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
 
 #define RTSIG_MAX	  32
diff -urN linux-2.5.2-pre11/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.5.2-pre11/include/linux/netfilter_ipv4/ip_conntrack.h	Tue Oct 30 15:08:12 2001
+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Jan 14 18:28:32 2002
@@ -27,6 +27,21 @@
 	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
 };
 
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+	/* It's an expected connection: bit 0 set.  This bit never changed */
+	IPS_EXPECTED_BIT = 0,
+	IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
+	IPS_SEEN_REPLY_BIT = 1,
+	IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+	/* Conntrack should never be early-expired. */
+	IPS_ASSURED_BIT = 2,
+	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+};
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
@@ -46,21 +61,6 @@
 #else
 #define IP_NF_ASSERT(x)
 #endif
-
-/* Bitset representing status of connection. */
-enum ip_conntrack_status {
-	/* It's an expected connection: bit 0 set.  This bit never changed */
-	IPS_EXPECTED_BIT = 0,
-	IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
-
-	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
-	IPS_SEEN_REPLY_BIT = 1,
-	IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
-
-	/* Conntrack should never be early-expired. */
-	IPS_ASSURED_BIT = 2,
-	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
-};
 
 struct ip_conntrack_expect
 {
diff -urN linux-2.5.2-pre11/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- linux-2.5.2-pre11/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Thu Jul 26 13:58:26 2001
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Mon Jan 14 18:28:32 2002
@@ -62,6 +62,13 @@
 	} dst;
 };
 
+enum ip_conntrack_dir
+{
+	IP_CT_DIR_ORIGINAL,
+	IP_CT_DIR_REPLY,
+	IP_CT_DIR_MAX
+};
+
 #ifdef __KERNEL__
 
 #define DUMP_TUPLE(tp)						\
@@ -75,13 +82,19 @@
 /* If we're the first tuple, it's the original dir. */
 #define DIRECTION(h) ((enum ip_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
 
-enum ip_conntrack_dir
+/* Connections have two entries in the hash table: one for each way */
+struct ip_conntrack_tuple_hash
 {
-	IP_CT_DIR_ORIGINAL,
-	IP_CT_DIR_REPLY,
-	IP_CT_DIR_MAX
+	struct list_head list;
+
+	struct ip_conntrack_tuple tuple;
+
+	/* this == &ctrack->tuplehash[DIRECTION(this)]. */
+	struct ip_conntrack *ctrack;
 };
 
+#endif /* __KERNEL__ */
+
 static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
 				        const struct ip_conntrack_tuple *t2)
 {
@@ -115,16 +128,4 @@
 		     & mask->dst.protonum));
 }
 
-/* Connections have two entries in the hash table: one for each way */
-struct ip_conntrack_tuple_hash
-{
-	struct list_head list;
-
-	struct ip_conntrack_tuple tuple;
-
-	/* this == &ctrack->tuplehash[DIRECTION(this)]. */
-	struct ip_conntrack *ctrack;
-};
-
-#endif /* __KERNEL__ */
 #endif /* _IP_CONNTRACK_TUPLE_H */
diff -urN linux-2.5.2-pre11/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- linux-2.5.2-pre11/include/linux/reiserfs_fs.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/reiserfs_fs.h	Mon Jan 14 18:28:32 2002
@@ -1651,7 +1651,7 @@
 #define _jhashfn(dev,block)	\
 	((((dev)<<(JBH_HASH_SHIFT - 6)) ^ ((dev)<<(JBH_HASH_SHIFT - 9))) ^ \
 	 (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
-#define journal_hash(t,dev,block) ((t)[_jhashfn((kdev_t_to_nr(dev)),(block)) & JBH_HASH_MASK])
+#define journal_hash(t,sb,block) ((t)[_jhashfn((kdev_t_to_nr(sb->s_dev)),(block)) & JBH_HASH_MASK])
 
 /* finds n'th buffer with 0 being the start of this commit.  Needs to go away, j_ap_blocks has changed
 ** since I created this.  One chunk of code in journal.c needs changing before deleting it
@@ -1678,14 +1678,13 @@
 int journal_lock_dobalance(struct super_block *p_s_sb) ;
 int journal_unlock_dobalance(struct super_block *p_s_sb) ;
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
+int reiserfs_in_journal(struct super_block *p_s_sb, unsigned long bl, int searchall, unsigned long *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
 int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
 struct super_block *reiserfs_get_super(kdev_t dev) ;
 void flush_async_commits(struct super_block *p_s_sb) ;
 
 int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ;
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ;
 
 int buffer_journaled(const struct buffer_head *bh) ;
 int mark_buffer_journal_new(struct buffer_head *bh) ;
diff -urN linux-2.5.2-pre11/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- linux-2.5.2-pre11/include/linux/reiserfs_fs_sb.h	Sun Dec 16 15:43:25 2001
+++ linux/include/linux/reiserfs_fs_sb.h	Mon Jan 14 18:28:32 2002
@@ -199,7 +199,7 @@
 */
 struct reiserfs_journal_cnode {
   struct buffer_head *bh ;		 /* real buffer head */
-  kdev_t dev ;				 /* dev of real buffer head */
+  struct super_block *sb ;		 /* dev of real buffer head */
   unsigned long blocknr ;		 /* block number of real buffer head, == 0 when buffer on disk */		 
   int state ;
   struct reiserfs_journal_list *jlist ;  /* journal list this cnode lives in */
diff -urN linux-2.5.2-pre11/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.5.2-pre11/include/linux/sched.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/sched.h	Mon Jan 14 18:28:32 2002
@@ -305,7 +305,7 @@
 	prio_array_t *array;
 
 	unsigned int time_slice;
-	unsigned long swap_cnt_last;
+	unsigned long sleep_jtime;
 
 	unsigned long policy;
 	unsigned long cpus_allowed;
diff -urN linux-2.5.2-pre11/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h
--- linux-2.5.2-pre11/include/linux/shmem_fs.h	Wed Oct 10 07:53:57 2001
+++ linux/include/linux/shmem_fs.h	Mon Jan 14 18:28:32 2002
@@ -11,7 +11,7 @@
  * swapper address space.
  *
  * We have to move it here, since not every user of fs.h is including
- * mm.h, but m.h is including fs.h via sched .h :-/
+ * mm.h, but mm.h is including fs.h via sched .h :-/
  */
 typedef struct {
 	unsigned long val;
diff -urN linux-2.5.2-pre11/include/linux/socket.h linux/include/linux/socket.h
--- linux-2.5.2-pre11/include/linux/socket.h	Sun Dec 16 15:43:25 2001
+++ linux/include/linux/socket.h	Mon Jan 14 18:28:32 2002
@@ -156,6 +156,7 @@
 #define AF_IRDA		23	/* IRDA sockets			*/
 #define AF_PPPOX	24	/* PPPoX sockets		*/
 #define AF_WANPIPE	25	/* Wanpipe API Sockets */
+#define AF_LLC		26	/* Linux LLC			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_MAX		32	/* For now.. */
 
@@ -187,6 +188,7 @@
 #define PF_IRDA		AF_IRDA
 #define PF_PPPOX	AF_PPPOX
 #define PF_WANPIPE	AF_WANPIPE
+#define PF_LLC		AF_LLC
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_MAX		AF_MAX
 
@@ -237,6 +239,8 @@
 #define SOL_ATM		264	/* ATM layer (cell level) */
 #define SOL_AAL		265	/* ATM Adaption Layer (packet level) */
 #define SOL_IRDA        266
+#define SOL_NETBEUI	267
+#define SOL_LLC		268
 
 /* IPX options */
 #define IPX_TYPE	1
diff -urN linux-2.5.2-pre11/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- linux-2.5.2-pre11/include/linux/sunrpc/clnt.h	Mon Jan 14 18:28:25 2002
+++ linux/include/linux/sunrpc/clnt.h	Mon Jan 14 18:28:32 2002
@@ -137,7 +137,6 @@
 	xprt_set_timeout(&clnt->cl_timeout, retr, incr);
 }
 
-extern void rpciod_tcp_dispatcher(void);
 extern void rpciod_wake_up(void);
 
 /*
diff -urN linux-2.5.2-pre11/include/linux/swap.h linux/include/linux/swap.h
--- linux-2.5.2-pre11/include/linux/swap.h	Sun Dec 16 15:43:25 2001
+++ linux/include/linux/swap.h	Mon Jan 14 18:28:32 2002
@@ -65,8 +65,7 @@
 	unsigned int flags;
 	kdev_t swap_device;
 	spinlock_t sdev_lock;
-	struct dentry * swap_file;
-	struct vfsmount *swap_vfsmnt;
+	struct file *swap_file;
 	unsigned short * swap_map;
 	unsigned int lowest_bit;
 	unsigned int highest_bit;
@@ -141,8 +140,7 @@
 extern int is_swap_partition(kdev_t);
 extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(void);
-extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *, 
-					struct inode **);
+extern void get_swaphandle_info(swp_entry_t, unsigned long *, struct inode **);
 extern int swap_duplicate(swp_entry_t);
 extern int swap_count(struct page *);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
diff -urN linux-2.5.2-pre11/include/math-emu/double.h linux/include/math-emu/double.h
--- linux-2.5.2-pre11/include/math-emu/double.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/double.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef    __MATH_EMU_DOUBLE_H__
+#define    __MATH_EMU_DOUBLE_H__
+
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel kid.  Go buy yourself a real computer."
 #endif
@@ -197,3 +200,6 @@
 #define _FP_FRAC_HIGH_RAW_D(X)	_FP_FRAC_HIGH_1(X)
 
 #endif /* W_TYPE_SIZE < 64 */
+
+
+#endif /* __MATH_EMU_DOUBLE_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/extended.h linux/include/math-emu/extended.h
--- linux-2.5.2-pre11/include/math-emu/extended.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/extended.h	Mon Jan 14 18:28:32 2002
@@ -19,6 +19,10 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+
+#ifndef    __MATH_EMU_EXTENDED_H__
+#define    __MATH_EMU_EXTENDED_H__
+
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel, kid. Go buy yourself a real computer."
 #endif
@@ -388,3 +392,5 @@
 #define _FP_FRAC_HIGH_RAW_E(X)	(X##_f0)
 
 #endif /* not _FP_W_TYPE_SIZE < 64 */
+
+#endif /* __MATH_EMU_EXTENDED_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/op-1.h linux/include/math-emu/op-1.h
--- linux-2.5.2-pre11/include/math-emu/op-1.h	Mon Dec 20 22:05:52 1999
+++ linux/include/math-emu/op-1.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef    __MATH_EMU_OP_1_H__
+#define    __MATH_EMU_OP_1_H__
+
 #define _FP_FRAC_DECL_1(X)	_FP_W_TYPE X##_f
 #define _FP_FRAC_COPY_1(D,S)	(D##_f = S##_f)
 #define _FP_FRAC_SET_1(X,I)	(X##_f = I)
@@ -295,3 +298,5 @@
     else								\
       D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs;		\
   } while (0)
+
+#endif /* __MATH_EMU_OP_1_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/op-2.h linux/include/math-emu/op-2.h
--- linux-2.5.2-pre11/include/math-emu/op-2.h	Mon Feb 19 11:36:34 2001
+++ linux/include/math-emu/op-2.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef __MATH_EMU_OP_2_H__
+#define __MATH_EMU_OP_2_H__
+
 #define _FP_FRAC_DECL_2(X)	_FP_W_TYPE X##_f0, X##_f1
 #define _FP_FRAC_COPY_2(D,S)	(D##_f0 = S##_f0, D##_f1 = S##_f1)
 #define _FP_FRAC_SET_2(X,I)	__FP_FRAC_SET_2(X, I)
@@ -606,3 +609,4 @@
     _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
   } while (0)
 
+#endif
diff -urN linux-2.5.2-pre11/include/math-emu/op-4.h linux/include/math-emu/op-4.h
--- linux-2.5.2-pre11/include/math-emu/op-4.h	Tue Aug 31 11:24:24 1999
+++ linux/include/math-emu/op-4.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef __MATH_EMU_OP_4_H__
+#define __MATH_EMU_OP_4_H__
+
 #define _FP_FRAC_DECL_4(X)	_FP_W_TYPE X##_f[4]
 #define _FP_FRAC_COPY_4(D,S)			\
   (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],	\
@@ -659,3 +662,4 @@
      _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
    } while (0)
 
+#endif
diff -urN linux-2.5.2-pre11/include/math-emu/op-8.h linux/include/math-emu/op-8.h
--- linux-2.5.2-pre11/include/math-emu/op-8.h	Tue Aug 31 11:24:24 1999
+++ linux/include/math-emu/op-8.h	Mon Jan 14 18:28:32 2002
@@ -21,6 +21,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef __MATH_EMU_OP_8_H__
+#define __MATH_EMU_OP_8_H__
+
 /* We need just a few things from here for op-4, if we ever need some
    other macros, they can be added. */
 #define _FP_FRAC_DECL_8(X)	_FP_W_TYPE X##_f[8]
@@ -101,3 +104,4 @@
     X##_f[0] |= (_s != 0);						\
   } while (0)
 
+#endif
diff -urN linux-2.5.2-pre11/include/math-emu/op-common.h linux/include/math-emu/op-common.h
--- linux-2.5.2-pre11/include/math-emu/op-common.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/op-common.h	Mon Jan 14 18:28:32 2002
@@ -21,6 +21,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef __MATH_EMU_OP_COMMON_H__
+#define __MATH_EMU_OP_COMMON_H__
+
 #define _FP_DECL(wc, X)			\
   _FP_I_TYPE X##_c, X##_s, X##_e;	\
   _FP_FRAC_DECL_##wc(X)
@@ -846,3 +849,4 @@
     q = n / d, r = n % d;			\
   } while (0)
 
+#endif /* __MATH_EMU_OP_COMMON_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/quad.h linux/include/math-emu/quad.h
--- linux-2.5.2-pre11/include/math-emu/quad.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/quad.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef  __MATH_EMU_QUAD_H__
+#define  __MATH_EMU_QUAD_H__
+
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel, kid. Go buy yourself a real computer."
 #endif
@@ -201,3 +204,5 @@
 #define _FP_FRAC_HIGH_RAW_Q(X)	_FP_FRAC_HIGH_2(X)
 
 #endif /* not _FP_W_TYPE_SIZE < 64 */
+
+#endif /* __MATH_EMU_QUAD_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/single.h linux/include/math-emu/single.h
--- linux-2.5.2-pre11/include/math-emu/single.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/single.h	Mon Jan 14 18:28:32 2002
@@ -22,6 +22,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef    __MATH_EMU_SINGLE_H__
+#define    __MATH_EMU_SINGLE_H__
+
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel kid.  Go buy yourself a real computer."
 #endif
@@ -109,3 +112,5 @@
 
 #define _FP_FRAC_HIGH_S(X)	_FP_FRAC_HIGH_1(X)
 #define _FP_FRAC_HIGH_RAW_S(X)	_FP_FRAC_HIGH_1(X)
+
+#endif /* __MATH_EMU_SINGLE_H__ */
diff -urN linux-2.5.2-pre11/include/math-emu/soft-fp.h linux/include/math-emu/soft-fp.h
--- linux-2.5.2-pre11/include/math-emu/soft-fp.h	Thu Dec  2 15:28:54 1999
+++ linux/include/math-emu/soft-fp.h	Mon Jan 14 18:28:32 2002
@@ -21,8 +21,8 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#ifndef SOFT_FP_H
-#define SOFT_FP_H
+#ifndef __MATH_EMU_SOFT_FP_H__
+#define __MATH_EMU_SOFT_FP_H__
 
 #include <asm/sfp-machine.h>
 
@@ -178,4 +178,4 @@
 #include <stdlib/longlong.h>
 #endif
 
-#endif
+#endif /* __MATH_EMU_SOFT_FP_H__ */
diff -urN linux-2.5.2-pre11/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.5.2-pre11/kernel/ksyms.c	Mon Jan 14 18:28:25 2002
+++ linux/kernel/ksyms.c	Mon Jan 14 18:28:32 2002
@@ -511,7 +511,7 @@
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
-EXPORT_SYMBOL(get_hash_table);
+EXPORT_SYMBOL(__get_hash_table);
 EXPORT_SYMBOL(get_empty_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
diff -urN linux-2.5.2-pre11/kernel/sched.c linux/kernel/sched.c
--- linux-2.5.2-pre11/kernel/sched.c	Mon Jan 14 18:28:25 2002
+++ linux/kernel/sched.c	Mon Jan 14 18:28:32 2002
@@ -21,6 +21,9 @@
 #include <asm/mmu_context.h>
 
 #define BITMAP_SIZE ((MAX_PRIO+7)/8)
+#define PRIO_INTERACTIVE	(MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 4)
+#define TASK_INTERACTIVE(p)	((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
+#define JSLEEP_TO_PRIO(t)	(((t) * 20) / HZ)
 
 typedef struct runqueue runqueue_t;
 
@@ -48,7 +51,6 @@
 	spinlock_t lock;
 	unsigned long nr_running, nr_switches;
 	task_t *curr, *idle;
-	unsigned long swap_cnt;
 	prio_array_t *active, *expired, arrays[2];
 	char __pad [SMP_CACHE_BYTES];
 } runqueues [NR_CPUS] __cacheline_aligned;
@@ -97,7 +99,7 @@
 	prio_array_t *array = rq->active;
 
 	if (!rt_task(p)) {
-		unsigned long prio_bonus = rq->swap_cnt - p->swap_cnt_last;
+		unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
 
 		if (prio_bonus > MAX_PRIO)
 			prio_bonus = MAX_PRIO;
@@ -114,7 +116,7 @@
 	rq->nr_running--;
 	dequeue_task(p, p->array);
 	p->array = NULL;
-	p->swap_cnt_last = rq->swap_cnt;
+	p->sleep_jtime = jiffies;
 }
 
 static inline void resched_task(task_t *p)
@@ -448,7 +450,10 @@
 				p->prio = MAX_PRIO - 1;
 		}
 		p->time_slice = time_slice;
-		enqueue_task(p, rq->expired);
+		if (TASK_INTERACTIVE(p))
+			enqueue_task(p, rq->active);
+		else
+			enqueue_task(p, rq->expired);
 	}
 	spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -475,14 +480,14 @@
 	spin_lock_irq(&rq->lock);
 
 	switch (prev->state) {
-		case TASK_INTERRUPTIBLE:
-			if (unlikely(signal_pending(prev))) {
-				prev->state = TASK_RUNNING;
-				break;
-			}
-		default:
-			deactivate_task(prev, rq);
-		case TASK_RUNNING:
+	case TASK_INTERRUPTIBLE:
+		if (unlikely(signal_pending(prev))) {
+			prev->state = TASK_RUNNING;
+			break;
+		}
+	default:
+		deactivate_task(prev, rq);
+	case TASK_RUNNING:
 	}
 pick_next_task:
 	if (unlikely(!rq->nr_running)) {
@@ -501,7 +506,6 @@
 		rq->active = rq->expired;
 		rq->expired = array;
 		array = rq->active;
-		rq->swap_cnt++;
 	}
 
 	idx = sched_find_first_zero_bit(array->bitmap);
@@ -1187,7 +1191,6 @@
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
 		rq->cpu = i;
-		rq->swap_cnt = 0;
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
diff -urN linux-2.5.2-pre11/lib/Config.in linux/lib/Config.in
--- linux-2.5.2-pre11/lib/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/lib/Config.in	Mon Jan 14 18:28:32 2002
@@ -0,0 +1,8 @@
+#
+# Library configuration
+#
+mainmenu_option next_comment
+comment 'Library routines'
+
+tristate 'CRC32 functions' CONFIG_CRC32
+endmenu
diff -urN linux-2.5.2-pre11/lib/Makefile linux/lib/Makefile
--- linux-2.5.2-pre11/lib/Makefile	Mon Sep 17 15:31:15 2001
+++ linux/lib/Makefile	Mon Jan 14 18:28:32 2002
@@ -8,7 +8,7 @@
 
 L_TARGET := lib.a
 
-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o
 
 obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
 
@@ -18,5 +18,10 @@
 ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
   obj-y += dec_and_lock.o
 endif
+
+obj-$(CONFIG_CRC32)	+= crc32.o
+include $(TOPDIR)/drivers/net/Makefile.lib
+include $(TOPDIR)/drivers/usb/Makefile.lib
+include $(TOPDIR)/fs/Makefile.lib
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.5.2-pre11/lib/crc32.c linux/lib/crc32.c
--- linux-2.5.2-pre11/lib/crc32.c	Wed Dec 31 16:00:00 1969
+++ linux/lib/crc32.c	Mon Jan 14 18:28:32 2002
@@ -0,0 +1,571 @@
+/* 
+ * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
+ *
+ * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * Same crc32 function was used in 5 other places in the kernel.
+ * I made one version, and deleted the others.
+ * There are various incantations of crc32().  Some use a seed of 0 or ~0.
+ * Some xor at the end with ~0.  The generic crc32() function takes
+ * seed as an argument, and doesn't xor at the end.  Then individual
+ * users can do whatever they need.
+ *   drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
+ *   fs/jffs2 uses seed 0, doesn't xor with ~0.
+ *   fs/partitions/efi.c uses seed ~0, xor's with ~0.
+ * 
+ */
+
+#include <linux/crc32.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+#if __GNUC__ >= 3	/* 2.x has "attribute", but only 3.0 has "pure */
+#define attribute(x) __attribute__(x)
+#else
+#define attribute(x)
+#endif
+
+/*
+ * This code is in the public domain; copyright abandoned.
+ * Liability for non-performance of this code is limited to the amount
+ * you paid for it.  Since it is distributed for free, your refund will
+ * be very very small.  If it breaks, you get to keep both pieces.
+ */
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
+MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_LICENSE("GPL and additional rights");
+
+
+/*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
+/* For less performance-sensitive, use 4 */
+#define CRC_LE_BITS 8
+#define CRC_BE_BITS 8
+
+/*
+ * Little-endian CRC computation.  Used with serial bit streams sent
+ * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
+ */
+#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
+# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_LE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_le()
+#define crc32cleanup_le()
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	return crc;
+}
+#else				/* Table-based approach */
+
+static u32 *crc32table_le;
+/**
+ * crc32init_le() - allocate and initialize LE table data
+ *
+ * crc is the crc of the byte i; other entries are filled in based on the
+ * fact that crctable[i^j] = crctable[i] ^ crctable[j].
+ *
+ */
+static int __init crc32init_le(void)
+{
+	unsigned i, j;
+	u32 crc = 1;
+
+	crc32table_le =
+	    kmalloc((1 << CRC_LE_BITS) * sizeof(u32), GFP_KERNEL);
+	if (!crc32table_le)
+		return 1;
+	crc32table_le[0] = 0;
+
+	for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
+		crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+		for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
+			crc32table_le[i + j] = crc ^ crc32table_le[j];
+	}
+	return 0;
+}
+
+/**
+ * crc32cleanup_le(): free LE table data
+ */
+static void __exit crc32cleanup_le(void)
+{
+	if (crc32table_le) kfree(crc32table_le);
+	crc32table_le = NULL;
+}
+
+/**
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+u32 attribute((pure)) crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+	while (len--) {
+# if CRC_LE_BITS == 8
+		crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
+# elif CRC_LE_BITS == 4
+		crc ^= *p++;
+		crc = (crc >> 4) ^ crc32table_le[crc & 15];
+		crc = (crc >> 4) ^ crc32table_le[crc & 15];
+# elif CRC_LE_BITS == 2
+		crc ^= *p++;
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+		crc = (crc >> 2) ^ crc32table_le[crc & 3];
+# endif
+	}
+	return crc;
+}
+#endif
+
+/*
+ * Big-endian CRC computation.  Used with serial bit streams sent
+ * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
+ */
+#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
+# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#endif
+
+#if CRC_BE_BITS == 1
+/*
+ * In fact, the table-based code will work in this case, but it can be
+ * simplified by inlining the table in ?: form.
+ */
+#define crc32init_be()
+#define crc32cleanup_be()
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+	int i;
+	while (len--) {
+		crc ^= *p++ << 24;
+		for (i = 0; i < 8; i++)
+			crc =
+			    (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+					  0);
+	}
+	return crc;
+}
+
+#else				/* Table-based approach */
+static u32 *crc32table_be;
+
+/**
+ * crc32init_be() - allocate and initialize BE table data
+ */
+static int __init crc32init_be(void)
+{
+	unsigned i, j;
+	u32 crc = 0x80000000;
+
+	crc32table_be =
+	    kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
+	if (!crc32table_be)
+		return 1;
+	crc32table_be[0] = 0;
+
+	for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
+		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+		for (j = 0; j < i; j++)
+			crc32table_be[i + j] = crc ^ crc32table_be[j];
+	}
+	return 0;
+}
+
+/**
+ * crc32cleanup_be(): free BE table data
+ */
+static void __exit crc32cleanup_be(void)
+{
+	if (crc32table_be) kfree(crc32table_be);
+	crc32table_be = NULL;
+}
+
+
+/**
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc - seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *        other uses, or the previous crc32 value if computing incrementally.
+ * @p   - pointer to buffer over which CRC is run
+ * @len - length of buffer @p
+ * 
+ */
+u32 attribute((pure)) crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+	while (len--) {
+# if CRC_BE_BITS == 8
+		crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++];
+# elif CRC_BE_BITS == 4
+		crc ^= *p++ << 24;
+		crc = (crc << 4) ^ crc32table_be[crc >> 28];
+		crc = (crc << 4) ^ crc32table_be[crc >> 28];
+# elif CRC_BE_BITS == 2
+		crc ^= *p++ << 24;
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+		crc = (crc << 2) ^ crc32table_be[crc >> 30];
+# endif
+	}
+	return crc;
+}
+#endif
+
+/*
+ * A brief CRC tutorial.
+ *
+ * A CRC is a long-division remainder.  You add the CRC to the message,
+ * and the whole thing (message+CRC) is a multiple of the given
+ * CRC polynomial.  To check the CRC, you can either check that the
+ * CRC matches the recomputed value, *or* you can check that the
+ * remainder computed on the message+CRC is 0.  This latter approach
+ * is used by a lot of hardware implementations, and is why so many
+ * protocols put the end-of-frame flag after the CRC.
+ *
+ * It's actually the same long division you learned in school, except that
+ * - We're working in binary, so the digits are only 0 and 1, and
+ * - When dividing polynomials, there are no carries.  Rather than add and
+ *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
+ *   the difference between adding and subtracting.
+ *
+ * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
+ * 33 bits long, bit 32 is always going to be set, so usually the CRC
+ * is written in hex with the most significant bit omitted.  (If you're
+ * familiar with the IEEE 754 floating-point format, it's the same idea.)
+ *
+ * Note that a CRC is computed over a string of *bits*, so you have
+ * to decide on the endianness of the bits within each byte.  To get
+ * the best error-detecting properties, this should correspond to the
+ * order they're actually sent.  For example, standard RS-232 serial is
+ * little-endian; the most significant bit (sometimes used for parity)
+ * is sent last.  And when appending a CRC word to a message, you should
+ * do it in the right order, matching the endianness.
+ *
+ * Just like with ordinary division, the remainder is always smaller than
+ * the divisor (the CRC polynomial) you're dividing by.  Each step of the
+ * division, you take one more digit (bit) of the dividend and append it
+ * to the current remainder.  Then you figure out the appropriate multiple
+ * of the divisor to subtract to being the remainder back into range.
+ * In binary, it's easy - it has to be either 0 or 1, and to make the
+ * XOR cancel, it's just a copy of bit 32 of the remainder.
+ *
+ * When computing a CRC, we don't care about the quotient, so we can
+ * throw the quotient bit away, but subtract the appropriate multiple of
+ * the polynomial from the remainder and we're back to where we started,
+ * ready to process the next bit.
+ *
+ * A big-endian CRC written this way would be coded like:
+ * for (i = 0; i < input_bits; i++) {
+ * 	multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+ * 	remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+ * }
+ * Notice how, to get at bit 32 of the shifted remainder, we look
+ * at bit 31 of the remainder *before* shifting it.
+ *
+ * But also notice how the next_input_bit() bits we're shifting into
+ * the remainder don't actually affect any decision-making until
+ * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
+ * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+ * the end, so we have to add 32 extra cycles shifting in zeros at the
+ * end of every message,
+ *
+ * So the standard trick is to rearrage merging in the next_input_bit()
+ * until the moment it's needed.  Then the first 32 cycles can be precomputed,
+ * and merging in the final 32 zero bits to make room for the CRC can be
+ * skipped entirely.
+ * This changes the code to:
+ * for (i = 0; i < input_bits; i++) {
+ *      remainder ^= next_input_bit() << 31;
+ * 	multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * 	remainder = (remainder << 1) ^ multiple;
+ * }
+ * With this optimization, the little-endian code is simpler:
+ * for (i = 0; i < input_bits; i++) {
+ *      remainder ^= next_input_bit();
+ * 	multiple = (remainder & 1) ? CRCPOLY : 0;
+ * 	remainder = (remainder >> 1) ^ multiple;
+ * }
+ *
+ * Note that the other details of endianness have been hidden in CRCPOLY
+ * (which must be bit-reversed) and next_input_bit().
+ *
+ * However, as long as next_input_bit is returning the bits in a sensible
+ * order, we can actually do the merging 8 or more bits at a time rather
+ * than one bit at a time:
+ * for (i = 0; i < input_bytes; i++) {
+ * 	remainder ^= next_input_byte() << 24;
+ * 	for (j = 0; j < 8; j++) {
+ * 		multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+ * 		remainder = (remainder << 1) ^ multiple;
+ * 	}
+ * }
+ * Or in little-endian:
+ * for (i = 0; i < input_bytes; i++) {
+ * 	remainder ^= next_input_byte();
+ * 	for (j = 0; j < 8; j++) {
+ * 		multiple = (remainder & 1) ? CRCPOLY : 0;
+ * 		remainder = (remainder << 1) ^ multiple;
+ * 	}
+ * }
+ * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+ * word at a time and increase the inner loop count to 32.
+ *
+ * You can also mix and match the two loop styles, for example doing the
+ * bulk of a message byte-at-a-time and adding bit-at-a-time processing
+ * for any fractional bytes at the end.
+ *
+ * The only remaining optimization is to the byte-at-a-time table method.
+ * Here, rather than just shifting one bit of the remainder to decide
+ * in the correct multiple to subtract, we can shift a byte at a time.
+ * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+ * but again the multiple of the polynomial to subtract depends only on
+ * the high bits, the high 8 bits in this case.  
+ *
+ * The multile we need in that case is the low 32 bits of a 40-bit
+ * value whose high 8 bits are given, and which is a multiple of the
+ * generator polynomial.  This is simply the CRC-32 of the given
+ * one-byte message.
+ *
+ * Two more details: normally, appending zero bits to a message which
+ * is already a multiple of a polynomial produces a larger multiple of that
+ * polynomial.  To enable a CRC to detect this condition, it's common to
+ * invert the CRC before appending it.  This makes the remainder of the
+ * message+crc come out not as zero, but some fixed non-zero value.
+ *
+ * The same problem applies to zero bits prepended to the message, and
+ * a similar solution is used.  Instead of starting with a remainder of
+ * 0, an initial remainder of all ones is used.  As long as you start
+ * the same way on decoding, it doesn't make a difference.
+ */
+
+#if UNITTEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if 0				/*Not used at present */
+static void
+buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+{
+	fputs(prefix, stdout);
+	while (len--)
+		printf(" %02x", *buf++);
+	putchar('\n');
+
+}
+#endif
+
+static u32 attribute((const)) bitreverse(u32 x)
+{
+	x = (x >> 16) | (x << 16);
+	x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
+	x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
+	x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
+	x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
+	return x;
+}
+
+static void bytereverse(unsigned char *buf, size_t len)
+{
+	while (len--) {
+		unsigned char x = *buf;
+		x = (x >> 4) | (x << 4);
+		x = (x >> 2 & 0x33) | (x << 2 & 0xcc);
+		x = (x >> 1 & 0x55) | (x << 1 & 0xaa);
+		*buf++ = x;
+	}
+}
+
+static void random_garbage(unsigned char *buf, size_t len)
+{
+	while (len--)
+		*buf++ = (unsigned char) random();
+}
+
+#if 0				/* Not used at present */
+static void store_le(u32 x, unsigned char *buf)
+{
+	buf[0] = (unsigned char) x;
+	buf[1] = (unsigned char) (x >> 8);
+	buf[2] = (unsigned char) (x >> 16);
+	buf[3] = (unsigned char) (x >> 24);
+}
+#endif
+
+static void store_be(u32 x, unsigned char *buf)
+{
+	buf[0] = (unsigned char) (x >> 24);
+	buf[1] = (unsigned char) (x >> 16);
+	buf[2] = (unsigned char) (x >> 8);
+	buf[3] = (unsigned char) x;
+}
+
+/*
+ * This checks that CRC(buf + CRC(buf)) = 0, and that
+ * CRC commutes with bit-reversal.  This has the side effect
+ * of bytewise bit-reversing the input buffer, and returns
+ * the CRC of the reversed buffer.
+ */
+static u32 test_step(u32 init, unsigned char *buf, size_t len)
+{
+	u32 crc1, crc2;
+	size_t i;
+
+	crc1 = crc32_be(init, buf, len);
+	store_be(crc1, buf + len);
+	crc2 = crc32_be(init, buf, len + 4);
+	if (crc2)
+		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+		       crc2);
+
+	for (i = 0; i <= len + 4; i++) {
+		crc2 = crc32_be(init, buf, i);
+		crc2 = crc32_be(crc2, buf + i, len + 4 - i);
+		if (crc2)
+			printf("\nCRC split fail: 0x%08x\n", crc2);
+	}
+
+	/* Now swap it around for the other test */
+
+	bytereverse(buf, len + 4);
+	init = bitreverse(init);
+	crc2 = bitreverse(crc1);
+	if (crc1 != bitreverse(crc2))
+		printf("\nBit reversal fail: 0x%08x -> %0x08x -> 0x%08x\n",
+		       crc1, crc2, bitreverse(crc2));
+	crc1 = crc32_le(init, buf, len);
+	if (crc1 != crc2)
+		printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
+		       crc2);
+	crc2 = crc32_le(init, buf, len + 4);
+	if (crc2)
+		printf("\nCRC cancellation fail: 0x%08x should be 0\n",
+		       crc2);
+
+	for (i = 0; i <= len + 4; i++) {
+		crc2 = crc32_le(init, buf, i);
+		crc2 = crc32_le(crc2, buf + i, len + 4 - i);
+		if (crc2)
+			printf("\nCRC split fail: 0x%08x\n", crc2);
+	}
+
+	return crc1;
+}
+
+#define SIZE 64
+#define INIT1 0
+#define INIT2 0
+
+int main(void)
+{
+	unsigned char buf1[SIZE + 4];
+	unsigned char buf2[SIZE + 4];
+	unsigned char buf3[SIZE + 4];
+	int i, j;
+	u32 crc1, crc2, crc3;
+
+	crc32init_le();
+	crc32init_be();
+
+	for (i = 0; i <= SIZE; i++) {
+		printf("\rTesting length %d...", i);
+		fflush(stdout);
+		random_garbage(buf1, i);
+		random_garbage(buf2, i);
+		for (j = 0; j < i; j++)
+			buf3[j] = buf1[j] ^ buf2[j];
+
+		crc1 = test_step(INIT1, buf1, i);
+		crc2 = test_step(INIT2, buf2, i);
+		/* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
+		crc3 = test_step(INIT1 ^ INIT2, buf3, i);
+		if (crc3 != (crc1 ^ crc2))
+			printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
+			       crc3, crc1, crc2);
+	}
+	printf("\nAll test complete.  No failures expected.\n");
+	return 0;
+}
+
+#endif				/* UNITTEST */
+
+/**
+ * init_crc32(): generates CRC32 tables
+ * 
+ * On successful initialization, use count is increased.
+ * This guarantees that the library functions will stay resident
+ * in memory, and prevents someone from 'rmmod crc32' while
+ * a driver that needs it is still loaded.
+ * This also greatly simplifies drivers, as there's no need
+ * to call an initialization/cleanup function from each driver.
+ * Since crc32.o is a library module, there's no requirement
+ * that the user can unload it.
+ */
+static int __init init_crc32(void)
+{
+	int rc1, rc2, rc;
+	rc1 = crc32init_le();
+	rc2 = crc32init_be();
+	rc = rc1 || rc2;
+	if (!rc) MOD_INC_USE_COUNT;
+	return rc;
+}
+
+/**
+ * cleanup_crc32(): frees crc32 data when no longer needed
+ */
+static void cleanup_crc32(void)
+{
+	crc32cleanup_le();
+	crc32cleanup_be();
+}
+
+module_init(init_crc32);
+module_exit(cleanup_crc32);
+
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(crc32_be);
diff -urN linux-2.5.2-pre11/mm/bootmem.c linux/mm/bootmem.c
--- linux-2.5.2-pre11/mm/bootmem.c	Tue Nov 27 09:23:27 2001
+++ linux/mm/bootmem.c	Mon Jan 14 18:28:32 2002
@@ -155,6 +155,12 @@
 	if (align & (align-1))
 		BUG();
 
+	offset = 0;
+	if (align &&
+	    (bdata->node_boot_start & (align - 1UL)) != 0)
+		offset = (align - (bdata->node_boot_start & (align - 1UL)));
+	offset >>= PAGE_SHIFT;
+
 	/*
 	 * We try to allocate bootmem pages above 'goal'
 	 * first, then we try to allocate lower pages.
@@ -166,6 +172,7 @@
 		preferred = 0;
 
 	preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
+	preferred += offset;
 	areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
 	incr = align >> PAGE_SHIFT ? : 1;
 
@@ -185,7 +192,7 @@
 	fail_block:;
 	}
 	if (preferred) {
-		preferred = 0;
+		preferred = offset;
 		goto restart_scan;
 	}
 	return NULL;
diff -urN linux-2.5.2-pre11/mm/highmem.c linux/mm/highmem.c
--- linux-2.5.2-pre11/mm/highmem.c	Mon Jan 14 18:28:25 2002
+++ linux/mm/highmem.c	Mon Jan 14 18:28:32 2002
@@ -25,7 +25,7 @@
 
 static void *page_pool_alloc(int gfp_mask, void *data)
 {
-	int gfp = gfp_mask | (int) data;
+	int gfp = gfp_mask | (int) (long) data;
 
 	return alloc_page(gfp);
 }
diff -urN linux-2.5.2-pre11/mm/page_io.c linux/mm/page_io.c
--- linux-2.5.2-pre11/mm/page_io.c	Mon Jan 14 18:28:25 2002
+++ linux/mm/page_io.c	Mon Jan 14 18:28:32 2002
@@ -38,9 +38,9 @@
 	unsigned long offset;
 	sector_t zones[PAGE_SIZE/512];
 	int zones_used;
-	kdev_t dev = NODEV;
 	int block_size;
 	struct inode *swapf = 0;
+	struct block_device *bdev;
 
 	if (rw == READ) {
 		ClearPageUptodate(page);
@@ -48,12 +48,13 @@
 	} else
 		kstat.pswpout++;
 
-	get_swaphandle_info(entry, &offset, &dev, &swapf);
-	if (!kdev_none(dev)) {
+	get_swaphandle_info(entry, &offset, &swapf);
+	bdev = swapf->i_bdev;
+	if (bdev) {
 		zones[0] = offset;
 		zones_used = 1;
 		block_size = PAGE_SIZE;
-	} else if (swapf) {
+	} else {
 		int i, j;
 		unsigned int block = offset
 			<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
@@ -65,13 +66,11 @@
 				return 0;
 			}
 		zones_used = i;
-		dev = swapf->i_dev;
-	} else {
-		return 0;
+		bdev = swapf->i_sb->s_bdev;
 	}
 
  	/* block_size == PAGE_SIZE/zones_used */
- 	brw_page(rw, page, dev, zones, block_size);
+ 	brw_page(rw, page, bdev, zones, block_size);
 
  	/* Note! For consistency we do all of the logic,
  	 * decrementing the page count, and unlocking the page in the
diff -urN linux-2.5.2-pre11/mm/swapfile.c linux/mm/swapfile.c
--- linux-2.5.2-pre11/mm/swapfile.c	Mon Jan 14 18:28:25 2002
+++ linux/mm/swapfile.c	Mon Jan 14 18:28:32 2002
@@ -11,7 +11,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
 #include <linux/swapctl.h>
-#include <linux/blkdev.h> /* for blk_size */
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
 #include <linux/shm.h>
@@ -713,6 +712,7 @@
 {
 	struct swap_info_struct * p = NULL;
 	unsigned short *swap_map;
+	struct file *swap_file;
 	struct nameidata nd;
 	int i, type, prev;
 	int err;
@@ -730,8 +730,8 @@
 	for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
 		p = swap_info + type;
 		if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-			if (p->swap_file == nd.dentry)
-			  break;
+			if (p->swap_file->f_dentry == nd.dentry)
+				break;
 		}
 		prev = type;
 	}
@@ -774,15 +774,9 @@
 		swap_list_unlock();
 		goto out_dput;
 	}
-	if (!kdev_none(p->swap_device))
-		blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
-	path_release(&nd);
-
 	swap_list_lock();
 	swap_device_lock(p);
-	nd.mnt = p->swap_vfsmnt;
-	nd.dentry = p->swap_file;
-	p->swap_vfsmnt = NULL;
+	swap_file = p->swap_file;
 	p->swap_file = NULL;
 	p->swap_device = NODEV;
 	p->max = 0;
@@ -792,6 +786,7 @@
 	swap_device_unlock(p);
 	swap_list_unlock();
 	vfree(swap_map);
+	filp_close(swap_file, NULL);
 	err = 0;
 
 out_dput:
@@ -813,7 +808,8 @@
 	len = sprintf(buf, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if ((ptr->flags & SWP_USED) && ptr->swap_map) {
-			char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt,
+			char * path = d_path(ptr->swap_file->f_dentry,
+						ptr->swap_file->f_vfsmnt,
 						page, PAGE_SIZE);
 			int j, usedswap = 0;
 			for (j = 0; j < ptr->max; ++j)
@@ -826,7 +822,7 @@
 				}
 			len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
 				       path,
-				       kdev_none(ptr->swap_device) ? "file\t" : "partition",
+				       !kdev_none(ptr->swap_device) ? "partition" : "file\t",
 				       ptr->pages << (PAGE_SHIFT - 10),
 				       usedswap << (PAGE_SHIFT - 10),
 				       ptr->prio);
@@ -856,8 +852,9 @@
 asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
 {
 	struct swap_info_struct * p;
-	struct nameidata nd;
-	struct inode * swap_inode;
+	char *name;
+	struct file *swap_file = NULL;
+	struct address_space *mapping;
 	unsigned int type;
 	int i, j, prev;
 	int error;
@@ -867,7 +864,6 @@
 	int nr_good_pages = 0;
 	unsigned long maxpages = 1;
 	int swapfilesize;
-	struct block_device *bdev = NULL;
 	unsigned short *swap_map;
 	
 	if (!capable(CAP_SYS_ADMIN))
@@ -887,7 +883,6 @@
 		nr_swapfiles = type+1;
 	p->flags = SWP_USED;
 	p->swap_file = NULL;
-	p->swap_vfsmnt = NULL;
 	p->swap_device = NODEV;
 	p->swap_map = NULL;
 	p->lowest_bit = 0;
@@ -902,53 +897,33 @@
 		p->prio = --least_priority;
 	}
 	swap_list_unlock();
-	error = user_path_walk(specialfile, &nd);
+	name = getname(specialfile);
+	error = PTR_ERR(name);
+	if (IS_ERR(name))
+		goto bad_swap_2;
+	swap_file = filp_open(name, O_RDWR, 0);
+	putname(name);
+	error = PTR_ERR(swap_file);
 	if (error)
 		goto bad_swap_2;
 
-	p->swap_file = nd.dentry;
-	p->swap_vfsmnt = nd.mnt;
-	swap_inode = nd.dentry->d_inode;
-	error = -EINVAL;
-
-	if (S_ISBLK(swap_inode->i_mode)) {
-		kdev_t dev = swap_inode->i_rdev;
-		struct block_device_operations *bdops;
-		devfs_handle_t de;
+	p->swap_file = swap_file;
 
-		p->swap_device = dev;
-		set_blocksize(dev, PAGE_SIZE);
-		
-		bd_acquire(swap_inode);
-		bdev = swap_inode->i_bdev;
-		de = devfs_get_handle_from_inode(swap_inode);
-		bdops = devfs_get_ops(de);  /*  Increments module use count  */
-		if (bdops) bdev->bd_op = bdops;
-
-		error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
-		devfs_put_ops(de);/*Decrement module use count now we're safe*/
-		if (error)
-			goto bad_swap_2;
-		set_blocksize(dev, PAGE_SIZE);
-		error = -ENODEV;
-		if (kdev_none(dev) || (blk_size[major(dev)] &&
-		     !blk_size[major(dev)][minor(dev)]))
-			goto bad_swap;
-		swapfilesize = 0;
-		if (blk_size[major(dev)])
-			swapfilesize = blk_size[major(dev)][minor(dev)]
-				>> (PAGE_SHIFT - 10);
-	} else if (S_ISREG(swap_inode->i_mode))
-		swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
-	else
+	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
+		p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
+		set_blocksize(p->swap_device, PAGE_SIZE);
+	} else if (!S_ISREG(swap_file->f_dentry->d_inode->i_mode))
 		goto bad_swap;
 
+	mapping = swap_file->f_dentry->d_inode->i_mapping;
+	swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
+
 	error = -EBUSY;
 	for (i = 0 ; i < nr_swapfiles ; i++) {
 		struct swap_info_struct *q = &swap_info[i];
 		if (i == type || !q->swap_file)
 			continue;
-		if (swap_inode->i_mapping == q->swap_file->d_inode->i_mapping)
+		if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
 			goto bad_swap;
 	}
 
@@ -1085,16 +1060,11 @@
 	error = 0;
 	goto out;
 bad_swap:
-	if (bdev)
-		blkdev_put(bdev, BDEV_SWAP);
 bad_swap_2:
 	swap_list_lock();
 	swap_map = p->swap_map;
-	nd.mnt = p->swap_vfsmnt;
-	nd.dentry = p->swap_file;
 	p->swap_device = NODEV;
 	p->swap_file = NULL;
-	p->swap_vfsmnt = NULL;
 	p->swap_map = NULL;
 	p->flags = 0;
 	if (!(swap_flags & SWAP_FLAG_PREFER))
@@ -1102,7 +1072,8 @@
 	swap_list_unlock();
 	if (swap_map)
 		vfree(swap_map);
-	path_release(&nd);
+	if (swap_file)
+		filp_close(swap_file, NULL);
 out:
 	if (swap_header)
 		free_page((long) swap_header);
@@ -1219,7 +1190,7 @@
  * Prior swap_duplicate protects against swap device deletion.
  */
 void get_swaphandle_info(swp_entry_t entry, unsigned long *offset, 
-			kdev_t *dev, struct inode **swapf)
+			struct inode **swapf)
 {
 	unsigned long type;
 	struct swap_info_struct *p;
@@ -1245,14 +1216,7 @@
 		return;
 	}
 
-	if (!kdev_none(p->swap_device)) {
-		*dev = p->swap_device;
-	} else if (p->swap_file) {
-		*swapf = p->swap_file->d_inode;
-	} else {
-		printk(KERN_ERR "rw_swap_page: no swap file or device\n");
-	}
-	return;
+	*swapf = p->swap_file->f_dentry->d_inode;
 }
 
 /*
diff -urN linux-2.5.2-pre11/net/8021q/vlan.c linux/net/8021q/vlan.c
--- linux-2.5.2-pre11/net/8021q/vlan.c	Tue Oct 30 15:08:12 2001
+++ linux/net/8021q/vlan.c	Mon Jan 14 18:28:32 2002
@@ -1,11 +1,10 @@
 /*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
+ * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
- * Authors:	Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *              Please send support related email to: vlan@scry.wanfear.com
+ *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
  * 
  * Fixes:
  *              Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
@@ -42,7 +41,7 @@
 
 static char vlan_fullname[] = "802.1Q VLAN Support";
 static unsigned int vlan_version = 1;
-static unsigned int vlan_release = 5;
+static unsigned int vlan_release = 6;
 static char vlan_copyright[] = " Ben Greear <greearb@candelatech.com>";
 
 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
@@ -106,6 +105,23 @@
 }
 
 /*
+ * Cleanup of groups before exit
+ */
+
+static void vlan_group_cleanup(void)
+{
+	struct vlan_group *grp = NULL;
+	struct vlan_group *nextgroup;
+
+	for (grp = p802_1Q_vlan_list; (grp != NULL);) {
+		nextgroup = grp->next;
+		kfree(grp);
+		grp = nextgroup;
+	}
+	p802_1Q_vlan_list = NULL;
+}
+
+/*
  *     Module 'remove' entry point.
  *     o delete /proc/net/router directory and static entries.
  */ 
@@ -116,7 +132,7 @@
 
 	dev_remove_pack(&vlan_packet_type);
 	vlan_proc_cleanup();
-
+	vlan_group_cleanup();
 	vlan_ioctl_hook = NULL;
 }
 
@@ -328,6 +344,7 @@
 	/* set up method calls */
 	new_dev->init = vlan_dev_init;
 	new_dev->destructor = vlan_dev_destruct;
+	new_dev->features |= NETIF_F_DYNALLOC ; 
 	    
 	/* new_dev->ifindex = 0;  it will be set when added to
 	 * the global list.
diff -urN linux-2.5.2-pre11/net/8021q/vlan_dev.c linux/net/8021q/vlan_dev.c
--- linux-2.5.2-pre11/net/8021q/vlan_dev.c	Tue Oct 30 15:08:12 2001
+++ linux/net/8021q/vlan_dev.c	Mon Jan 14 18:28:32 2002
@@ -1,11 +1,10 @@
 /*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
+ * INET		802.1Q VLAN
  *		Ethernet-type device handling.
  *
- * Authors:	Ben Greear <greearb@candelatech.com>, <greearb@agcs.com>
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *              Please send support related email to: vlan@scry.wanfear.com
+ *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
  * 
  * Fixes:       Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com>
  *                - reset skb->pkt_type on incoming packets when MAC was changed
@@ -512,10 +511,6 @@
 			VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv);
 			dev->priv = NULL;
 		}
-
-		kfree(dev);
-		VLAN_FMEM_DBG("net_device free, addr: %p\n", dev);
-		dev = NULL;
 	}
 }
 
diff -urN linux-2.5.2-pre11/net/8021q/vlanproc.c linux/net/8021q/vlanproc.c
--- linux-2.5.2-pre11/net/8021q/vlanproc.c	Mon Jan 14 18:28:25 2002
+++ linux/net/8021q/vlanproc.c	Mon Jan 14 18:28:32 2002
@@ -115,7 +115,7 @@
  *	Clean up /proc/net/vlan entries
  */
 
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
 {
 	if (proc_vlan_conf)
 		remove_proc_entry(name_conf, proc_vlan_dir);
@@ -461,7 +461,7 @@
 	return 0;
 }
 
-void __exit vlan_proc_cleanup(void)
+void vlan_proc_cleanup(void)
 {
 	return;
 }
diff -urN linux-2.5.2-pre11/net/Config.in linux/net/Config.in
--- linux-2.5.2-pre11/net/Config.in	Tue Oct 30 15:08:12 2001
+++ linux/net/Config.in	Mon Jan 14 18:28:32 2002
@@ -61,7 +61,7 @@
 if [ "$CONFIG_DECNET" != "n" ]; then
    source net/decnet/Config.in
 fi
-tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
+dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
diff -urN linux-2.5.2-pre11/net/README linux/net/README
--- linux-2.5.2-pre11/net/README	Mon Jun 11 19:15:27 2001
+++ linux/net/README	Mon Jan 14 18:28:32 2002
@@ -23,4 +23,4 @@
 unix			alan@lxorguk.ukuu.org.uk
 x25			g4klx@g4klx.demon.co.uk
 bluetooth		maxk@qualcomm.com
-
+8021q                   greearb@candelatech.com, vlan@scry.wanfear.com
diff -urN linux-2.5.2-pre11/net/bridge/br.c linux/net/bridge/br.c
--- linux-2.5.2-pre11/net/bridge/br.c	Wed Oct 17 14:16:39 2001
+++ linux/net/bridge/br.c	Mon Jan 14 18:28:32 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br.c,v 1.46 2001/10/02 02:22:36 davem Exp $
+ *	$Id: br.c,v 1.47 2001/12/24 00:56:41 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -43,9 +43,7 @@
 	printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
 
 	br_handle_frame_hook = br_handle_frame;
-#ifdef CONFIG_INET
 	br_ioctl_hook = br_ioctl_deviceless_stub;
-#endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	br_fdb_get_hook = br_fdb_get;
 	br_fdb_put_hook = br_fdb_put;
@@ -62,9 +60,7 @@
 
 static void __br_clear_ioctl_hook(void)
 {
-#ifdef CONFIG_INET
 	br_ioctl_hook = NULL;
-#endif	
 }
 
 static void __exit br_deinit(void)
diff -urN linux-2.5.2-pre11/net/bridge/br_device.c linux/net/bridge/br_device.c
--- linux-2.5.2-pre11/net/bridge/br_device.c	Wed Aug 15 01:54:30 2001
+++ linux/net/bridge/br_device.c	Mon Jan 14 18:28:32 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_device.c,v 1.5 2001/08/14 22:05:57 davem Exp $
+ *	$Id: br_device.c,v 1.6 2001/12/24 00:59:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -71,7 +71,7 @@
 	return 0;
 }
 
-static int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_bridge *br;
 	int ret;
diff -urN linux-2.5.2-pre11/net/bridge/br_if.c linux/net/bridge/br_if.c
--- linux-2.5.2-pre11/net/bridge/br_if.c	Thu Nov  9 15:57:53 2000
+++ linux/net/bridge/br_if.c	Mon Jan 14 18:28:32 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ *	$Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -226,6 +226,9 @@
 	if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
 		return -EINVAL;
 
+	if (dev->hard_start_xmit == br_dev_xmit)
+		return -ELOOP;
+
 	dev_hold(dev);
 	write_lock_bh(&br->lock);
 	if ((p = new_nbp(br, dev)) == NULL) {
@@ -261,8 +264,6 @@
 {
 	struct net_bridge *br;
 	int i;
-
-	i = 0;
 
 	br = bridge_list;
 	for (i=0;i<num;i++) {
diff -urN linux-2.5.2-pre11/net/bridge/br_input.c linux/net/bridge/br_input.c
--- linux-2.5.2-pre11/net/bridge/br_input.c	Wed Aug 15 01:54:39 2001
+++ linux/net/bridge/br_input.c	Mon Jan 14 18:28:32 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_input.c,v 1.9 2001/08/14 22:05:57 davem Exp $
+ *	$Id: br_input.c,v 1.10 2001/12/24 04:50:20 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -46,7 +46,7 @@
 			br_pass_frame_up_finish);
 }
 
-static void __br_handle_frame(struct sk_buff *skb)
+static int br_handle_frame_finish(struct sk_buff *skb)
 {
 	struct net_bridge *br;
 	unsigned char *dest;
@@ -57,103 +57,112 @@
 	dest = skb->mac.ethernet->h_dest;
 
 	p = skb->dev->br_port;
-	br = p->br;
-	passedup = 0;
+	if (p == NULL)
+		goto err_nolock;
 
-	if (!(br->dev.flags & IFF_UP) ||
-	    p->state == BR_STATE_DISABLED)
-		goto freeandout;
+	br = p->br;
+	read_lock(&br->lock);
+	if (skb->dev->br_port == NULL)
+		goto err;
 
+	passedup = 0;
 	if (br->dev.flags & IFF_PROMISC) {
 		struct sk_buff *skb2;
 
 		skb2 = skb_clone(skb, GFP_ATOMIC);
-		if (skb2) {
+		if (skb2 != NULL) {
 			passedup = 1;
 			br_pass_frame_up(br, skb2);
 		}
 	}
 
-	if (skb->mac.ethernet->h_source[0] & 1)
-		goto freeandout;
-
-	if (!passedup &&
-	    (dest[0] & 1) &&
-	    (br->dev.flags & IFF_ALLMULTI || br->dev.mc_list != NULL)) {
-		struct sk_buff *skb2;
-
-		skb2 = skb_clone(skb, GFP_ATOMIC);
-		if (skb2) {
-			passedup = 1;
-			br_pass_frame_up(br, skb2);
-		}
-	}
-
-	if (br->stp_enabled &&
-	    !memcmp(dest, bridge_ula, 5) &&
-	    !(dest[5] & 0xF0))
-		goto handle_special_frame;
-
-	if (p->state == BR_STATE_LEARNING ||
-	    p->state == BR_STATE_FORWARDING)
-		br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
-
-	if (p->state != BR_STATE_FORWARDING)
-		goto freeandout;
-
 	if (dest[0] & 1) {
-		br_flood_forward(br, skb, 1);
+		br_flood_forward(br, skb, !passedup);
 		if (!passedup)
 			br_pass_frame_up(br, skb);
-		else
-			kfree_skb(skb);
-		return;
+		goto out;
 	}
 
 	dst = br_fdb_get(br, dest);
-
 	if (dst != NULL && dst->is_local) {
 		if (!passedup)
 			br_pass_frame_up(br, skb);
 		else
 			kfree_skb(skb);
 		br_fdb_put(dst);
-		return;
+		goto out;
 	}
 
 	if (dst != NULL) {
 		br_forward(dst->dst, skb);
 		br_fdb_put(dst);
-		return;
+		goto out;
 	}
 
 	br_flood_forward(br, skb, 0);
-	return;
 
- handle_special_frame:
-	if (!dest[5]) {
-		br_stp_handle_bpdu(skb);
-		return;
-	}
+out:
+	read_unlock(&br->lock);
+	return 0;
 
- freeandout:
+err:
+	read_unlock(&br->lock);
+err_nolock:
 	kfree_skb(skb);
+	return 0;
 }
 
-static int br_handle_frame_finish(struct sk_buff *skb)
+void br_handle_frame(struct sk_buff *skb)
 {
 	struct net_bridge *br;
+	unsigned char *dest;
+	struct net_bridge_port *p;
 
-	br = skb->dev->br_port->br;
+	dest = skb->mac.ethernet->h_dest;
+
+	p = skb->dev->br_port;
+	if (p == NULL)
+		goto err_nolock;
+
+	br = p->br;
 	read_lock(&br->lock);
-	__br_handle_frame(skb);
-	read_unlock(&br->lock);
+	if (skb->dev->br_port == NULL)
+		goto err;
 
-	return 0;
-}
+	if (!(br->dev.flags & IFF_UP) ||
+	    p->state == BR_STATE_DISABLED)
+		goto err;
 
-void br_handle_frame(struct sk_buff *skb)
-{
-	NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+	if (skb->mac.ethernet->h_source[0] & 1)
+		goto err;
+
+	if (p->state == BR_STATE_LEARNING ||
+	    p->state == BR_STATE_FORWARDING)
+		br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
+
+	if (br->stp_enabled &&
+	    !memcmp(dest, bridge_ula, 5) &&
+	    !(dest[5] & 0xF0))
+		goto handle_special_frame;
+
+	if (p->state == BR_STATE_FORWARDING) {
+		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 			br_handle_frame_finish);
+		read_unlock(&br->lock);
+		return;
+	}
+
+err:
+	read_unlock(&br->lock);
+err_nolock:
+	kfree_skb(skb);
+	return;
+
+handle_special_frame:
+	if (!dest[5]) {
+		br_stp_handle_bpdu(skb);
+		return;
+	}
+
+	kfree_skb(skb);
 }
diff -urN linux-2.5.2-pre11/net/bridge/br_private.h linux/net/bridge/br_private.h
--- linux-2.5.2-pre11/net/bridge/br_private.h	Mon Jun 11 19:15:27 2001
+++ linux/net/bridge/br_private.h	Mon Jan 14 18:28:32 2002
@@ -4,7 +4,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_private.h,v 1.6 2001/06/01 09:28:28 davem Exp $
+ *	$Id: br_private.h,v 1.7 2001/12/24 00:59:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -121,6 +121,7 @@
 
 /* br_device.c */
 extern void br_dev_setup(struct net_device *dev);
+extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* br_fdb.c */
 extern void br_fdb_changeaddr(struct net_bridge_port *p,
diff -urN linux-2.5.2-pre11/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- linux-2.5.2-pre11/net/ipv4/icmp.c	Wed Nov  7 14:39:36 2001
+++ linux/net/ipv4/icmp.c	Mon Jan 14 18:28:32 2002
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.82 2001/11/01 23:44:31 davem Exp $
+ *	Version: $Id: icmp.c,v 1.83 2001/12/13 09:00:19 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -154,8 +154,8 @@
  * 	it's bit position.
  *
  *	default: 
- *	dest unreachable (0x03), source quench (0x04),
- *	time exceeded (0x11), parameter problem (0x12)
+ *	dest unreachable (3), source quench (4),
+ *	time exceeded (11), parameter problem (12)
  */
 
 int sysctl_icmp_ratelimit = 1*HZ;
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_conntrack_irc.c linux/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_conntrack_irc.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/ip_conntrack_irc.c	Mon Jan 14 18:28:32 2002
@@ -1,8 +1,8 @@
-/* IRC extension for IP connection tracking, Version 1.19
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+/* IRC extension for IP connection tracking, Version 1.20
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  * based on RR's ip_conntrack_ftp.c	
  *
- * ip_conntrack_irc.c,v 1.19 2001/10/25 14:34:21 laforge Exp
+ * ip_conntrack_irc.c,v 1.20 2001/12/06 07:42:10 laforge Exp
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
  *      2 of the License, or (at your option) any later version.
  **
  *	Module load syntax:
- * 	insmod ip_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
+ * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
  *	
  * 	please give the ports of all IRC servers You wish to connect to.
  *	If You don't specify ports, the default will be port 6667
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_conntrack_standalone.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Jan 14 18:28:32 2002
@@ -243,7 +243,7 @@
 
 	ret = nf_register_hook(&ip_conntrack_in_ops);
 	if (ret < 0) {
-		printk("ip_conntrack: can't register in hook.\n");
+		printk("ip_conntrack: can't register pre-routing hook.\n");
 		goto cleanup_proc;
 	}
 	ret = nf_register_hook(&ip_conntrack_local_out_ops);
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_fw_compat.c	Sat Nov 10 15:36:38 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat.c	Mon Jan 14 18:28:32 2002
@@ -84,6 +84,16 @@
 	if ((*pskb)->ip_summed == CHECKSUM_HW)
 		(*pskb)->ip_summed = CHECKSUM_NONE;
 
+	/* Firewall rules can alter TOS: raw socket (tcpdump) may have
+           clone of incoming skb: don't disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
 	switch (hooknum) {
 	case NF_IP_PRE_ROUTING:
 		if (fwops->fw_acct_in)
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_fw_compat_redir.c	Fri Aug  4 13:07:24 2000
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Mon Jan 14 18:28:32 2002
@@ -206,6 +206,8 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
+			redir->destroyme.expires = jiffies + 75*HZ;
+			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
 		redir->core = ((struct redir_core)
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_core.c	Sat Nov 10 15:36:38 2001
+++ linux/net/ipv4/netfilter/ip_nat_core.c	Mon Jan 14 18:28:32 2002
@@ -734,6 +734,18 @@
 	   synchronize_bh()) can vanish. */
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
+		/* raw socket (tcpdump) may have clone of incoming
+                   skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb) {
+				READ_UNLOCK(&ip_nat_lock);
+				return NF_DROP;
+			}
+			kfree_skb(*pskb);
+			*pskb = nskb;
+		}
+
 		if (info->manips[i].direction == dir
 		    && info->manips[i].hooknum == hooknum) {
 			DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_helper.c linux/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_helper.c	Tue Aug 28 07:09:44 2001
+++ linux/net/ipv4/netfilter/ip_nat_helper.c	Mon Jan 14 18:28:32 2002
@@ -143,6 +143,23 @@
 		}
 	}
 
+	/* Alexey says: if a hook changes _data_ ... it can break
+	   original packet sitting in tcp queue and this is fatal */
+	if (skb_cloned(*skb)) {
+		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
+		if (!nskb) {
+			if (net_ratelimit())
+				printk("Out of memory cloning TCP packet\n");
+			return 0;
+		}
+		/* Rest of kernel will get very unhappy if we pass it
+		   a suddenly-orphaned skbuff */
+		if ((*skb)->sk)
+			skb_set_owner_w(nskb, (*skb)->sk);
+		kfree_skb(*skb);
+		*skb = nskb;
+	}
+
 	/* skb may be copied !! */
 	iph = (*skb)->nh.iph;
 	tcph = (void *)iph + iph->ihl*4;
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_irc.c linux/net/ipv4/netfilter/ip_nat_irc.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ip_nat_irc.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/ip_nat_irc.c	Mon Jan 14 18:28:32 2002
@@ -1,8 +1,8 @@
 /* IRC extension for TCP NAT alteration.
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  * based on a copy of RR's ip_nat_ftp.c
  *
- * ip_nat_irc.c,v 1.15 2001/10/22 10:43:53 laforge Exp
+ * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -81,7 +81,7 @@
 	}
 
 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-	newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
 
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ipt_MIRROR.c linux/net/ipv4/netfilter/ipt_MIRROR.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ipt_MIRROR.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipt_MIRROR.c	Mon Jan 14 18:28:32 2002
@@ -6,6 +6,10 @@
 
   Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
 
+  Changes:
+	25 Aug 2001 Harald Welte <laforge@gnumonks.org>
+		- decrement and check TTL if not called from FORWARD hook
+
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
@@ -24,6 +28,7 @@
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <net/ip.h>
+#include <net/icmp.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netdevice.h>
 #include <linux/route.h>
@@ -100,15 +105,31 @@
 				      const void *targinfo,
 				      void *userinfo)
 {
-	if ((*pskb)->dst != NULL) {
-		if (route_mirror(*pskb)) {
-			ip_rewrite(*pskb);
-			/* Don't let conntrack code see this packet:
-                           it will think we are starting a new
-                           connection! --RR */
-			ip_direct_send(*pskb);
-			return NF_STOLEN;
+	if (((*pskb)->dst != NULL) &&
+	    route_mirror(*pskb)) {
+
+		ip_rewrite(*pskb);
+
+		/* If we are not at FORWARD hook (INPUT/PREROUTING),
+		 * the TTL isn't decreased by the IP stack */
+		if (hooknum != NF_IP_FORWARD) {
+			struct iphdr *iph = (*pskb)->nh.iph;
+			if (iph->ttl <= 1) {
+				/* this will traverse normal stack, and 
+				 * thus call conntrack on the icmp packet */
+				icmp_send(*pskb, ICMP_TIME_EXCEEDED, 
+					  ICMP_EXC_TTL, 0);
+				return NF_DROP;
+			}
+			ip_decrease_ttl(iph);
 		}
+
+		/* Don't let conntrack code see this packet:
+                   it will think we are starting a new
+                   connection! --RR */
+		ip_direct_send(*pskb);
+
+		return NF_STOLEN;
 	}
 	return NF_DROP;
 }
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ipt_TCPMSS.c linux/net/ipv4/netfilter/ipt_TCPMSS.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ipt_TCPMSS.c	Sat Nov 10 15:36:38 2001
+++ linux/net/ipv4/netfilter/ipt_TCPMSS.c	Mon Jan 14 18:28:32 2002
@@ -44,11 +44,22 @@
 {
 	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
 	struct tcphdr *tcph;
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph;
 	u_int16_t tcplen, newtotlen, oldval, newmss;
 	unsigned int i;
 	u_int8_t *opt;
 
+	/* raw socket (tcpdump) may have clone of incoming skb: don't
+	   disturb it --RR */
+	if (skb_cloned(*pskb) && !(*pskb)->sk) {
+		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
+	iph = (*pskb)->nh.iph;
 	tcplen = (*pskb)->len - iph->ihl*4;
 
 	tcph = (void *)iph + iph->ihl*4;
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ipt_TOS.c linux/net/ipv4/netfilter/ipt_TOS.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ipt_TOS.c	Sat Nov 10 15:36:38 2001
+++ linux/net/ipv4/netfilter/ipt_TOS.c	Mon Jan 14 18:28:32 2002
@@ -21,6 +21,17 @@
 	if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
 		u_int16_t diffs[2];
 
+		/* raw socket (tcpdump) may have clone of incoming
+                   skb: don't disturb it --RR */
+		if (skb_cloned(*pskb) && !(*pskb)->sk) {
+			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
+			if (!nskb)
+				return NF_DROP;
+			kfree_skb(*pskb);
+			*pskb = nskb;
+			iph = (*pskb)->nh.iph;
+		}
+
 		diffs[0] = htons(iph->tos) ^ 0xFFFF;
 		iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
 		diffs[1] = htons(iph->tos);
diff -urN linux-2.5.2-pre11/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.5.2-pre11/net/ipv4/netfilter/ipt_unclean.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipt_unclean.c	Mon Jan 14 18:28:32 2002
@@ -257,6 +257,8 @@
 #define	TH_PUSH	0x08
 #define	TH_ACK	0x10
 #define	TH_URG	0x20
+#define	TH_ECE	0x40
+#define	TH_CWR	0x80
 
 /* TCP-specific checks. */
 static int
@@ -328,9 +330,10 @@
 	}
 
 	/* CHECK: TCP flags. */
-	tcpflags = ((u_int8_t *)tcph)[13];
+	tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
 	if (tcpflags != TH_SYN
 	    && tcpflags != (TH_SYN|TH_ACK)
+		&& tcpflags != TH_RST
 	    && tcpflags != (TH_RST|TH_ACK)
 	    && tcpflags != (TH_RST|TH_ACK|TH_PUSH)
 	    && tcpflags != (TH_FIN|TH_ACK)
diff -urN linux-2.5.2-pre11/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- linux-2.5.2-pre11/net/ipv6/tcp_ipv6.c	Mon Nov  5 09:46:12 2001
+++ linux/net/ipv6/tcp_ipv6.c	Mon Jan 14 18:28:32 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.140 2001/10/15 12:34:50 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.143 2001/12/21 05:05:41 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -1172,6 +1172,7 @@
 
 	tcp_parse_options(skb, &tp, 0);
 
+	tp.tstamp_ok = tp.saw_tstamp;
 	tcp_openreq_init(req, &tp, skb);
 
 	req->class = &or_ipv6;
diff -urN linux-2.5.2-pre11/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- linux-2.5.2-pre11/net/sunrpc/sched.c	Mon Jan 14 18:28:25 2002
+++ linux/net/sunrpc/sched.c	Mon Jan 14 18:28:32 2002
@@ -21,6 +21,7 @@
 #include <linux/spinlock.h>
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
 
 #ifdef RPC_DEBUG
 #define RPCDBG_FACILITY		RPCDBG_SCHED
diff -urN linux-2.5.2-pre11/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- linux-2.5.2-pre11/net/sunrpc/xprt.c	Mon Oct  8 12:36:07 2001
+++ linux/net/sunrpc/xprt.c	Mon Jan 14 18:28:32 2002
@@ -630,10 +630,14 @@
 			int to_move = cur_len;
 			if (to_move > copied)
 				to_move = copied;
-			if (need_csum)
-				csum = skb_copy_and_csum_bits(skb, offset, cur_ptr,
-							      to_move, csum);
-			else
+			if (need_csum) {
+				unsigned int csum2;
+
+				csum2 = skb_copy_and_csum_bits(skb, offset,
+							       cur_ptr,
+							       to_move, 0);
+				csum = csum_block_add(csum, csum2, offset);
+			} else
 				skb_copy_bits(skb, offset, cur_ptr, to_move);
 			offset += to_move;
 			copied -= to_move;
@@ -647,8 +651,12 @@
 		}
 	}
 	if (need_csum) {
-		if (slack > 0)
-			csum = skb_checksum(skb, offset, slack, csum);
+		if (slack > 0) {
+			unsigned int csum2;
+
+			csum2 = skb_checksum(skb, offset, slack, 0);
+			csum = csum_block_add(csum, csum2, offset);
+		}
 		if ((unsigned short)csum_fold(csum))
 			return -1;
 	}
