diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/Documentation/Configure.help linux-2.4.28-pre1/Documentation/Configure.help
--- linux-2.4.27/Documentation/Configure.help	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/Documentation/Configure.help	2004-08-15 19:51:41.354124056 +0000
@@ -696,6 +696,24 @@ CONFIG_BLK_DEV_IDE
   could say N here, and select the "Old hard disk driver" below
   instead to save about 13 KB of memory in the kernel.
 
+Support for SATA (deprecated; conflicts with libata SATA driver)
+CONFIG_BLK_DEV_IDE_SATA
+  There are two drivers for Serial ATA controllers.
+
+  The main driver, "libata", exists inside the SCSI subsystem
+  and supports most modern SATA controllers.
+
+  The IDE driver (which you are currently configuring) supports
+  a few first-generation SATA controllers.
+
+  In order to eliminate conflicts between the two subsystems,
+  this config option enables the IDE driver's SATA support.
+  Normally this is disabled, as it is preferred that libata
+  supports SATA controllers, and this (IDE) driver supports
+  PATA controllers.
+
+  If unsure, say N.
+
 Old hard disk (MFM/RLL/IDE) driver
 CONFIG_BLK_DEV_HD_ONLY
   There are two drivers for MFM/RLL/IDE hard disks. Most people use
@@ -10077,6 +10095,49 @@ CONFIG_AIRONET4500_CS
   compile it as a module, say M here and read
   <file:Documentation/modules.txt>.
 
+Intersil 802.11(a/b/g) Prism GT/Duette/Indigo support
+CONFIG_PRISM54
+  Enable PCI and Cardbus support for the following chipset based cards:
+
+  ISL3880 - Prism GT		802.11 b/g
+  ISL3877 - Prism Indigo	802.11 a
+  ISL3890 - Prism Duette	802.11 a/b/g
+  
+  For a complete list of supported cards visit <http://prism54.org>.
+  Here is the latest confirmed list of supported cards:
+
+  3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72
+  Allnet ALL0271 PCI Card
+  Compex WL54G Cardbus Card
+  Corega CG-WLCB54GT Cardbus Card
+  D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650
+  I-O Data WN-G54/CB Cardbus Card
+  Kobishi XG-300 aka Z-Com Cardbus Card
+  Netgear WG511 Cardbus Card
+  Ovislink WL-5400PCI PCI Card
+  Peabird WLG-PCI PCI Card
+  Sitecom WL-100i Cardbus Card
+  Sitecom WL-110i PCI Card
+  SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
+  SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
+  Z-Com XG-900 PCI Card
+  Zyxel G-100 Cardbus Card
+
+  If you enable this, you require a firmware file as well.
+  You will need to copy this to /usr/lib/hotplug/firmware/isl3890.
+  You can get this non-GPL'd firmware file from the Prism54 project page:
+  <http://prism54.org>.
+  You will also need the /etc/hotplug/firmware.agent script from
+  a current hotplug package.
+
+
+  Note: You need a motherboard with DMA support to use any of these cards 
+  
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called prism54.o.
+
 Aironet 4500/4800 PROC interface
 CONFIG_AIRONET4500_PROC
   If you say Y here (and to the "/proc file system" below), you will
@@ -28932,7 +28993,7 @@ CONFIG_CRYPTO_TEA
   many rounds for security.  It is very fast and uses
   little memory.
 
-  Xtendend Tiny Encryption Algorithm is a modifcation to
+  Xtendend Tiny Encryption Algorithm is a modification to
   the TEA algorithm to address a potential key weakness
   in the TEA algorithm.
 
@@ -28944,6 +29005,16 @@ CONFIG_CRYPTO_ARC4
   WEP, but it should not be for other purposes because of the
   weakness of the algorithm.
 
+CONFIG_CRYPTO_KHAZAD
+  Khazad cipher algorithm.
+
+  Khazad was a finalist in the initial NESSIE competition.  It is
+  an algorithm optimized for 64-bit processors with good performance
+  on 32-bit processors.  Khazad uses an 128 bit key size.
+
+  See also:
+  http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html
+
 CONFIG_CRYPTO_DEFLATE
   This is the Deflate algorithm (RFC1951), specified for use in
   IPSec with the IPCOMP protocol (RFC3173, RFC2394).
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/Documentation/crypto/api-intro.txt linux-2.4.28-pre1/Documentation/crypto/api-intro.txt
--- linux-2.4.27/Documentation/crypto/api-intro.txt	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/Documentation/crypto/api-intro.txt	2004-08-15 19:52:04.543598720 +0000
@@ -219,6 +219,12 @@ AES algorithm contributors:
 CAST5/CAST6 algorithm contributors:
   Kartikey Mahendra Bhatt (original developers unknown, FSF copyright).
 
+TEA/XTEA algorithm contributors:
+  Aaron Grothe
+
+Khazad algorithm contributors:
+  Aaron Grothe
+
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
 Please send any credits updates or corrections to:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/Documentation/isdn/CREDITS linux-2.4.28-pre1/Documentation/isdn/CREDITS
--- linux-2.4.27/Documentation/isdn/CREDITS	2000-02-15 19:40:42.000000000 +0000
+++ linux-2.4.28-pre1/Documentation/isdn/CREDITS	2004-08-15 19:48:04.000000000 +0000
@@ -37,7 +37,7 @@ Michael Knigge (knick@cove.han.de)
 Andreas Kool (akool@Kool.f.EUnet.de)
   For contribution of the isdnlog/isdnrep-tool
 
-Pedro Roque Marques (roque@di.fc.ul.pt)
+Pedro Roque Marques (pedro_m@yahoo.com)
   For lot of new ideas and the pcbit driver.
 
 Eberhard Moenkeberg (emoenke@gwdg.de)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/Documentation/isdn/README.pcbit linux-2.4.28-pre1/Documentation/isdn/README.pcbit
--- linux-2.4.27/Documentation/isdn/README.pcbit	1999-11-08 00:34:00.000000000 +0000
+++ linux-2.4.28-pre1/Documentation/isdn/README.pcbit	2004-08-15 19:51:20.000000000 +0000
@@ -37,4 +37,4 @@ mailing list (isdn4linux@listserv.isdn4l
 regards,
   Pedro.
 		
-<roque@di.fc.ul.pt>
+<pedro_m@yahoo.com>
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/MAINTAINERS linux-2.4.28-pre1/MAINTAINERS
--- linux-2.4.27/MAINTAINERS	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/MAINTAINERS	2004-08-15 19:50:30.000000000 +0000
@@ -456,14 +456,20 @@ L:	omnibook@zurich.ai.mit.edu
 S:      Maintained
 
 
+HP 66Mhz FIBRE CHANNEL DRIVER
+P:	Chirag Kantharia
+M:	chirag.kantharia@hp.com
+L:	iss_storagedev@hp.com
+S:	Maintained
+
 HP SMART2 RAID DRIVER
-P:     Francis Wiran
-M:     francis.wiran@hp.com
+P:	Chirag Kantharia
+M:	chirag.kantharia@hp.com
 L:     iss_storagedev@hp.com
-S:	Odd Fixes
+S:	Maintained
 
-HP SMART CISS RAID DRIVER
-P:     Mike Miller, Michael Ni
+HP SMART ARRAY CISS RAID DRIVER (cciss)
+P:	Mike Miller
 M:     mike.miller@hp.com
 L:     iss_storagedev@hp.com
 S:	Supported
@@ -1735,8 +1741,8 @@ L:	ultralinux@vger.kernel.org
 S:	Maintained
 
 SPARC (sparc32):
-P:	Keith M. Wesolowski
-M:	wesolows@foobazco.org
+P:	William L. Irwin
+M:	wli@holomorphy.com
 L:	sparclinux@vger.kernel.org
 S:	Maintained
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/Makefile linux-2.4.28-pre1/Makefile
--- linux-2.4.27/Makefile	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/Makefile	2004-08-15 19:50:44.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 27
-EXTRAVERSION =
+SUBLEVEL = 28
+EXTRAVERSION = -pre1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/Makefile linux-2.4.28-pre1/arch/i386/Makefile
--- linux-2.4.27/arch/i386/Makefile	2003-06-13 14:51:29.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/Makefile	2004-08-15 19:49:20.000000000 +0000
@@ -94,6 +94,10 @@ ifdef CONFIG_MVIAC3_2
 CFLAGS += $(call check_gcc,-march=c3-2,-march=i686)
 endif
 
+# Disable unit-at-a-time mode, it makes gcc use a lot more stack
+# due to the lack of sharing of stacklots.
+CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
+
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/boot/compressed/misc.c linux-2.4.28-pre1/arch/i386/boot/compressed/misc.c
--- linux-2.4.27/arch/i386/boot/compressed/misc.c	2003-08-25 11:44:39.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/boot/compressed/misc.c	2004-08-15 19:50:27.000000000 +0000
@@ -104,7 +104,7 @@ static unsigned long output_ptr = 0;
 static void *malloc(int size);
 static void free(void *where);
 
-static void puts(const char *);
+static void putstr(const char *);
 
 extern int end;
 static long free_mem_ptr = (long)&end;
@@ -165,7 +165,7 @@ static void scroll(void)
 		vidmem[i] = ' ';
 }
 
-static void puts(const char *s)
+static void putstr(const char *s)
 {
 	int x,y,pos;
 	char c;
@@ -283,9 +283,9 @@ static void flush_window(void)
 
 static void error(char *x)
 {
-	puts("\n\n");
-	puts(x);
-	puts("\n\n -- System halted");
+	putstr("\n\n");
+	putstr(x);
+	putstr("\n\n -- System halted");
 
 	while(1);	/* Halt */
 }
@@ -369,9 +369,9 @@ asmlinkage int decompress_kernel(struct 
 	else setup_output_buffer_if_we_run_high(mv);
 
 	makecrc();
-	puts("Uncompressing Linux... ");
+	putstr("Uncompressing Linux... ");
 	gunzip();
-	puts("Ok, booting the kernel.\n");
+	putstr("Ok, booting the kernel.\n");
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
 	return high_loaded;
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/dmi_scan.c linux-2.4.28-pre1/arch/i386/kernel/dmi_scan.c
--- linux-2.4.27/arch/i386/kernel/dmi_scan.c	2004-04-14 13:05:25.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/dmi_scan.c	2004-08-15 19:49:25.000000000 +0000
@@ -459,6 +459,22 @@ static __init int fix_broken_hp_bios_irq
 }
 
 /*
+ * Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to
+ * IRQ 11 even though it is actually wired to IRQ 10
+ */
+static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int acer_tm360_irqrouting;
+	if (acer_tm360_irqrouting == 0) {
+		acer_tm360_irqrouting = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
+
+/*
  *	Exploding PnPBIOS. Don't yet know if its the BIOS or us for
  *	some entries
  */
@@ -820,6 +836,12 @@ static __initdata struct dmi_blacklist d
 			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
 			} },
 
+	{ fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Acer"),
+			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+			NO_MATCH, NO_MATCH
+			} },
+ 
 	/*
 	 *	Generic per vendor APM settings
 	 */
@@ -935,6 +957,13 @@ static __initdata struct dmi_blacklist d
 			/* newer BIOS, Revision 1011, does work */
 			MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
 			NO_MATCH }},
+
+	{ disable_acpi_pci, "Acer TravelMate 36x Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Acer"),
+			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+			NO_MATCH, NO_MATCH
+			} },
+ 
 #endif	/* CONFIG_ACPI_PCI */
 
 	{ NULL, }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/io_apic.c linux-2.4.28-pre1/arch/i386/kernel/io_apic.c
--- linux-2.4.27/arch/i386/kernel/io_apic.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/io_apic.c	2004-08-15 19:49:14.000000000 +0000
@@ -1349,7 +1349,7 @@ static void mask_and_ack_level_ioapic_ir
 
 #ifndef CONFIG_SMP
 
-void send_IPI_self(int vector)
+void fastcall send_IPI_self(int vector)
 {
 	unsigned int cfg;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/pci-irq.c linux-2.4.28-pre1/arch/i386/kernel/pci-irq.c
--- linux-2.4.27/arch/i386/kernel/pci-irq.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/pci-irq.c	2004-08-15 19:52:03.224799208 +0000
@@ -23,6 +23,7 @@
 #define PIRQ_VERSION 0x0100
 
 int broken_hp_bios_irq9;
+int acer_tm360_irqrouting;
 
 static struct irq_routing_table *pirq_table;
 
@@ -894,6 +895,14 @@ static int pcibios_lookup_irq(struct pci
 		r->set(pirq_router_dev, dev, pirq, 11);
 	}
 
+	/* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
+	if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) {
+		pirq = 0x68;
+		mask = 0x400;
+		dev->irq = r->get(pirq_router_dev, dev, pirq);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ 	}
+
 	/*
 	 * Find the best IRQ to assign: use the one
 	 * reported by the device if possible.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/pci-pc.c linux-2.4.28-pre1/arch/i386/kernel/pci-pc.c
--- linux-2.4.27/arch/i386/kernel/pci-pc.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/pci-pc.c	2004-08-15 19:49:35.000000000 +0000
@@ -177,6 +177,7 @@ static struct pci_ops pci_direct_mq_conf
 };
 
 #endif /* !CONFIG_MULTIQUAD */
+#undef PCI_CONF1_ADDRESS
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
@@ -1017,11 +1018,13 @@ struct irq_routing_table * __devinit pci
 		"1:"
 		: "=a" (ret),
 		  "=b" (map),
-		  "+m" (opt)
+		  "=m" (opt)
 		: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
 		  "1" (0),
 		  "D" ((long) &opt),
-		  "S" (&pci_indirect));
+		  "S" (&pci_indirect),
+		  "m" (opt)
+		: "memory");
 	DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
 	if (ret & 0xff00)
 		printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/process.c linux-2.4.28-pre1/arch/i386/kernel/process.c
--- linux-2.4.27/arch/i386/kernel/process.c	2004-02-18 13:36:30.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/process.c	2004-08-15 19:47:11.000000000 +0000
@@ -644,7 +644,7 @@ void dump_thread(struct pt_regs * regs, 
  * More important, however, is the fact that this allows us much
  * more flexibility.
  */
-void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+void fastcall __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread,
 				 *next = &next_p->thread;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/signal.c linux-2.4.28-pre1/arch/i386/kernel/signal.c
--- linux-2.4.27/arch/i386/kernel/signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/signal.c	2004-08-15 19:49:49.000000000 +0000
@@ -581,7 +581,7 @@ handle_signal(unsigned long sig, struct 
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/smp.c linux-2.4.28-pre1/arch/i386/kernel/smp.c
--- linux-2.4.27/arch/i386/kernel/smp.c	2003-06-13 14:51:29.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/smp.c	2004-08-15 19:47:54.000000000 +0000
@@ -150,7 +150,7 @@ static inline void __send_IPI_shortcut(u
 	apic_write_around(APIC_ICR, cfg);
 }
 
-void send_IPI_self(int vector)
+void fastcall send_IPI_self(int vector)
 {
 	__send_IPI_shortcut(APIC_DEST_SELF, vector);
 }
@@ -497,7 +497,7 @@ void flush_tlb_all(void)
  * anything. Worst case is that we lose a reschedule ...
  */
 
-void smp_send_reschedule(int cpu)
+void fastcall smp_send_reschedule(int cpu)
 {
 	send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR);
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/i386/kernel/vm86.c linux-2.4.28-pre1/arch/i386/kernel/vm86.c
--- linux-2.4.27/arch/i386/kernel/vm86.c	2003-08-25 11:44:39.000000000 +0000
+++ linux-2.4.28-pre1/arch/i386/kernel/vm86.c	2004-08-15 19:47:59.000000000 +0000
@@ -91,7 +91,7 @@
 #define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1)
 
 struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
-struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
+struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs)
 {
 	struct tss_struct *tss;
 	struct pt_regs *ret;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/ppc/kernel/ppc_htab.c linux-2.4.28-pre1/arch/ppc/kernel/ppc_htab.c
--- linux-2.4.27/arch/ppc/kernel/ppc_htab.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/ppc/kernel/ppc_htab.c	2004-08-15 19:47:47.000000000 +0000
@@ -489,7 +489,7 @@ int proc_dol2crvec(ctl_table *table, int
 				if (!isspace(c))
 					break;
 				left--;
-				((char *) buffer)++;
+				buffer++;
 			}
 			if (!left)
 				break;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/s390x/kernel/ioctl32.c linux-2.4.28-pre1/arch/s390x/kernel/ioctl32.c
--- linux-2.4.27/arch/s390x/kernel/ioctl32.c	2003-08-25 11:44:40.000000000 +0000
+++ linux-2.4.28-pre1/arch/s390x/kernel/ioctl32.c	2004-08-15 19:51:42.000000000 +0000
@@ -34,6 +34,7 @@
 #include <asm/uaccess.h>
 #include <asm/dasd.h>
 #include <asm/sockios.h>
+#include "../../../drivers/s390/char/tubio.h"
 
 #include "linux32.h"
 
@@ -535,6 +536,12 @@ static struct ioctl32_list ioctl32_handl
 
 	IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl),
 
+	IOCTL32_DEFAULT(TUBICMD),
+	IOCTL32_DEFAULT(TUBOCMD),
+	IOCTL32_DEFAULT(TUBGETI),
+	IOCTL32_DEFAULT(TUBGETO),
+	IOCTL32_DEFAULT(TUBSETMOD),
+	IOCTL32_DEFAULT(TUBGETMOD),
 	IOCTL32_DEFAULT(TCGETA),
 	IOCTL32_DEFAULT(TCSETA),
 	IOCTL32_DEFAULT(TCSETAW),
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc/lib/copy_user.S linux-2.4.28-pre1/arch/sparc/lib/copy_user.S
--- linux-2.4.27/arch/sparc/lib/copy_user.S	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc/lib/copy_user.S	2004-08-15 19:50:15.000000000 +0000
@@ -65,52 +65,52 @@
 
 /* Both these macros have to start with exactly the same insn */
 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-	ldd	[%src + offset + 0x00], %t0; \
-	ldd	[%src + offset + 0x08], %t2; \
-	ldd	[%src + offset + 0x10], %t4; \
-	ldd	[%src + offset + 0x18], %t6; \
-	st	%t0, [%dst + offset + 0x00]; \
-	st	%t1, [%dst + offset + 0x04]; \
-	st	%t2, [%dst + offset + 0x08]; \
-	st	%t3, [%dst + offset + 0x0c]; \
-	st	%t4, [%dst + offset + 0x10]; \
-	st	%t5, [%dst + offset + 0x14]; \
-	st	%t6, [%dst + offset + 0x18]; \
-	st	%t7, [%dst + offset + 0x1c];
+	ldd	[%src + (offset) + 0x00], %t0; \
+	ldd	[%src + (offset) + 0x08], %t2; \
+	ldd	[%src + (offset) + 0x10], %t4; \
+	ldd	[%src + (offset) + 0x18], %t6; \
+	st	%t0, [%dst + (offset) + 0x00]; \
+	st	%t1, [%dst + (offset) + 0x04]; \
+	st	%t2, [%dst + (offset) + 0x08]; \
+	st	%t3, [%dst + (offset) + 0x0c]; \
+	st	%t4, [%dst + (offset) + 0x10]; \
+	st	%t5, [%dst + (offset) + 0x14]; \
+	st	%t6, [%dst + (offset) + 0x18]; \
+	st	%t7, [%dst + (offset) + 0x1c];
 
 #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-	ldd	[%src + offset + 0x00], %t0; \
-	ldd	[%src + offset + 0x08], %t2; \
-	ldd	[%src + offset + 0x10], %t4; \
-	ldd	[%src + offset + 0x18], %t6; \
-	std	%t0, [%dst + offset + 0x00]; \
-	std	%t2, [%dst + offset + 0x08]; \
-	std	%t4, [%dst + offset + 0x10]; \
-	std	%t6, [%dst + offset + 0x18];
+	ldd	[%src + (offset) + 0x00], %t0; \
+	ldd	[%src + (offset) + 0x08], %t2; \
+	ldd	[%src + (offset) + 0x10], %t4; \
+	ldd	[%src + (offset) + 0x18], %t6; \
+	std	%t0, [%dst + (offset) + 0x00]; \
+	std	%t2, [%dst + (offset) + 0x08]; \
+	std	%t4, [%dst + (offset) + 0x10]; \
+	std	%t6, [%dst + (offset) + 0x18];
 
 #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
-	ldd	[%src - offset - 0x10], %t0; \
-	ldd	[%src - offset - 0x08], %t2; \
-	st	%t0, [%dst - offset - 0x10]; \
-	st	%t1, [%dst - offset - 0x0c]; \
-	st	%t2, [%dst - offset - 0x08]; \
-	st	%t3, [%dst - offset - 0x04];
+	ldd	[%src - (offset) - 0x10], %t0; \
+	ldd	[%src - (offset) - 0x08], %t2; \
+	st	%t0, [%dst - (offset) - 0x10]; \
+	st	%t1, [%dst - (offset) - 0x0c]; \
+	st	%t2, [%dst - (offset) - 0x08]; \
+	st	%t3, [%dst - (offset) - 0x04];
 
 #define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
-	lduh	[%src + offset + 0x00], %t0; \
-	lduh	[%src + offset + 0x02], %t1; \
-	lduh	[%src + offset + 0x04], %t2; \
-	lduh	[%src + offset + 0x06], %t3; \
-	sth	%t0, [%dst + offset + 0x00]; \
-	sth	%t1, [%dst + offset + 0x02]; \
-	sth	%t2, [%dst + offset + 0x04]; \
-	sth	%t3, [%dst + offset + 0x06];
+	lduh	[%src + (offset) + 0x00], %t0; \
+	lduh	[%src + (offset) + 0x02], %t1; \
+	lduh	[%src + (offset) + 0x04], %t2; \
+	lduh	[%src + (offset) + 0x06], %t3; \
+	sth	%t0, [%dst + (offset) + 0x00]; \
+	sth	%t1, [%dst + (offset) + 0x02]; \
+	sth	%t2, [%dst + (offset) + 0x04]; \
+	sth	%t3, [%dst + (offset) + 0x06];
 
 #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
-	ldub	[%src - offset - 0x02], %t0; \
-	ldub	[%src - offset - 0x01], %t1; \
-	stb	%t0, [%dst - offset - 0x02]; \
-	stb	%t1, [%dst - offset - 0x01];
+	ldub	[%src - (offset) - 0x02], %t0; \
+	ldub	[%src - (offset) - 0x01], %t1; \
+	stb	%t0, [%dst - (offset) - 0x02]; \
+	stb	%t1, [%dst - (offset) - 0x01];
 
 	.text
 	.align	4
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/kernel/itlb_base.S linux-2.4.28-pre1/arch/sparc64/kernel/itlb_base.S
--- linux-2.4.27/arch/sparc64/kernel/itlb_base.S	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/kernel/itlb_base.S	2004-08-15 19:48:01.000000000 +0000
@@ -41,7 +41,9 @@
 	CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
 	ldxa		[%g3 + %g6] ASI_P, %g5		! Load VPTE
 1:	brgez,pn	%g5, 3f				! Not valid, branch out
-	 nop						! Delay-slot
+	 sethi		%hi(_PAGE_EXEC), %g4		! Delay-slot
+	andcc		%g5, %g4, %g0			! Executable?
+	be,pn		%xcc, 3f			! Nope, branch.
 2:	stxa		%g5, [%g0] ASI_ITLB_DATA_IN	! Load PTE into TLB
 	retry						! Trap return
 3:	rdpr		%pstate, %g4			! Move into alternate globals
@@ -73,9 +75,6 @@ winfix_trampoline:
 	nop
 	nop
 	nop
-	nop
-	nop
-	nop
 	CREATE_VPTE_NOP
 
 #undef CREATE_VPTE_OFFSET1
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/kernel/sbus.c linux-2.4.28-pre1/arch/sparc64/kernel/sbus.c
--- linux-2.4.27/arch/sparc64/kernel/sbus.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/kernel/sbus.c	2004-08-15 19:52:04.564595528 +0000
@@ -27,10 +27,10 @@
  *
  * On SYSIO, using an 8K page size we have 1GB of SBUS
  * DMA space mapped.  We divide this space into equally
- * sized clusters.  Currently we allow clusters up to a
- * size of 1MB.  If anything begins to generate DMA
- * mapping requests larger than this we will need to
- * increase things a bit.
+ * sized clusters. We allocate a DMA mapping from the
+ * cluster that matches the order of the allocation, or
+ * if the order is greater than the number of clusters,
+ * we try to allocate from the last cluster.
  */
 
 #define NCLUSTERS	8UL
@@ -133,12 +133,17 @@ static void strbuf_flush(struct sbus_iom
 
 static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
 {
-	iopte_t *iopte, *limit, *first;
-	unsigned long cnum, ent, flush_point;
+	iopte_t *iopte, *limit, *first, *cluster;
+	unsigned long cnum, ent, nent, flush_point, found;
 
 	cnum = 0;
+	nent = 1;
 	while ((1UL << cnum) < npages)
 		cnum++;
+	if(cnum >= NCLUSTERS) {
+		nent = 1UL << (cnum - NCLUSTERS);
+		cnum = NCLUSTERS - 1;
+	}
 	iopte  = iommu->page_table + (cnum * CLUSTER_NPAGES);
 
 	if (cnum == 0)
@@ -151,22 +156,31 @@ static iopte_t *alloc_streaming_cluster(
 	flush_point = iommu->alloc_info[cnum].flush;
 
 	first = iopte;
+	cluster = NULL;
+	found = 0;
 	for (;;) {
 		if (iopte_val(*iopte) == 0UL) {
-			if ((iopte + (1 << cnum)) >= limit)
-				ent = 0;
-			else
-				ent = ent + 1;
-			iommu->alloc_info[cnum].next = ent;
-			if (ent == flush_point)
-				__iommu_flushall(iommu);
-			break;
+			found++;
+			if (!cluster)
+				cluster = iopte;
+		} else {
+			/* Used cluster in the way */
+			cluster = NULL;
+			found = 0;
 		}
+
+		if (found == nent)
+			break;
+
 		iopte += (1 << cnum);
 		ent++;
 		if (iopte >= limit) {
 			iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES));
 			ent = 0;
+
+			/* Multiple cluster allocations must not wrap */
+			cluster = NULL;
+			found = 0;
 		}
 		if (ent == flush_point)
 			__iommu_flushall(iommu);
@@ -174,8 +188,19 @@ static iopte_t *alloc_streaming_cluster(
 			goto bad;
 	}
 
+	/* ent/iopte points to the last cluster entry we're going to use,
+	 * so save our place for the next allocation.
+	 */
+	if ((iopte + (1 << cnum)) >= limit)
+		ent = 0;
+	else
+		ent = ent + 1;
+	iommu->alloc_info[cnum].next = ent;
+	if (ent == flush_point)
+		__iommu_flushall(iommu);
+
 	/* I've got your streaming cluster right here buddy boy... */
-	return iopte;
+	return cluster;
 
 bad:
 	printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n",
@@ -185,15 +210,23 @@ bad:
 
 static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
 {
-	unsigned long cnum, ent;
+	unsigned long cnum, ent, nent;
 	iopte_t *iopte;
 
 	cnum = 0;
+	nent = 1;
 	while ((1UL << cnum) < npages)
 		cnum++;
+	if(cnum >= NCLUSTERS) {
+		nent = 1UL << (cnum - NCLUSTERS);
+		cnum = NCLUSTERS - 1;
+	}
 	ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum);
 	iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);
-	iopte_val(*iopte) = 0UL;
+	do {
+		iopte_val(*iopte) = 0UL;
+		iopte += 1 << cnum;
+	} while(--nent);
 
 	/* If the global flush might not have caught this entry,
 	 * adjust the flush point such that we will flush before
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.28-pre1/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/kernel/sparc64_ksyms.c	2004-08-15 19:51:20.000000000 +0000
@@ -324,7 +324,6 @@ EXPORT_SYMBOL(sparc32_open);
 #endif
 
 /* Special internal versions of library functions. */
-EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(__memset);
 EXPORT_SYMBOL(_clear_page);
 EXPORT_SYMBOL(clear_user_page);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/lib/U3copy_from_user.S linux-2.4.28-pre1/arch/sparc64/lib/U3copy_from_user.S
--- linux-2.4.27/arch/sparc64/lib/U3copy_from_user.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/lib/U3copy_from_user.S	2004-08-15 19:48:28.000000000 +0000
@@ -1,20 +1,31 @@
-/* $Id: U3copy_from_user.S,v 1.3.2.1 2002/01/15 07:17:47 davem Exp $
- * U3memcpy.S: UltraSparc-III optimized copy from userspace.
+/* U3copy_from_user.S: UltraSparc-III optimized copy from userspace.
  *
- * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #include <asm/dcu.h>
 #include <asm/spitfire.h>
-#undef SMALL_COPY_USES_FPU
+
+#define XCC xcc
+
+#define EXNV_RAW(x,y,a,b)		\
+98:	x,y;				\
+	.section .fixup;		\
+	.align 4;			\
+99:	ba U3cfu_fixup;			\
+	 a, b, %o1;			\
+	.section __ex_table;		\
+	.align 4;			\
+	.word 98b, 99b;			\
+	.text;				\
+	.align 4;
 #define EXNV(x,y,a,b)			\
 98:	x,y;				\
 	.section .fixup;		\
 	.align 4;			\
-99:	VISExitHalf;			\
+99:	add %o1, %o3, %o0;		\
 	ba U3cfu_fixup;			\
 	 a, b, %o1;			\
 	.section __ex_table;		\
@@ -22,6 +33,32 @@
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
+#define EXNV4(x,y,a,b)			\
+98:	x,y;				\
+	.section .fixup;		\
+	.align 4;			\
+99:	add %o1, %o3, %o0;		\
+	a, b, %o1;			\
+	ba U3cfu_fixup;			\
+	 add %o1, 4, %o1;		\
+	.section __ex_table;		\
+	.align 4;			\
+	.word 98b, 99b;			\
+	.text;				\
+	.align 4;
+#define EXNV8(x,y,a,b)			\
+98:	x,y;				\
+	.section .fixup;		\
+	.align 4;			\
+99:	add %o1, %o3, %o0;		\
+	a, b, %o1;			\
+	ba U3cfu_fixup;			\
+	 add %o1, 8, %o1;		\
+	.section __ex_table;		\
+	.align 4;			\
+	.word 98b, 99b;			\
+	.text;				\
+	.align 4;
 #define EX(x,y,a,b)			\
 98:	x,y;				\
 	.section .fixup;		\
@@ -77,18 +114,9 @@
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#else
-#define ASI_BLK_P 0xf0
-#define FPRS_FEF  0x04
-#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
-#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
-#define SMALL_COPY_USES_FPU
-#define EXNV(x,y,a,b)	x,y;
-#define EX(x,y,a,b)	x,y;
-#define EX2(x,y)	x,y;
-#define EX3(x,y)	x,y;
-#define EX4(x,y)	x,y;
-#endif
+
+	.register	%g2,#scratch
+	.register	%g3,#scratch
 
 	/* Special/non-trivial issues of this code:
 	 *
@@ -109,81 +137,55 @@
 	 * of up to 2.4GB per second.
 	 */
 
-	.globl		U3copy_from_user
-U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */
-#ifndef __KERNEL__
-	/* Save away original 'dst' for memcpy return value. */
-	mov		%o0, %g3			! A0	Group
-#endif
-	/* Anything to copy at all? */
-	cmp		%o2, 0				! A1
-	ble,pn		%icc, U3copy_from_user_short_ret! BR
-
-	/* Extremely small copy? */
-	 cmp		%o2, 31				! A0	Group
-	ble,pn		%icc, U3copy_from_user_short	! BR
-
-	/* Large enough to use unrolled prefetch loops? */
-	 cmp		%o2, 0x100			! A1
-	bge,a,pt	%icc, U3copy_from_user_enter	! BR	Group
-	 andcc		%o0, 0x3f, %g2			! A0
-
-	ba,pt		%xcc, U3copy_from_user_toosmall	! BR	Group
-	 andcc		%o0, 0x7, %g2			! A0
-
-	.align		32
-U3copy_from_user_short:
-	/* Copy %o2 bytes from src to dst, one byte at a time. */
-	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS	Group
-	add		%o1, 0x1, %o1			! A0
-	add		%o0, 0x1, %o0			! A1
-	subcc		%o2, 1, %o2			! A0	Group
-
-	bg,pt		%icc, U3copy_from_user_short	! BR
-	 stb		%o3, [%o0 + -1]			! MS	Group (1-cycle stall)
-
-U3copy_from_user_short_ret:
-#ifdef __KERNEL__
-	retl						! BR	Group (0-4 cycle stall)
-	 clr		%o0				! A0
-#else
-	retl						! BR	Group (0-4 cycle stall)
-	 mov		%g3, %o0			! A0
-#endif
+	.globl	U3copy_from_user
+U3copy_from_user:	/* %o0=dst, %o1=src, %o2=len */
+	cmp		%o2, 0
+	be,pn		%XCC, out
+	 or		%o0, %o1, %o3
+	cmp		%o2, 16
+	bleu,a,pn	%XCC, small_copy
+	 or		%o3, %o2, %o3
+
+	cmp		%o2, 256
+	blu,pt		%XCC, medium_copy
+	 andcc		%o3, 0x7, %g0
 
-	/* Here len >= (6 * 64) and condition codes reflect execution
+	ba,pt		%xcc, enter
+	 andcc		%o0, 0x3f, %g2
+
+	/* Here len >= 256 and condition codes reflect execution
 	 * of "andcc %o0, 0x7, %g2", done by caller.
 	 */
 	.align		64
-U3copy_from_user_enter:
+enter:
 	/* Is 'dst' already aligned on an 64-byte boundary? */
-	be,pt		%xcc, 2f			! BR
+	be,pt		%XCC, 2f
 
 	/* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
 	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
 	 * subtract this from 'len'.
 	 */
-	 sub		%g2, 0x40, %g2			! A0	Group
-	sub		%g0, %g2, %g2			! A0	Group
-	sub		%o2, %g2, %o2			! A0	Group
+	 sub		%g2, 0x40, %g2
+	sub		%g0, %g2, %g2
+	sub		%o2, %g2, %o2
 
 	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS	(Group)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 stb		%o3, [%o0 + -1]			! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-	and		%o1, 0x7, %g1			! A1
-	ba,pt		%xcc, U3copy_from_user_begin		! BR
-	 alignaddr	%o1, %g0, %o1			! MS	      (Break-after)
+1:	EXNV_RAW(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+	add		%o1, 0x1, %o1
+	add		%o0, 0x1, %o0
+	subcc		%g2, 0x1, %g2
+
+	bg,pt		%XCC, 1b
+	 stb		%o3, [%o0 + -1]
+
+2:	VISEntryHalf
+	and		%o1, 0x7, %g1
+	ba,pt		%xcc, begin
+	 alignaddr	%o1, %g0, %o1
 
 	.align		64
-U3copy_from_user_begin:
-#ifdef __KERNEL__
+begin:
+
 	.globl		U3copy_from_user_nop_1_6
 U3copy_from_user_nop_1_6:
 	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
@@ -192,315 +194,225 @@ U3copy_from_user_nop_1_6:
 	or		%g3, %o3, %o3
 	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
 	membar		#Sync
-#endif
-	prefetcha	[%o1 + 0x000] %asi, #one_read	! MS	Group1
-	prefetcha	[%o1 + 0x040] %asi, #one_read	! MS	Group2
-	andn		%o2, (0x40 - 1), %o4		! A0
-	prefetcha	[%o1 + 0x080] %asi, #one_read	! MS	Group3
-	cmp		%o4, 0x140			! A0
-	prefetcha	[%o1 + 0x0c0] %asi, #one_read	! MS	Group4
-	EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0)	! MS	Group5 (%f0 results at G8)
-	bge,a,pt	%icc, 1f			! BR
-
-	prefetcha	[%o1 + 0x100] %asi, #one_read	! MS	Group6
-1:	EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0)	! AX	       (%f2 results at G9)
-	cmp		%o4, 0x180			! A1
-	bge,a,pt	%icc, 1f			! BR
-	 prefetcha	[%o1 + 0x140] %asi, #one_read	! MS	Group7
-1:	EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0)	! AX	       (%f4 results at G10)
-	cmp		%o4, 0x1c0			! A1
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetcha	[%o1 + 0x180] %asi, #one_read	! MS	Group8
-1:	faligndata	%f0, %f2, %f16			! FGA	Group9 (%f16 at G12)
-	EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0)	! AX	       (%f6 results at G12)
-	faligndata	%f2, %f4, %f18			! FGA	Group10 (%f18 results at G13)
-	EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0)	! MS	        (%f8 results at G13)
-	faligndata	%f4, %f6, %f20			! FGA	Group12	(1-cycle stall,%f20 at G15)
-	EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0)	! MS		(%f10 results at G15)
-	faligndata	%f6, %f8, %f22			! FGA	Group13 (%f22 results at G16)
-
-	EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0)	! MS		(%f12 results at G16)
-	faligndata	%f8, %f10, %f24			! FGA	Group15 (1-cycle stall,%f24 at G18)
-	EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0)	! MS		(%f14 results at G18)
-	faligndata	%f10, %f12, %f26		! FGA	Group16 (%f26 results at G19)
-	EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0)	! MS		(%f0 results at G19)
-
-	/* We only use the first loop if len > (7 * 64). */
-	subcc		%o4, 0x1c0, %o4			! A0	Group17
-	bg,pt		%icc, U3copy_from_user_loop1	! BR
-	 add		%o1, 0x40, %o1			! A1
-
-	add		%o4, 0x140, %o4			! A0	Group18
-	ba,pt		%xcc, U3copy_from_user_loop2	! BR
-	 srl		%o4, 6, %o3			! A0	Group19
-	nop
-	nop
-	nop
-	nop
-	nop
-
-	nop
-	nop
-
-	/* This loop performs the copy and queues new prefetches.
-	 * We drop into the second loop when len <= (5 * 64).  Note
-	 * that this (5 * 64) factor has been subtracted from len
-	 * already.
-	 */
-U3copy_from_user_loop1:
-	EX2(ldda [%o1 + 0x008] %asi, %f2)		! MS	Group2	(%f2 results at G5)
-	faligndata	%f12, %f14, %f28		! FGA		(%f28 results at G5)
-	EX2(ldda [%o1 + 0x010] %asi, %f4)		! MS	Group3	(%f4 results at G6)
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall, %f30 at G7)
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	EX2(ldda [%o1 + 0x018] %asi, %f6)		! AX		(%f6 results at G7)
-
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-	EX2(ldda [%o1 + 0x020] %asi, %f8)		! MS	        (%f8 results at G15)
-	faligndata	%f2, %f4, %f18			! FGA	Group13	(%f18 results at G16)
-	EX2(ldda [%o1 + 0x028] %asi, %f10)		! MS		(%f10 results at G16)
-	faligndata	%f4, %f6, %f20			! FGA	Group14	(%f20 results at G17)
-	EX2(ldda [%o1 + 0x030] %asi, %f12)		! MS		(%f12 results at G17)
-	faligndata	%f6, %f8, %f22			! FGA	Group15	(%f22 results at G18)
-	EX2(ldda [%o1 + 0x038] %asi, %f14)		! MS		(%f14 results at G18)
-
-	faligndata	%f8, %f10, %f24			! FGA	Group16	(%f24 results at G19)
-	EX2(ldda [%o1 + 0x040] %asi, %f0)		! AX		(%f0 results at G19)
-	prefetcha	[%o1 + 0x180] %asi, #one_read	! MS
-	faligndata	%f10, %f12, %f26		! FGA	Group17	(%f26 results at G20)
-	subcc		%o4, 0x40, %o4			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_from_user_loop1	! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
-
-U3copy_from_user_loop2_enter:
-	mov		5, %o3				! A1
-
-	/* This loop performs on the copy, no new prefetches are
-	 * queued.  We do things this way so that we do not perform
-	 * any spurious prefetches past the end of the src buffer.
-	 */
-U3copy_from_user_loop2:
-	EX3(ldda [%o1 + 0x008] %asi, %f2)		! MS
-	faligndata	%f12, %f14, %f28		! FGA	Group2
-	EX3(ldda [%o1 + 0x010] %asi, %f4)		! MS
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall)
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	EX3(ldda [%o1 + 0x018] %asi, %f6)		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-
-	EX3(ldda [%o1 + 0x020] %asi, %f8)		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group13
-	EX3(ldda [%o1 + 0x028] %asi, %f10)		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group14
-	EX3(ldda [%o1 + 0x030] %asi, %f12)		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group15
-	EX3(ldda [%o1 + 0x038] %asi, %f14)		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group16
-
-	EX3(ldda [%o1 + 0x040] %asi, %f0)		! AX
-	faligndata	%f10, %f12, %f26		! FGA	Group17
-	subcc		%o3, 0x01, %o3			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_from_user_loop2	! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
+
+	prefetcha	[%o1 + 0x000] %asi, #one_read
+	prefetcha	[%o1 + 0x040] %asi, #one_read
+	andn		%o2, (0x40 - 1), %o4
+	prefetcha	[%o1 + 0x080] %asi, #one_read
+	prefetcha	[%o1 + 0x0c0] %asi, #one_read
+	EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0)
+	prefetcha	[%o1 + 0x100] %asi, #one_read
+	EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0)
+	prefetcha	[%o1 + 0x140] %asi, #one_read
+	EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0)
+	prefetcha	[%o1 + 0x180] %asi, #one_read
+	faligndata	%f0, %f2, %f16
+	EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0)
+	faligndata	%f2, %f4, %f18
+	EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0)
+	faligndata	%f4, %f6, %f20
+	EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0)
+	faligndata	%f6, %f8, %f22
+
+	EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0)
+	faligndata	%f8, %f10, %f24
+	EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0)
+	faligndata	%f10, %f12, %f26
+	EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0)
+
+	sub		%o4, 0x80, %o4
+	add		%o1, 0x40, %o1
+	ba,pt		%xcc, loop
+	 srl		%o4, 6, %o3
+
+	.align		64
+loop:
+	EX3(ldda [%o1 + 0x008] %asi, %f2)
+	faligndata	%f12, %f14, %f28
+	EX3(ldda [%o1 + 0x010] %asi, %f4)
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	EX3(ldda [%o1 + 0x018] %asi, %f6)
+	faligndata	%f0, %f2, %f16
+
+	EX3(ldda [%o1 + 0x020] %asi, %f8)
+	faligndata	%f2, %f4, %f18
+	EX3(ldda [%o1 + 0x028] %asi, %f10)
+	faligndata	%f4, %f6, %f20
+	EX3(ldda [%o1 + 0x030] %asi, %f12)
+	faligndata	%f6, %f8, %f22
+	EX3(ldda [%o1 + 0x038] %asi, %f14)
+	faligndata	%f8, %f10, %f24
+
+	EX3(ldda [%o1 + 0x040] %asi, %f0)
+	prefetcha	[%o1 + 0x180] %asi, #one_read
+	faligndata	%f10, %f12, %f26
+	subcc		%o3, 0x01, %o3
+	add		%o1, 0x40, %o1
+	bg,pt		%XCC, loop
+	 add		%o0, 0x40, %o0
 
 	/* Finally we copy the last full 64-byte block. */
-U3copy_from_user_loopfini:
-	EX3(ldda [%o1 + 0x008] %asi, %f2)		! MS
-	faligndata	%f12, %f14, %f28		! FGA
-	EX3(ldda [%o1 + 0x010] %asi, %f4)		! MS	Group19
-	faligndata	%f14, %f0, %f30			! FGA
-	stda		%f16, [%o0] ASI_BLK_P		! MS	Group20
-	EX3(ldda [%o1 + 0x018] %asi, %f6)		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group11 (7-cycle stall)
-	EX3(ldda [%o1 + 0x020] %asi, %f8)		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group12
-	EX3(ldda [%o1 + 0x028] %asi, %f10)		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group13
-	EX3(ldda [%o1 + 0x030] %asi, %f12)		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group14
-	EX3(ldda [%o1 + 0x038] %asi, %f14)		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group15
-	cmp		%g1, 0				! A0
-	be,pt		%icc, 1f			! BR
-	 add		%o0, 0x40, %o0			! A1
-	EX4(ldda [%o1 + 0x040] %asi, %f0)		! MS
-1:	faligndata	%f10, %f12, %f26		! FGA	Group16
-	faligndata	%f12, %f14, %f28		! FGA	Group17
-	faligndata	%f14, %f0, %f30			! FGA	Group18
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	add		%o0, 0x40, %o0			! A0
-	add		%o1, 0x40, %o1			! A1
-#ifdef __KERNEL__
+loopfini:
+	EX3(ldda [%o1 + 0x008] %asi, %f2)
+	faligndata	%f12, %f14, %f28
+	EX3(ldda [%o1 + 0x010] %asi, %f4)
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	EX3(ldda [%o1 + 0x018] %asi, %f6)
+	faligndata	%f0, %f2, %f16
+	EX3(ldda [%o1 + 0x020] %asi, %f8)
+	faligndata	%f2, %f4, %f18
+	EX3(ldda [%o1 + 0x028] %asi, %f10)
+	faligndata	%f4, %f6, %f20
+	EX3(ldda [%o1 + 0x030] %asi, %f12)
+	faligndata	%f6, %f8, %f22
+	EX3(ldda [%o1 + 0x038] %asi, %f14)
+	faligndata	%f8, %f10, %f24
+	cmp		%g1, 0
+	be,pt		%XCC, 1f
+	 add		%o0, 0x40, %o0
+	EX4(ldda [%o1 + 0x040] %asi, %f0)
+1:	faligndata	%f10, %f12, %f26
+	faligndata	%f12, %f14, %f28
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	add		%o0, 0x40, %o0
+	add		%o1, 0x40, %o1
+
 	.globl		U3copy_from_user_nop_2_3
 U3copy_from_user_nop_2_3:
 	mov		PRIMARY_CONTEXT, %o3
 	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
 	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
-#endif
-	membar		#Sync				! MS	Group26 (7-cycle stall)
+
+	membar		#Sync
 
 	/* Now we copy the (len modulo 64) bytes at the end.
 	 * Note how we borrow the %f0 loaded above.
 	 *
 	 * Also notice how this code is careful not to perform a
-	 * load past the end of the src buffer just like similar
-	 * code found in U3copy_from_user_toosmall processing.
+	 * load past the end of the src buffer.
 	 */
-U3copy_from_user_loopend:
-	and		%o2, 0x3f, %o2			! A0	Group
-	andcc		%o2, 0x38, %g2			! A0	Group
-	be,pn		%icc, U3copy_from_user_endcruft	! BR
-	 subcc		%g2, 0x8, %g2			! A1
-	be,pn		%icc, U3copy_from_user_endcruft	! BR	Group
-	 cmp		%g1, 0				! A0
-
-	be,a,pt		%icc, 1f			! BR	Group
-	 EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0)	! MS
-
-1:	EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0)	! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f0, %f2, %f8			! FGA	Group
-	std		%f8, [%o0 + 0x00]		! MS	(XXX does it stall here? XXX)
-	be,pn		%icc, U3copy_from_user_endcruft	! BR
-	 add		%o0, 0x8, %o0			! A0
-	EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0)	! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA
-	std		%f8, [%o0 + 0x00]		! MS	(XXX does it stall here? XXX)
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A0	Group
+loopend:
+	and		%o2, 0x3f, %o2
+	andcc		%o2, 0x38, %g2
+	be,pn		%XCC, endcruft
+	 subcc		%g2, 0x8, %g2
+	be,pn		%XCC, endcruft
+	 cmp		%g1, 0
+
+	be,a,pt		%XCC, 1f
+	 EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0)
+
+1:	EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0)
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f0, %f2, %f8
+	std		%f8, [%o0 + 0x00]
+	be,pn		%XCC, endcruft
+	 add		%o0, 0x8, %o0
+	EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0)
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f2, %f0, %f8
+	std		%f8, [%o0 + 0x00]
+	bne,pn		%XCC, 1b
+	 add		%o0, 0x8, %o0
 
 	/* If anything is left, we copy it one byte at a time.
 	 * Note that %g1 is (src & 0x3) saved above before the
 	 * alignaddr was performed.
 	 */
-U3copy_from_user_endcruft:
+endcruft:
 	cmp		%o2, 0
 	add		%o1, %g1, %o1
 	VISExitHalf
-	be,pn		%icc, U3copy_from_user_short_ret
-	 nop
-	ba,a,pt		%xcc, U3copy_from_user_short
+	be,pn		%XCC, out
+	 sub		%o0, %o1, %o3
 
-	/* If we get here, then 32 <= len < (6 * 64) */
-U3copy_from_user_toosmall:
-
-#ifdef SMALL_COPY_USES_FPU
-
-	/* Is 'dst' already aligned on an 8-byte boundary? */
-	be,pt		%xcc, 2f			! BR	Group
-
-	/* Compute abs((dst & 7) - 8) into %g2.  This is the number
-	 * of bytes to copy to make 'dst' 8-byte aligned.  We pre-
-	 * subtract this from 'len'.
-	 */
-	 sub		%g2, 0x8, %g2			! A0
-	sub		%g0, %g2, %g2			! A0	Group (reg-dep)
-	sub		%o2, %g2, %o2			! A0	Group (reg-dep)
-
-	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS	(Group) (%o3 in 3 cycles)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 stb		%o3, [%o0 + -1]			! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-
-	/* Compute (len - (len % 8)) into %g2.  This is guarenteed
-	 * to be nonzero.
-	 */
-	andn		%o2, 0x7, %g2			! A0	Group
-
-	/* You may read this and believe that it allows reading
-	 * one 8-byte longword past the end of src.  It actually
-	 * does not, as %g2 is subtracted as loads are done from
-	 * src, so we always stop before running off the end.
-	 * Also, we are guarenteed to have at least 0x10 bytes
-	 * to move here.
-	 */
-	sub		%g2, 0x8, %g2			! A0	Group (reg-dep)
-	alignaddr	%o1, %g0, %g1			! MS	      (Break-after)
-	EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0)	! MS	Group (1-cycle stall)
-	add		%g1, 0x8, %g1			! A0
-
-1:	EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0)	! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-
-	faligndata	%f0, %f2, %f8			! FGA	Group (1-cycle stall)
-	std		%f8, [%o0 + 0x00]		! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-	be,pn		%icc, 2f			! BR
-
-	 add		%o0, 0x8, %o0			! A1
-	EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0)	! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA	Group (1-cycle stall)
-	std		%f8, [%o0 + 0x00]		! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A1
-
-	/* Nothing left to copy? */
-2:	cmp		%o2, 0				! A0	Group
-	VISExitHalf					! A0+MS
-	be,pn		%icc, U3copy_from_user_short_ret! BR	Group
-	 nop						! A0
-	ba,a,pt		%xcc, U3copy_from_user_short	! BR	Group
-
-#else /* !(SMALL_COPY_USES_FPU) */
-
-	xor		%o1, %o0, %g2
-	andcc		%g2, 0x7, %g0
-	bne,pn		%icc, U3copy_from_user_short
-	 andcc		%o1, 0x7, %g2
+	andcc		%g1, 0x7, %g0
+	bne,pn		%icc, small_copy_unaligned
+	 andcc		%o2, 0x8, %g0
+	be,pt		%icc, 1f
+	 nop
+	EXNV(ldxa [%o1] %asi, %o5, add %o2, %g0)
+	stx		%o5, [%o1 + %o3]
+	add		%o1, 0x8, %o1
 
-	be,pt		%xcc, 2f
-	 sub		%g2, 0x8, %g2
-	sub		%g0, %g2, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x4, %g0
+	be,pt		%icc, 1f
+	 nop
+	EXNV(lduwa [%o1] %asi, %o5, and %o2, 0x7)
+	stw		%o5, [%o1 + %o3]
+	add		%o1, 0x4, %o1
 
-1:	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
-	add		%o1, 0x1, %o1
-	add		%o0, 0x1, %o0
-	subcc		%g2, 0x1, %g2
-	bg,pt		%icc, 1b
-	 stb		%o3, [%o0 + -1]
+1:	andcc		%o2, 0x2, %g0
+	be,pt		%icc, 1f
+	 nop
+	EXNV(lduha [%o1] %asi, %o5, and %o2, 0x3)
+	sth		%o5, [%o1 + %o3]
+	add		%o1, 0x2, %o1
 
-2:	andn		%o2, 0x7, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x1, %g0
+	be,pt		%icc, out
+	 nop
+	EXNV(lduba [%o1] %asi, %o5, and %o2, 0x1)
+	ba,pt		%xcc, out
+	 stb		%o5, [%o1 + %o3]
+
+medium_copy: /* 16 < len <= 64 */
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+medium_copy_aligned:
+	andn		%o2, 0x7, %o4
+	and		%o2, 0x7, %o2
+1:	subcc		%o4, 0x8, %o4
+	EXNV8(ldxa [%o1] %asi, %o5, add %o2, %o4)
+	stx		%o5, [%o1 + %o3]
+	bgu,pt		%XCC, 1b
+	 add		%o1, 0x8, %o1
+	andcc		%o2, 0x4, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x4, %o2
+	EXNV4(lduwa [%o1] %asi, %o5, add %o2, %g0)
+	stw		%o5, [%o1 + %o3]
+	add		%o1, 0x4, %o1
+1:	cmp		%o2, 0
+	be,pt		%XCC, out
+	 nop
+	ba,pt		%xcc, small_copy_unaligned
+	 nop
 
-3:	EXNV(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
-	add		%o1, 0x8, %o1
-	add		%o0, 0x8, %o0
-	subcc		%g2, 0x8, %g2
-	bg,pt		%icc, 3b
-	 stx		%o3, [%o0 + -8]
+small_copy: /* 0 < len <= 16 */
+	andcc		%o3, 0x3, %g0
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+small_copy_aligned:
+	subcc		%o2, 4, %o2
+	EXNV(lduwa [%o1] %asi, %g1, add %o2, %g0)
+	stw		%g1, [%o1 + %o3]
+	bgu,pt		%XCC, small_copy_aligned
+	 add		%o1, 4, %o1
 
-	cmp		%o2, 0
-	bne,pn		%icc, U3copy_from_user_short
-	 nop
-	ba,a,pt		%xcc, U3copy_from_user_short_ret
+out:	retl
+	 clr		%o0
 
-#endif /* !(SMALL_COPY_USES_FPU) */
+	.align	32
+small_copy_unaligned:
+	subcc		%o2, 1, %o2
+	EXNV(lduba [%o1] %asi, %g1, add %o2, %g0)
+	stb		%g1, [%o1 + %o3]
+	bgu,pt		%XCC, small_copy_unaligned
+	 add		%o1, 1, %o1
+	retl
+	 clr		%o0
 
-#ifdef __KERNEL__
-	.globl		U3cfu_fixup
 U3cfu_fixup:
 	/* Since this is copy_from_user(), zero out the rest of the
 	 * kernel buffer.
@@ -516,4 +428,3 @@ U3cfu_fixup:
 
 2:	retl
 	 mov		%o1, %o0
-#endif
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/lib/U3copy_in_user.S linux-2.4.28-pre1/arch/sparc64/lib/U3copy_in_user.S
--- linux-2.4.27/arch/sparc64/lib/U3copy_in_user.S	2001-03-26 02:14:21.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/lib/U3copy_in_user.S	2004-08-15 19:49:28.000000000 +0000
@@ -1,13 +1,15 @@
-/* $Id: U3copy_in_user.S,v 1.4 2001/03/21 05:58:47 davem Exp $
- * U3memcpy.S: UltraSparc-III optimized copy within userspace.
+/* U3copy_in_user.S: UltraSparc-III optimized memcpy.
  *
- * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
-#undef SMALL_COPY_USES_FPU
+#include <asm/dcu.h>
+#include <asm/spitfire.h>
+
+#define XCC xcc
+
 #define EXNV(x,y,a,b)	\
 98:	x,y;				\
 	.section .fixup;		\
@@ -19,7 +21,7 @@
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#define EXNV2(x,y,a,b)	\
+#define EXNV1(x,y,a,b)			\
 98:	x,y;				\
 	.section .fixup;		\
 	.align 4;			\
@@ -31,501 +33,108 @@
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#define EXNV3(x,y,a,b)	\
+#define EXNV4(x,y,a,b)			\
 98:	x,y;				\
 	.section .fixup;		\
 	.align 4;			\
 99:	a, b, %o0;			\
 	retl;				\
-	 add %o0, 8, %o0;		\
-	.section __ex_table;		\
-	.align 4;			\
-	.word 98b, 99b;			\
-	.text;				\
-	.align 4;
-#define EX(x,y,a,b)			\
-98:	x,y;				\
-	.section .fixup;		\
-	.align 4;			\
-99:	VISExitHalf;			\
-	retl;				\
-	 a, b, %o0;			\
-	.section __ex_table;		\
-	.align 4;			\
-	.word 98b, 99b;			\
-	.text;				\
-	.align 4;
-#define EXBLK1(x,y)			\
-98:	x,y;				\
-	.section .fixup;		\
-	.align 4;			\
-99:	VISExitHalf;			\
-	add %o4, 0x1c0, %o1;		\
-	and %o2, (0x40 - 1), %o2;	\
-	retl;				\
-	 add %o1, %o2, %o0;		\
-	.section __ex_table;		\
-	.align 4;			\
-	.word 98b, 99b;			\
-	.text;				\
-	.align 4;
-#define EXBLK2(x,y)			\
-98:	x,y;				\
-	.section .fixup;		\
-	.align 4;			\
-99:	VISExitHalf;			\
-	sll %o3, 6, %o3;		\
-	and %o2, (0x40 - 1), %o2;	\
-	add %o3, 0x80, %o1;		\
-	retl;				\
-	 add %o1, %o2, %o0;		\
-	.section __ex_table;		\
-	.align 4;			\
-	.word 98b, 99b;			\
-	.text;				\
-	.align 4;
-#define EXBLK3(x,y)			\
-98:	x,y;				\
-	.section .fixup;		\
-	.align 4;			\
-99:	VISExitHalf;			\
-	and %o2, (0x40 - 1), %o2;	\
-	retl;				\
-	 add %o2, 0x80, %o0;		\
+	 add %o0, 4, %o0;		\
 	.section __ex_table;		\
 	.align 4;			\
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#define EXBLK4(x,y)			\
+#define EXNV8(x,y,a,b)			\
 98:	x,y;				\
 	.section .fixup;		\
 	.align 4;			\
-99:	VISExitHalf;			\
-	and %o2, (0x40 - 1), %o2;	\
+99:	a, b, %o0;			\
 	retl;				\
-	 add %o2, 0x40, %o0;		\
+	 add %o0, 8, %o0;		\
 	.section __ex_table;		\
 	.align 4;			\
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#else
-#define ASI_AIUS 0x80
-#define ASI_BLK_AIUS 0xf0
-#define FPRS_FEF  0x04
-#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
-#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
-#define SMALL_COPY_USES_FPU
-#define EXNV(x,y,a,b)	x,y;
-#define EXNV2(x,y,a,b)	x,y;
-#define EXNV3(x,y,a,b)	x,y;
-#define EX(x,y,a,b)	x,y;
-#define EXBLK1(x,y)	x,y;
-#define EXBLK2(x,y)	x,y;
-#define EXBLK3(x,y)	x,y;
-#define EXBLK4(x,y)	x,y;
-#endif
-
-	/* Special/non-trivial issues of this code:
-	 *
-	 * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
-	 * 2) Only low 32 FPU registers are used so that only the
-	 *    lower half of the FPU register set is dirtied by this
-	 *    code.  This is especially important in the kernel.
-	 * 3) This code never prefetches cachelines past the end
-	 *    of the source buffer.
-	 *
-	 *    XXX Actually, Cheetah can buffer up to 8 concurrent
-	 *    XXX prefetches, revisit this...
-	 */
+
+	.register	%g2,#scratch
+	.register	%g3,#scratch
 
 	.text
 	.align	32
 
-	/* The cheetah's flexible spine, oversized liver, enlarged heart,
-	 * slender muscular body, and claws make it the swiftest hunter
-	 * in Africa and the fastest animal on land.  Can reach speeds
-	 * of up to 2.4GB per second.
+	/* Don't try to get too fancy here, just nice and
+	 * simple.  This is predominantly used for well aligned
+	 * small copies in the compat layer.  It is also used
+	 * to copy register windows around during thread cloning.
 	 */
 
-	.globl		U3copy_in_user
-U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */
+	.globl	U3copy_in_user
+U3copy_in_user:	/* %o0=dst, %o1=src, %o2=len */
 	/* Writing to %asi is _expensive_ so we hardcode it.
 	 * Reading %asi to check for KERNEL_DS is comparatively
 	 * cheap.
 	 */
-	rd		%asi, %g1			! MS	Group	(4 cycles)
-	cmp		%g1, ASI_AIUS			! A0	Group
-	bne		U3memcpy			! BR
-	 nop						! A1
-#ifndef __KERNEL__
-	/* Save away original 'dst' for memcpy return value. */
-	mov		%o0, %g3			! A0	Group
-#endif
-	/* Anything to copy at all? */
-	cmp		%o2, 0				! A1
-	ble,pn		%icc, U3copy_in_user_short_ret	! BR
-
-	/* Extremely small copy? */
-	 cmp		%o2, 31				! A0	Group
-	ble,pn		%icc, U3copy_in_user_short	! BR
-
-	/* Large enough to use unrolled prefetch loops? */
-	 cmp		%o2, 0x100			! A1
-	bge,a,pt	%icc, U3copy_in_user_enter	! BR	Group
-	 andcc		%o0, 0x3f, %g2			! A0
-
-	ba,pt		%xcc, U3copy_in_user_toosmall	! BR	Group
-	 andcc		%o0, 0x7, %g2			! A0
-
-	.align		32
-U3copy_in_user_short:
-	/* Copy %o2 bytes from src to dst, one byte at a time. */
-	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS	Group
-	add		%o1, 0x1, %o1			! A0
-	add		%o0, 0x1, %o0			! A1
-	subcc		%o2, 1, %o2			! A0	Group
-
-	bg,pt		%icc, U3copy_in_user_short	! BR
-	 EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1)	! MS	Group (1-cycle stall)
-
-U3copy_in_user_short_ret:
-#ifdef __KERNEL__
-	retl						! BR	Group (0-4 cycle stall)
-	 clr		%o0				! A0
-#else
-	retl						! BR	Group (0-4 cycle stall)
-	 mov		%g3, %o0			! A0
-#endif
+	rd		%asi, %g1
+	cmp		%g1, ASI_AIUS
+	bne,pn		%icc, U3memcpy_user_stub
+	 nop
 
-	/* Here len >= (6 * 64) and condition codes reflect execution
-	 * of "andcc %o0, 0x7, %g2", done by caller.
-	 */
-	.align		64
-U3copy_in_user_enter:
-	/* Is 'dst' already aligned on an 64-byte boundary? */
-	be,pt		%xcc, 2f			! BR
-
-	/* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
-	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
-	 * subtract this from 'len'.
-	 */
-	 sub		%g2, 0x40, %g2			! A0	Group
-	sub		%g0, %g2, %g2			! A0	Group
-	sub		%o2, %g2, %o2			! A0	Group
-
-	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS	(Group)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)	! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-	and		%o1, 0x7, %g1			! A1
-	ba,pt		%xcc, U3copy_in_user_begin	! BR
-	 alignaddr	%o1, %g0, %o1			! MS	      (Break-after)
-
-	.align		64
-U3copy_in_user_begin:
-	prefetcha	[%o1 + 0x000] %asi, #one_read	! MS	Group1
-	prefetcha	[%o1 + 0x040] %asi, #one_read	! MS	Group2
-	andn		%o2, (0x40 - 1), %o4		! A0
-	prefetcha	[%o1 + 0x080] %asi, #one_read	! MS	Group3
-	cmp		%o4, 0x140			! A0
-	prefetcha	[%o1 + 0x0c0] %asi, #one_read	! MS	Group4
-	EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0)	! MS	Group5 (%f0 results at G8)
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetcha	[%o1 + 0x100] %asi, #one_read	! MS	Group6
-1:	EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0)	! AX	       (%f2 results at G9)
-	cmp		%o4, 0x180			! A1
-	bge,a,pt	%icc, 1f			! BR
-	 prefetcha	[%o1 + 0x140] %asi, #one_read	! MS	Group7
-1:	EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0)	! AX	       (%f4 results at G10)
-	cmp		%o4, 0x1c0			! A1
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetcha	[%o1 + 0x180] %asi, #one_read	! MS	Group8
-1:	faligndata	%f0, %f2, %f16			! FGA	Group9 (%f16 at G12)
-	EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0)	! AX	       (%f6 results at G12)
-	faligndata	%f2, %f4, %f18			! FGA	Group10 (%f18 results at G13)
-	EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0)	! MS	        (%f8 results at G13)
-	faligndata	%f4, %f6, %f20			! FGA	Group12	(1-cycle stall,%f20 at G15)
-	EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0)	! MS		(%f10 results at G15)
-	faligndata	%f6, %f8, %f22			! FGA	Group13 (%f22 results at G16)
-	
-	EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0)	! MS		(%f12 results at G16)
-	faligndata	%f8, %f10, %f24			! FGA	Group15 (1-cycle stall,%f24 at G18)
-	EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0)	! MS		(%f14 results at G18)
-	faligndata	%f10, %f12, %f26		! FGA	Group16 (%f26 results at G19)
-	EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0)	! MS		(%f0 results at G19)
-
-	/* We only use the first loop if len > (7 * 64). */
-	subcc		%o4, 0x1c0, %o4			! A0	Group17
-	bg,pt		%icc, U3copy_in_user_loop1	! BR
-	 add		%o1, 0x40, %o1			! A1
-
-	add		%o4, 0x140, %o4			! A0	Group18
-	ba,pt		%xcc, U3copy_in_user_loop2	! BR
-	 srl		%o4, 6, %o3			! A0	Group19
-	nop
-	nop
-	nop
-	nop
-	nop
-
-	nop
-	nop
-
-	/* This loop performs the copy and queues new prefetches.
-	 * We drop into the second loop when len <= (5 * 64).  Note
-	 * that this (5 * 64) factor has been subtracted from len
-	 * already.
-	 */
-U3copy_in_user_loop1:
-	EXBLK1(ldda [%o1 + 0x008] %asi, %f2)		! MS	Group2	(%f2 results at G5)
-	faligndata	%f12, %f14, %f28		! FGA		(%f28 results at G5)
-	EXBLK1(ldda [%o1 + 0x010] %asi, %f4)		! MS	Group3	(%f4 results at G6)
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall, %f30 at G7)
-	EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	EXBLK1(ldda [%o1 + 0x018] %asi, %f6)		! AX		(%f6 results at G7)
-
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-	EXBLK1(ldda [%o1 + 0x020] %asi, %f8)		! MS	        (%f8 results at G15)
-	faligndata	%f2, %f4, %f18			! FGA	Group13	(%f18 results at G16)
-	EXBLK1(ldda [%o1 + 0x028] %asi, %f10)		! MS		(%f10 results at G16)
-	faligndata	%f4, %f6, %f20			! FGA	Group14	(%f20 results at G17)
-	EXBLK1(ldda [%o1 + 0x030] %asi, %f12)		! MS		(%f12 results at G17)
-	faligndata	%f6, %f8, %f22			! FGA	Group15	(%f22 results at G18)
-	EXBLK1(ldda [%o1 + 0x038] %asi, %f14)		! MS		(%f14 results at G18)
-
-	faligndata	%f8, %f10, %f24			! FGA	Group16	(%f24 results at G19)
-	EXBLK1(ldda [%o1 + 0x040] %asi, %f0)		! AX		(%f0 results at G19)
-	prefetcha	[%o1 + 0x180] %asi, #one_read	! MS
-	faligndata	%f10, %f12, %f26		! FGA	Group17	(%f26 results at G20)
-	subcc		%o4, 0x40, %o4			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_in_user_loop1		! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
-
-U3copy_in_user_loop2_enter:
-	mov		5, %o3				! A1
-
-	/* This loop performs on the copy, no new prefetches are
-	 * queued.  We do things this way so that we do not perform
-	 * any spurious prefetches past the end of the src buffer.
-	 */
-U3copy_in_user_loop2:
-	EXBLK2(ldda [%o1 + 0x008] %asi, %f2)		! MS
-	faligndata	%f12, %f14, %f28		! FGA	Group2
-	EXBLK2(ldda [%o1 + 0x010] %asi, %f4)		! MS
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall)
-	EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	EXBLK2(ldda [%o1 + 0x018] %asi, %f6)		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-
-	EXBLK2(ldda [%o1 + 0x020] %asi, %f8)		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group13
-	EXBLK2(ldda [%o1 + 0x028] %asi, %f10)		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group14
-	EXBLK2(ldda [%o1 + 0x030] %asi, %f12)		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group15
-	EXBLK2(ldda [%o1 + 0x038] %asi, %f14)		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group16
-
-	EXBLK2(ldda [%o1 + 0x040] %asi, %f0)		! AX
-	faligndata	%f10, %f12, %f26		! FGA	Group17
-	subcc		%o3, 0x01, %o3			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_in_user_loop2	! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
-
-	/* Finally we copy the last full 64-byte block. */
-U3copy_in_user_loopfini:
-	EXBLK3(ldda [%o1 + 0x008] %asi, %f2)		! MS
-	faligndata	%f12, %f14, %f28		! FGA
-	EXBLK3(ldda [%o1 + 0x010] %asi, %f4)		! MS	Group19
-	faligndata	%f14, %f0, %f30			! FGA
-	EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS)		! MS	Group20
-	EXBLK4(ldda [%o1 + 0x018] %asi, %f6)		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group11 (7-cycle stall)
-	EXBLK4(ldda [%o1 + 0x020] %asi, %f8)		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group12
-	EXBLK4(ldda [%o1 + 0x028] %asi, %f10)		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group13
-	EXBLK4(ldda [%o1 + 0x030] %asi, %f12)		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group14
-	EXBLK4(ldda [%o1 + 0x038] %asi, %f14)		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group15
-	cmp		%g1, 0				! A0
-	be,pt		%icc, 1f			! BR
-	 add		%o0, 0x40, %o0			! A1
-	EXBLK4(ldda [%o1 + 0x040] %asi, %f0)		! MS
-1:	faligndata	%f10, %f12, %f26		! FGA	Group16
-	faligndata	%f12, %f14, %f28		! FGA	Group17
-	faligndata	%f14, %f0, %f30			! FGA	Group18
-	EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	add		%o0, 0x40, %o0			! A0
-	add		%o1, 0x40, %o1			! A1
-	membar		#Sync				! MS	Group26 (7-cycle stall)
-
-	/* Now we copy the (len modulo 64) bytes at the end.
-	 * Note how we borrow the %f0 loaded above.
-	 *
-	 * Also notice how this code is careful not to perform a
-	 * load past the end of the src buffer just like similar
-	 * code found in U3copy_in_user_toosmall processing.
-	 */
-U3copy_in_user_loopend:
-	and		%o2, 0x3f, %o2			! A0	Group
-	andcc		%o2, 0x38, %g2			! A0	Group
-	be,pn		%icc, U3copy_in_user_endcruft	! BR
-	 subcc		%g2, 0x8, %g2			! A1
-	be,pn		%icc, U3copy_in_user_endcruft	! BR	Group
-	 cmp		%g1, 0				! A0
-
-	be,a,pt		%icc, 1f			! BR	Group
-	 EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0)	! MS
-
-1:	EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0)	! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f0, %f2, %f8			! FGA	Group
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	(XXX does it stall here? XXX)
-	be,pn		%icc, U3copy_in_user_endcruft	! BR
-	 add		%o0, 0x8, %o0			! A0
-	EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0)	! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	(XXX does it stall here? XXX)
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A0	Group
-
-	/* If anything is left, we copy it one byte at a time.
-	 * Note that %g1 is (src & 0x3) saved above before the
-	 * alignaddr was performed.
-	 */
-U3copy_in_user_endcruft:
 	cmp		%o2, 0
-	add		%o1, %g1, %o1
-	VISExitHalf
-	be,pn		%icc, U3copy_in_user_short_ret
+	be,pn		%XCC, out
+	 or		%o0, %o1, %o3
+	cmp		%o2, 16
+	bleu,a,pn	%XCC, small_copy
+	 or		%o3, %o2, %o3
+
+medium_copy: /* 16 < len <= 64 */
+	andcc		%o3, 0x7, %g0
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+medium_copy_aligned:
+	andn		%o2, 0x7, %o4
+	and		%o2, 0x7, %o2
+1:	subcc		%o4, 0x8, %o4
+	EXNV8(ldxa [%o1] %asi, %o5, add %o4, %o2)
+	EXNV8(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2)
+	bgu,pt		%XCC, 1b
+	 add		%o1, 0x8, %o1
+	andcc		%o2, 0x4, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x4, %o2
+	EXNV4(lduwa [%o1] %asi, %o5, add %o4, %o2)
+	EXNV4(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2)
+	add		%o1, 0x4, %o1
+1:	cmp		%o2, 0
+	be,pt		%XCC, out
+	 nop
+	ba,pt		%xcc, small_copy_unaligned
 	 nop
-	ba,a,pt		%xcc, U3copy_in_user_short
-
-	/* If we get here, then 32 <= len < (6 * 64) */
-U3copy_in_user_toosmall:
-
-#ifdef SMALL_COPY_USES_FPU
-
-	/* Is 'dst' already aligned on an 8-byte boundary? */
-	be,pt		%xcc, 2f			! BR	Group
-
-	/* Compute abs((dst & 7) - 8) into %g2.  This is the number
-	 * of bytes to copy to make 'dst' 8-byte aligned.  We pre-
-	 * subtract this from 'len'.
-	 */
-	 sub		%g2, 0x8, %g2			! A0
-	sub		%g0, %g2, %g2			! A0	Group (reg-dep)
-	sub		%o2, %g2, %o2			! A0	Group (reg-dep)
-
-	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS	(Group) (%o3 in 3 cycles)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)	! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-
-	/* Compute (len - (len % 8)) into %g2.  This is guarenteed
-	 * to be nonzero.
-	 */
-	andn		%o2, 0x7, %g2			! A0	Group
 
-	/* You may read this and believe that it allows reading
-	 * one 8-byte longword past the end of src.  It actually
-	 * does not, as %g2 is subtracted as loads are done from
-	 * src, so we always stop before running off the end.
-	 * Also, we are guarenteed to have at least 0x10 bytes
-	 * to move here.
-	 */
-	sub		%g2, 0x8, %g2			! A0	Group (reg-dep)
-	alignaddr	%o1, %g0, %g1			! MS	      (Break-after)
-	EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0)	! MS	Group (1-cycle stall)
-	add		%g1, 0x8, %g1			! A0
-
-1:	EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0)	! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-
-	faligndata	%f0, %f2, %f8			! FGA	Group (1-cycle stall)
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-	be,pn		%icc, 2f			! BR
-
-	 add		%o0, 0x8, %o0			! A1
-	EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0)	! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA	Group (1-cycle stall)
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A1
-
-	/* Nothing left to copy? */
-2:	cmp		%o2, 0				! A0	Group
-	VISExitHalf					! A0+MS
-	be,pn		%icc, U3copy_in_user_short_ret	! BR	Group
-	 nop						! A0
-	ba,a,pt		%xcc, U3copy_in_user_short	! BR	Group
-
-#else /* !(SMALL_COPY_USES_FPU) */
-
-	xor		%o1, %o0, %g2
-	andcc		%g2, 0x7, %g0
-	bne,pn		%icc, U3copy_in_user_short
-	 andcc		%o1, 0x7, %g2
-
-	be,pt		%xcc, 2f
-	 sub		%g2, 0x8, %g2
-	sub		%g0, %g2, %g2
-	sub		%o2, %g2, %o2
-
-1:	EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
-	add		%o1, 0x1, %o1
-	add		%o0, 0x1, %o0
-	subcc		%g2, 0x1, %g2
-	bg,pt		%icc, 1b
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
-
-2:	andn		%o2, 0x7, %g2
-	sub		%o2, %g2, %o2
-
-3:	EXNV3(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
-	add		%o1, 0x8, %o1
-	add		%o0, 0x8, %o0
-	subcc		%g2, 0x8, %g2
-	bg,pt		%icc, 3b
-	 EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+small_copy: /* 0 < len <= 16 */
+	andcc		%o3, 0x3, %g0
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+small_copy_aligned:
+	subcc		%o2, 4, %o2
+	EXNV4(lduwa [%o1] %asi, %g1, add %o2, %g0)
+	EXNV4(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	bgu,pt		%XCC, small_copy_aligned
+	 add		%o1, 4, %o1
 
-	cmp		%o2, 0
-	bne,pn		%icc, U3copy_in_user_short
-	 nop
-	ba,a,pt		%xcc, U3copy_in_user_short_ret
+out:	retl
+	 clr		%o0
 
-#endif /* !(SMALL_COPY_USES_FPU) */
+	.align	32
+small_copy_unaligned:
+	subcc		%o2, 1, %o2
+	EXNV1(lduba [%o1] %asi, %g1, add %o2, %g0)
+	EXNV1(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	bgu,pt		%XCC, small_copy_unaligned
+	 add		%o1, 1, %o1
+	retl
+	 clr		%o0
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/lib/U3copy_to_user.S linux-2.4.28-pre1/arch/sparc64/lib/U3copy_to_user.S
--- linux-2.4.27/arch/sparc64/lib/U3copy_to_user.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/lib/U3copy_to_user.S	2004-08-15 19:47:14.000000000 +0000
@@ -1,15 +1,15 @@
-/* $Id: U3copy_to_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
- * U3memcpy.S: UltraSparc-III optimized copy to userspace.
+/* U3copy_to_user.S: UltraSparc-III optimized memcpy.
  *
- * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
-#ifdef __KERNEL__
 #include <asm/visasm.h>
 #include <asm/asi.h>
 #include <asm/dcu.h>
 #include <asm/spitfire.h>
-#undef SMALL_COPY_USES_FPU
+
+#define XCC xcc
+
 #define EXNV(x,y,a,b)	\
 98:	x,y;				\
 	.section .fixup;		\
@@ -39,6 +39,18 @@
 	.align 4;			\
 99:	a, b, %o0;			\
 	retl;				\
+	 add %o0, 4, %o0;		\
+	.section __ex_table;		\
+	.align 4;			\
+	.word 98b, 99b;			\
+	.text;				\
+	.align 4;
+#define EXNV4(x,y,a,b)	\
+98:	x,y;				\
+	.section .fixup;		\
+	.align 4;			\
+99:	a, b, %o0;			\
+	retl;				\
 	 add %o0, 8, %o0;		\
 	.section __ex_table;		\
 	.align 4;			\
@@ -112,22 +124,9 @@
 	.word 98b, 99b;			\
 	.text;				\
 	.align 4;
-#else
-#define ASI_AIUS 0x80
-#define ASI_BLK_AIUS 0xf0
-#define FPRS_FEF  0x04
-#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
-#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
-#define SMALL_COPY_USES_FPU
-#define EXNV(x,y,a,b)	x,y;
-#define EXNV2(x,y,a,b)	x,y;
-#define EXNV3(x,y,a,b)	x,y;
-#define EX(x,y,a,b)	x,y;
-#define EXBLK1(x,y)	x,y;
-#define EXBLK2(x,y)	x,y;
-#define EXBLK3(x,y)	x,y;
-#define EXBLK4(x,y)	x,y;
-#endif
+
+	.register	%g2,#scratch
+	.register	%g3,#scratch
 
 	/* Special/non-trivial issues of this code:
 	 *
@@ -148,89 +147,64 @@
 	 * of up to 2.4GB per second.
 	 */
 
-	.globl		U3copy_to_user
-U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */
+	.globl	U3copy_to_user
+U3copy_to_user:	/* %o0=dst, %o1=src, %o2=len */
 	/* Writing to %asi is _expensive_ so we hardcode it.
 	 * Reading %asi to check for KERNEL_DS is comparatively
 	 * cheap.
 	 */
-	rd		%asi, %g1			! MS	Group	(4 cycles)
-	cmp		%g1, ASI_AIUS			! A0	Group
-	bne		U3memcpy			! BR
-	 nop						! A1
-#ifndef __KERNEL__
-	/* Save away original 'dst' for memcpy return value. */
-	mov		%o0, %g3			! A0	Group
-#endif
-	/* Anything to copy at all? */
-	cmp		%o2, 0				! A1
-	ble,pn		%icc, U3copy_to_user_short_ret	! BR
-
-	/* Extremely small copy? */
-	 cmp		%o2, 31				! A0	Group
-	ble,pn		%icc, U3copy_to_user_short	! BR
-
-	/* Large enough to use unrolled prefetch loops? */
-	 cmp		%o2, 0x100			! A1
-	bge,a,pt	%icc, U3copy_to_user_enter	! BR	Group
-	 andcc		%o0, 0x3f, %g2			! A0
-
-	ba,pt		%xcc, U3copy_to_user_toosmall	! BR	Group
-	 andcc		%o0, 0x7, %g2			! A0
-
-	.align		32
-U3copy_to_user_short:
-	/* Copy %o2 bytes from src to dst, one byte at a time. */
-	ldub		[%o1 + 0x00], %o3		! MS	Group
-	add		%o1, 0x1, %o1			! A0
-	add		%o0, 0x1, %o0			! A1
-	subcc		%o2, 1, %o2			! A0	Group
-
-	bg,pt		%icc, U3copy_to_user_short	! BR
-	 EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1)	! MS	Group (1-cycle stall)
-
-U3copy_to_user_short_ret:
-#ifdef __KERNEL__
-	retl						! BR	Group (0-4 cycle stall)
-	 clr		%o0				! A0
-#else
-	retl						! BR	Group (0-4 cycle stall)
-	 mov		%g3, %o0			! A0
-#endif
+	rd		%asi, %g1
+	cmp		%g1, ASI_AIUS
+	bne,pn		%icc, U3memcpy_user_stub
+	 nop
 
-	/* Here len >= (6 * 64) and condition codes reflect execution
+	cmp		%o2, 0
+	be,pn		%XCC, out
+	 or		%o0, %o1, %o3
+	cmp		%o2, 16
+	bleu,a,pn	%XCC, small_copy
+	 or		%o3, %o2, %o3
+
+	cmp		%o2, 256
+	blu,pt		%XCC, medium_copy
+	 andcc		%o3, 0x7, %g0
+
+	ba,pt		%xcc, enter
+	 andcc		%o0, 0x3f, %g2
+
+	/* Here len >= 256 and condition codes reflect execution
 	 * of "andcc %o0, 0x7, %g2", done by caller.
 	 */
 	.align		64
-U3copy_to_user_enter:
+enter:
 	/* Is 'dst' already aligned on an 64-byte boundary? */
-	be,pt		%xcc, 2f			! BR
+	be,pt		%XCC, 2f
 
 	/* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
 	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
 	 * subtract this from 'len'.
 	 */
-	 sub		%g2, 0x40, %g2			! A0	Group
-	sub		%g0, %g2, %g2			! A0	Group
-	sub		%o2, %g2, %o2			! A0	Group
+	 sub		%g2, 0x40, %g2
+	sub		%g0, %g2, %g2
+	sub		%o2, %g2, %o2
 
 	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	ldub		[%o1 + 0x00], %o3		! MS	(Group)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)	! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-	and		%o1, 0x7, %g1			! A1
-	ba,pt		%xcc, U3copy_to_user_begin	! BR
-	 alignaddr	%o1, %g0, %o1			! MS	      (Break-after)
+1:	ldub		[%o1 + 0x00], %o3
+	add		%o1, 0x1, %o1
+	add		%o0, 0x1, %o0
+	subcc		%g2, 0x1, %g2
+
+	bg,pt		%XCC, 1b
+	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+
+2:	VISEntryHalf
+	and		%o1, 0x7, %g1
+	ba,pt		%xcc, begin
+	 alignaddr	%o1, %g0, %o1
 
 	.align		64
-U3copy_to_user_begin:
-#ifdef __KERNEL__
+begin:
+
 	.globl		U3copy_to_user_nop_1_6
 U3copy_to_user_nop_1_6:
 	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g3
@@ -239,309 +213,221 @@ U3copy_to_user_nop_1_6:
 	or		%g3, %o3, %o3
 	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
 	membar		#Sync
-#endif
-	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
-	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
-	andn		%o2, (0x40 - 1), %o4		! A0
-	prefetch	[%o1 + 0x080], #one_read	! MS	Group3
-	cmp		%o4, 0x140			! A0
-	prefetch	[%o1 + 0x0c0], #one_read	! MS	Group4
-	ldd		[%o1 + 0x000], %f0		! MS	Group5 (%f0 results at G8)
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetch	[%o1 + 0x100], #one_read	! MS	Group6
-1:	ldd		[%o1 + 0x008], %f2		! AX	       (%f2 results at G9)
-	cmp		%o4, 0x180			! A1
-	bge,a,pt	%icc, 1f			! BR
-	 prefetch	[%o1 + 0x140], #one_read	! MS	Group7
-1:	ldd		[%o1 + 0x010], %f4		! AX	       (%f4 results at G10)
-	cmp		%o4, 0x1c0			! A1
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetch	[%o1 + 0x180], #one_read	! MS	Group8
-1:	faligndata	%f0, %f2, %f16			! FGA	Group9 (%f16 at G12)
-	ldd		[%o1 + 0x018], %f6		! AX	       (%f6 results at G12)
-	faligndata	%f2, %f4, %f18			! FGA	Group10 (%f18 results at G13)
-	ldd		[%o1 + 0x020], %f8		! MS	        (%f8 results at G13)
-	faligndata	%f4, %f6, %f20			! FGA	Group12	(1-cycle stall,%f20 at G15)
-	ldd		[%o1 + 0x028], %f10		! MS		(%f10 results at G15)
-	faligndata	%f6, %f8, %f22			! FGA	Group13 (%f22 results at G16)
-	
-	ldd		[%o1 + 0x030], %f12		! MS		(%f12 results at G16)
-	faligndata	%f8, %f10, %f24			! FGA	Group15 (1-cycle stall,%f24 at G18)
-	ldd		[%o1 + 0x038], %f14		! MS		(%f14 results at G18)
-	faligndata	%f10, %f12, %f26		! FGA	Group16 (%f26 results at G19)
-	ldd		[%o1 + 0x040], %f0		! MS		(%f0 results at G19)
-
-	/* We only use the first loop if len > (7 * 64). */
-	subcc		%o4, 0x1c0, %o4			! A0	Group17
-	bg,pt		%icc, U3copy_to_user_loop1	! BR
-	 add		%o1, 0x40, %o1			! A1
-
-	add		%o4, 0x140, %o4			! A0	Group18
-	ba,pt		%xcc, U3copy_to_user_loop2	! BR
-	 srl		%o4, 6, %o3			! A0	Group19
-	nop
-	nop
-	nop
-	nop
-	nop
-
-	nop
-	nop
-
-	/* This loop performs the copy and queues new prefetches.
-	 * We drop into the second loop when len <= (5 * 64).  Note
-	 * that this (5 * 64) factor has been subtracted from len
-	 * already.
-	 */
-U3copy_to_user_loop1:
-	ldd		[%o1 + 0x008], %f2		! MS	Group2	(%f2 results at G5)
-	faligndata	%f12, %f14, %f28		! FGA		(%f28 results at G5)
-	ldd		[%o1 + 0x010], %f4		! MS	Group3	(%f4 results at G6)
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall, %f30 at G7)
-	EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	ldd		[%o1 + 0x018], %f6		! AX		(%f6 results at G7)
-
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-	ldd		[%o1 + 0x020], %f8		! MS	        (%f8 results at G15)
-	faligndata	%f2, %f4, %f18			! FGA	Group13	(%f18 results at G16)
-	ldd		[%o1 + 0x028], %f10		! MS		(%f10 results at G16)
-	faligndata	%f4, %f6, %f20			! FGA	Group14	(%f20 results at G17)
-	ldd		[%o1 + 0x030], %f12		! MS		(%f12 results at G17)
-	faligndata	%f6, %f8, %f22			! FGA	Group15	(%f22 results at G18)
-	ldd		[%o1 + 0x038], %f14		! MS		(%f14 results at G18)
-
-	faligndata	%f8, %f10, %f24			! FGA	Group16	(%f24 results at G19)
-	ldd		[%o1 + 0x040], %f0		! AX		(%f0 results at G19)
-	prefetch	[%o1 + 0x180], #one_read	! MS
-	faligndata	%f10, %f12, %f26		! FGA	Group17	(%f26 results at G20)
-	subcc		%o4, 0x40, %o4			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_to_user_loop1		! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
-
-U3copy_to_user_loop2_enter:
-	mov		5, %o3				! A1
-
-	/* This loop performs on the copy, no new prefetches are
-	 * queued.  We do things this way so that we do not perform
-	 * any spurious prefetches past the end of the src buffer.
-	 */
-U3copy_to_user_loop2:
-	ldd		[%o1 + 0x008], %f2		! MS
-	faligndata	%f12, %f14, %f28		! FGA	Group2
-	ldd		[%o1 + 0x010], %f4		! MS
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall)
-	EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	ldd		[%o1 + 0x018], %f6		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-
-	ldd		[%o1 + 0x020], %f8		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group13
-	ldd		[%o1 + 0x028], %f10		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group14
-	ldd		[%o1 + 0x030], %f12		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group15
-	ldd		[%o1 + 0x038], %f14		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group16
-
-	ldd		[%o1 + 0x040], %f0		! AX
-	faligndata	%f10, %f12, %f26		! FGA	Group17
-	subcc		%o3, 0x01, %o3			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3copy_to_user_loop2	! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
+
+	prefetch	[%o1 + 0x000], #one_read
+	prefetch	[%o1 + 0x040], #one_read
+	andn		%o2, (0x40 - 1), %o4
+	prefetch	[%o1 + 0x080], #one_read
+	prefetch	[%o1 + 0x0c0], #one_read
+	ldd		[%o1 + 0x000], %f0
+	prefetch	[%o1 + 0x100], #one_read
+	ldd		[%o1 + 0x008], %f2
+	prefetch	[%o1 + 0x140], #one_read
+	ldd		[%o1 + 0x010], %f4
+	prefetch	[%o1 + 0x180], #one_read
+	faligndata	%f0, %f2, %f16
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f6, %f8, %f22
+
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f8, %f10, %f24
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f10, %f12, %f26
+	ldd		[%o1 + 0x040], %f0
+
+	sub		%o4, 0x80, %o4
+	add		%o1, 0x40, %o1
+	ba,pt		%xcc, loop
+	 srl		%o4, 6, %o3
+
+	.align		64
+loop:
+	ldd		[%o1 + 0x008], %f2
+	faligndata	%f12, %f14, %f28
+	ldd		[%o1 + 0x010], %f4
+	faligndata	%f14, %f0, %f30
+	EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS)
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f0, %f2, %f16
+
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f6, %f8, %f22
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f8, %f10, %f24
+
+	ldd		[%o1 + 0x040], %f0
+	prefetch	[%o1 + 0x180], #one_read
+	faligndata	%f10, %f12, %f26
+	subcc		%o3, 0x01, %o3
+	add		%o1, 0x40, %o1
+	bg,pt		%XCC, loop
+	 add		%o0, 0x40, %o0
 
 	/* Finally we copy the last full 64-byte block. */
-U3copy_to_user_loopfini:
-	ldd		[%o1 + 0x008], %f2		! MS
-	faligndata	%f12, %f14, %f28		! FGA
-	ldd		[%o1 + 0x010], %f4		! MS	Group19
-	faligndata	%f14, %f0, %f30			! FGA
-	EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS)		! MS	Group20
-	ldd		[%o1 + 0x018], %f6		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group11 (7-cycle stall)
-	ldd		[%o1 + 0x020], %f8		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group12
-	ldd		[%o1 + 0x028], %f10		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group13
-	ldd		[%o1 + 0x030], %f12		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group14
-	ldd		[%o1 + 0x038], %f14		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group15
-	cmp		%g1, 0				! A0
-	be,pt		%icc, 1f			! BR
-	 add		%o0, 0x40, %o0			! A1
-	ldd		[%o1 + 0x040], %f0		! MS
-1:	faligndata	%f10, %f12, %f26		! FGA	Group16
-	faligndata	%f12, %f14, %f28		! FGA	Group17
-	faligndata	%f14, %f0, %f30			! FGA	Group18
-	EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS)		! MS
-	add		%o0, 0x40, %o0			! A0
-	add		%o1, 0x40, %o1			! A1
-#ifdef __KERNEL__
+loopfini:
+	ldd		[%o1 + 0x008], %f2
+	faligndata	%f12, %f14, %f28
+	ldd		[%o1 + 0x010], %f4
+	faligndata	%f14, %f0, %f30
+	EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS)
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f0, %f2, %f16
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f6, %f8, %f22
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f8, %f10, %f24
+	cmp		%g1, 0
+	be,pt		%XCC, 1f
+	 add		%o0, 0x40, %o0
+	ldd		[%o1 + 0x040], %f0
+1:	faligndata	%f10, %f12, %f26
+	faligndata	%f12, %f14, %f28
+	faligndata	%f14, %f0, %f30
+	EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS)
+	add		%o0, 0x40, %o0
+	add		%o1, 0x40, %o1
+
 	.globl		U3copy_to_user_nop_2_3
 U3copy_to_user_nop_2_3:
 	mov		PRIMARY_CONTEXT, %o3
 	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
 	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
-#endif
-	membar		#Sync				! MS	Group26 (7-cycle stall)
+
+	membar		#Sync
 
 	/* Now we copy the (len modulo 64) bytes at the end.
 	 * Note how we borrow the %f0 loaded above.
 	 *
 	 * Also notice how this code is careful not to perform a
-	 * load past the end of the src buffer just like similar
-	 * code found in U3copy_to_user_toosmall processing.
+	 * load past the end of the src buffer.
 	 */
-U3copy_to_user_loopend:
-	and		%o2, 0x3f, %o2			! A0	Group
-	andcc		%o2, 0x38, %g2			! A0	Group
-	be,pn		%icc, U3copy_to_user_endcruft	! BR
-	 subcc		%g2, 0x8, %g2			! A1
-	be,pn		%icc, U3copy_to_user_endcruft	! BR	Group
-	 cmp		%g1, 0				! A0
-
-	be,a,pt		%icc, 1f			! BR	Group
-	 ldd		[%o1 + 0x00], %f0		! MS
-
-1:	ldd		[%o1 + 0x08], %f2		! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f0, %f2, %f8			! FGA	Group
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	(XXX does it stall here? XXX)
-	be,pn		%icc, U3copy_to_user_endcruft	! BR
-	 add		%o0, 0x8, %o0			! A0
-	ldd		[%o1 + 0x08], %f0		! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	(XXX does it stall here? XXX)
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A0	Group
+loopend:
+	and		%o2, 0x3f, %o2
+	andcc		%o2, 0x38, %g2
+	be,pn		%XCC, endcruft
+	 subcc		%g2, 0x8, %g2
+	be,pn		%XCC, endcruft
+	 cmp		%g1, 0
+
+	be,a,pt		%XCC, 1f
+	 ldd		[%o1 + 0x00], %f0
+
+1:	ldd		[%o1 + 0x08], %f2
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f0, %f2, %f8
+	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)
+	be,pn		%XCC, endcruft
+	 add		%o0, 0x8, %o0
+	ldd		[%o1 + 0x08], %f0
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f2, %f0, %f8
+	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)
+	bne,pn		%XCC, 1b
+	 add		%o0, 0x8, %o0
 
 	/* If anything is left, we copy it one byte at a time.
 	 * Note that %g1 is (src & 0x3) saved above before the
 	 * alignaddr was performed.
 	 */
-U3copy_to_user_endcruft:
+endcruft:
 	cmp		%o2, 0
 	add		%o1, %g1, %o1
 	VISExitHalf
-	be,pn		%icc, U3copy_to_user_short_ret
-	 nop
-	ba,a,pt		%xcc, U3copy_to_user_short
-
-	/* If we get here, then 32 <= len < (6 * 64) */
-U3copy_to_user_toosmall:
-
-#ifdef SMALL_COPY_USES_FPU
-
-	/* Is 'dst' already aligned on an 8-byte boundary? */
-	be,pt		%xcc, 2f			! BR	Group
-
-	/* Compute abs((dst & 7) - 8) into %g2.  This is the number
-	 * of bytes to copy to make 'dst' 8-byte aligned.  We pre-
-	 * subtract this from 'len'.
-	 */
-	 sub		%g2, 0x8, %g2			! A0
-	sub		%g0, %g2, %g2			! A0	Group (reg-dep)
-	sub		%o2, %g2, %o2			! A0	Group (reg-dep)
+	be,pn		%XCC, out
+	 sub		%o0, %o1, %o3
 
-	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	ldub		[%o1 + 0x00], %o3		! MS	(Group) (%o3 in 3 cycles)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)	! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-
-	/* Compute (len - (len % 8)) into %g2.  This is guarenteed
-	 * to be nonzero.
-	 */
-	andn		%o2, 0x7, %g2			! A0	Group
-
-	/* You may read this and believe that it allows reading
-	 * one 8-byte longword past the end of src.  It actually
-	 * does not, as %g2 is subtracted as loads are done from
-	 * src, so we always stop before running off the end.
-	 * Also, we are guarenteed to have at least 0x10 bytes
-	 * to move here.
-	 */
-	sub		%g2, 0x8, %g2			! A0	Group (reg-dep)
-	alignaddr	%o1, %g0, %g1			! MS	      (Break-after)
-	ldd		[%g1 + 0x00], %f0		! MS	Group (1-cycle stall)
-	add		%g1, 0x8, %g1			! A0
-
-1:	ldd		[%g1 + 0x00], %f2		! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-
-	faligndata	%f0, %f2, %f8			! FGA	Group (1-cycle stall)
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-	be,pn		%icc, 2f			! BR
-
-	 add		%o0, 0x8, %o0			! A1
-	ldd		[%g1 + 0x00], %f0		! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA	Group (1-cycle stall)
-	EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8)	! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A1
-
-	/* Nothing left to copy? */
-2:	cmp		%o2, 0				! A0	Group
-	VISExitHalf					! A0+MS
-	be,pn		%icc, U3copy_to_user_short_ret	! BR	Group
-	 nop						! A0
-	ba,a,pt		%xcc, U3copy_to_user_short	! BR	Group
-
-#else /* !(SMALL_COPY_USES_FPU) */
-
-	xor		%o1, %o0, %g2
-	andcc		%g2, 0x7, %g0
-	bne,pn		%icc, U3copy_to_user_short
-	 andcc		%o1, 0x7, %g2
+	andcc		%g1, 0x7, %g0
+	bne,pn		%icc, small_copy_unaligned
+	 andcc		%o2, 0x8, %g0
+	be,pt		%icc, 1f
+	 nop
+	ldx		[%o1], %o5
+	EXNV(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	add		%o1, 0x8, %o1
 
-	be,pt		%xcc, 2f
-	 sub		%g2, 0x8, %g2
-	sub		%g0, %g2, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x4, %g0
+	be,pt		%icc, 1f
+	 nop
+	lduw		[%o1], %o5
+	EXNV(stwa %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x7)
+	add		%o1, 0x4, %o1
 
-1:	ldub		[%o1 + 0x00], %o3
-	add		%o1, 0x1, %o1
-	add		%o0, 0x1, %o0
-	subcc		%g2, 0x1, %g2
-	bg,pt		%icc, 1b
-	 EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+1:	andcc		%o2, 0x2, %g0
+	be,pt		%icc, 1f
+	 nop
+	lduh		[%o1], %o5
+	EXNV(stha %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x3)
+	add		%o1, 0x2, %o1
 
-2:	andn		%o2, 0x7, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x1, %g0
+	be,pt		%icc, out
+	 nop
+	ldub		[%o1], %o5
+	ba,pt		%xcc, out
+	 EXNV(stba %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x1)
+
+medium_copy: /* 16 < len <= 64 */
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+medium_copy_aligned:
+	andn		%o2, 0x7, %o4
+	and		%o2, 0x7, %o2
+1:	subcc		%o4, 0x8, %o4
+	ldx		[%o1], %o5
+	EXNV4(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %o4)
+	bgu,pt		%XCC, 1b
+	 add		%o1, 0x8, %o1
+	andcc		%o2, 0x4, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x4, %o2
+	lduw		[%o1], %o5
+	EXNV3(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	add		%o1, 0x4, %o1
+1:	cmp		%o2, 0
+	be,pt		%XCC, out
+	 nop
+	ba,pt		%xcc, small_copy_unaligned
+	 nop
 
-3:	ldx		[%o1 + 0x00], %o3
-	add		%o1, 0x8, %o1
-	add		%o0, 0x8, %o0
-	subcc		%g2, 0x8, %g2
-	bg,pt		%icc, 3b
-	 EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+small_copy: /* 0 < len <= 16 */
+	andcc		%o3, 0x3, %g0
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+small_copy_aligned:
+	subcc		%o2, 4, %o2
+	lduw		[%o1], %g1
+	EXNV3(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	bgu,pt		%XCC, small_copy_aligned
+	 add		%o1, 4, %o1
 
-	cmp		%o2, 0
-	bne,pn		%icc, U3copy_to_user_short
-	 nop
-	ba,a,pt		%xcc, U3copy_to_user_short_ret
+out:	retl
+	 clr		%o0
 
-#endif /* !(SMALL_COPY_USES_FPU) */
+	.align	32
+small_copy_unaligned:
+	subcc		%o2, 1, %o2
+	ldub		[%o1], %g1
+	EXNV2(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0)
+	bgu,pt		%XCC, small_copy_unaligned
+	 add		%o1, 1, %o1
+	retl
+	 clr		%o0
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/lib/U3memcpy.S linux-2.4.28-pre1/arch/sparc64/lib/U3memcpy.S
--- linux-2.4.27/arch/sparc64/lib/U3memcpy.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/lib/U3memcpy.S	2004-08-15 19:52:07.710117336 +0000
@@ -1,7 +1,6 @@
-/* $Id: U3memcpy.S,v 1.2 2000/11/01 09:29:19 davem Exp $
- * U3memcpy.S: UltraSparc-III optimized memcpy.
+/* U3memcpy.S: UltraSparc-III optimized memcpy.
  *
- * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
  */
 
 #ifdef __KERNEL__
@@ -9,15 +8,20 @@
 #include <asm/asi.h>
 #include <asm/dcu.h>
 #include <asm/spitfire.h>
-#undef SMALL_COPY_USES_FPU
 #else
 #define ASI_BLK_P 0xf0
 #define FPRS_FEF  0x04
 #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
 #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
-#define SMALL_COPY_USES_FPU
 #endif
 
+#ifndef XCC
+#define XCC xcc
+#endif
+
+	.register	%g2,#scratch
+	.register	%g3,#scratch
+
 	/* Special/non-trivial issues of this code:
 	 *
 	 * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
@@ -37,80 +41,55 @@
 	 * of up to 2.4GB per second.
 	 */
 
-	.globl		U3memcpy
-U3memcpy: /* %o0=dst, %o1=src, %o2=len */
-#ifndef __KERNEL__
-	/* Save away original 'dst' for memcpy return value. */
-	mov		%o0, %g3			! A0	Group
-#endif
-	/* Anything to copy at all? */
-	cmp		%o2, 0				! A1
-	ble,pn		%icc, U3memcpy_short_ret	! BR
-
-	/* Extremely small copy? */
-	 cmp		%o2, 31				! A0	Group
-	ble,pn		%icc, U3memcpy_short		! BR
-
-	/* Large enough to use unrolled prefetch loops? */
-	 cmp		%o2, 0x100			! A1
-	bge,a,pt	%icc, U3memcpy_enter		! BR	Group
-	 andcc		%o0, 0x3f, %g2			! A0
-
-	ba,pt		%xcc, U3memcpy_toosmall		! BR	Group
-	 andcc		%o0, 0x7, %g2			! A0
-
-	.align		32
-U3memcpy_short:
-	/* Copy %o2 bytes from src to dst, one byte at a time. */
-	ldub		[%o1 + 0x00], %o3		! MS	Group
-	add		%o1, 0x1, %o1			! A0
-	add		%o0, 0x1, %o0			! A1
-	subcc		%o2, 1, %o2			! A0	Group
-
-	bg,pt		%icc, U3memcpy_short		! BR
-	 stb		%o3, [%o0 + -1]			! MS	Group (1-cycle stall)
+	.globl	U3memcpy
+U3memcpy:	/* %o0=dst, %o1=src, %o2=len */
+	mov		%o0, %g5
+	cmp		%o2, 0
+	be,pn		%XCC, out
+	 or		%o0, %o1, %o3
+	cmp		%o2, 16
+	bleu,a,pn	%XCC, small_copy
+	 or		%o3, %o2, %o3
+
+	cmp		%o2, 256
+	blu,pt		%XCC, medium_copy
+	 andcc		%o3, 0x7, %g0
 
-U3memcpy_short_ret:
-#ifdef __KERNEL__
-	retl						! BR	Group (0-4 cycle stall)
-	 clr		%o0				! A0
-#else
-	retl						! BR	Group (0-4 cycle stall)
-	 mov		%g3, %o0			! A0
-#endif
+	ba,pt		%xcc, enter
+	 andcc		%o0, 0x3f, %g2
 
-	/* Here len >= (6 * 64) and condition codes reflect execution
+	/* Here len >= 256 and condition codes reflect execution
 	 * of "andcc %o0, 0x7, %g2", done by caller.
 	 */
 	.align		64
-U3memcpy_enter:
+enter:
 	/* Is 'dst' already aligned on an 64-byte boundary? */
-	be,pt		%xcc, 2f			! BR
+	be,pt		%XCC, 2f
 
 	/* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
 	 * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
 	 * subtract this from 'len'.
 	 */
-	 sub		%g2, 0x40, %g2			! A0	Group
-	sub		%g0, %g2, %g2			! A0	Group
-	sub		%o2, %g2, %o2			! A0	Group
+	 sub		%g2, 0x40, %g2
+	sub		%g0, %g2, %g2
+	sub		%o2, %g2, %o2
 
 	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	ldub		[%o1 + 0x00], %o3		! MS	(Group)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 stb		%o3, [%o0 + -1]			! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-	and		%o1, 0x7, %g1			! A1
-	ba,pt		%xcc, U3memcpy_begin		! BR
-	 alignaddr	%o1, %g0, %o1			! MS	      (Break-after)
+1:	ldub		[%o1 + 0x00], %o3
+	add		%o1, 0x1, %o1
+	add		%o0, 0x1, %o0
+	subcc		%g2, 0x1, %g2
+
+	bg,pt		%XCC, 1b
+	 stb		%o3, [%o0 + -1]
+
+2:	VISEntryHalf
+	and		%o1, 0x7, %g1
+	ba,pt		%xcc, begin
+	 alignaddr	%o1, %g0, %o1
 
 	.align		64
-U3memcpy_begin:
+begin:
 #ifdef __KERNEL__
 	.globl		U3memcpy_nop_1_6
 U3memcpy_nop_1_6:
@@ -121,146 +100,90 @@ U3memcpy_nop_1_6:
 	stxa		%o3, [%g0] ASI_DCU_CONTROL_REG	! Enable P-cache
 	membar		#Sync
 #endif
-	prefetch	[%o1 + 0x000], #one_read	! MS	Group1
-	prefetch	[%o1 + 0x040], #one_read	! MS	Group2
-	andn		%o2, (0x40 - 1), %o4		! A0
-	prefetch	[%o1 + 0x080], #one_read	! MS	Group3
-	cmp		%o4, 0x140			! A0
-	prefetch	[%o1 + 0x0c0], #one_read	! MS	Group4
-	ldd		[%o1 + 0x000], %f0		! MS	Group5 (%f0 results at G8)
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetch	[%o1 + 0x100], #one_read	! MS	Group6
-1:	ldd		[%o1 + 0x008], %f2		! AX	       (%f2 results at G9)
-	cmp		%o4, 0x180			! A1
-	bge,a,pt	%icc, 1f			! BR
-	 prefetch	[%o1 + 0x140], #one_read	! MS	Group7
-1:	ldd		[%o1 + 0x010], %f4		! AX	       (%f4 results at G10)
-	cmp		%o4, 0x1c0			! A1
-	bge,a,pt	%icc, 1f			! BR
-
-	 prefetch	[%o1 + 0x180], #one_read	! MS	Group8
-1:	faligndata	%f0, %f2, %f16			! FGA	Group9 (%f16 at G12)
-	ldd		[%o1 + 0x018], %f6		! AX	       (%f6 results at G12)
-	faligndata	%f2, %f4, %f18			! FGA	Group10 (%f18 results at G13)
-	ldd		[%o1 + 0x020], %f8		! MS	        (%f8 results at G13)
-	faligndata	%f4, %f6, %f20			! FGA	Group12	(1-cycle stall,%f20 at G15)
-	ldd		[%o1 + 0x028], %f10		! MS		(%f10 results at G15)
-	faligndata	%f6, %f8, %f22			! FGA	Group13 (%f22 results at G16)
-
-	ldd		[%o1 + 0x030], %f12		! MS		(%f12 results at G16)
-	faligndata	%f8, %f10, %f24			! FGA	Group15 (1-cycle stall,%f24 at G18)
-	ldd		[%o1 + 0x038], %f14		! MS		(%f14 results at G18)
-	faligndata	%f10, %f12, %f26		! FGA	Group16 (%f26 results at G19)
-	ldd		[%o1 + 0x040], %f0		! MS		(%f0 results at G19)
-
-	/* We only use the first loop if len > (7 * 64). */
-	subcc		%o4, 0x1c0, %o4			! A0	Group17
-	bg,pt		%icc, U3memcpy_loop1		! BR
-	 add		%o1, 0x40, %o1			! A1
-
-	add		%o4, 0x140, %o4			! A0	Group18
-	ba,pt		%xcc, U3memcpy_loop2		! BR
-	 srl		%o4, 6, %o3			! A0	Group19
-	nop
-	nop
-	nop
-	nop
-	nop
-
-	nop
-	nop
-
-	/* This loop performs the copy and queues new prefetches.
-	 * We drop into the second loop when len <= (5 * 64).  Note
-	 * that this (5 * 64) factor has been subtracted from len
-	 * already.
-	 */
-U3memcpy_loop1:
-	ldd		[%o1 + 0x008], %f2		! MS	Group2	(%f2 results at G5)
-	faligndata	%f12, %f14, %f28		! FGA		(%f28 results at G5)
-	ldd		[%o1 + 0x010], %f4		! MS	Group3	(%f4 results at G6)
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall, %f30 at G7)
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	ldd		[%o1 + 0x018], %f6		! AX		(%f6 results at G7)
-
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-	ldd		[%o1 + 0x020], %f8		! MS	        (%f8 results at G15)
-	faligndata	%f2, %f4, %f18			! FGA	Group13	(%f18 results at G16)
-	ldd		[%o1 + 0x028], %f10		! MS		(%f10 results at G16)
-	faligndata	%f4, %f6, %f20			! FGA	Group14	(%f20 results at G17)
-	ldd		[%o1 + 0x030], %f12		! MS		(%f12 results at G17)
-	faligndata	%f6, %f8, %f22			! FGA	Group15	(%f22 results at G18)
-	ldd		[%o1 + 0x038], %f14		! MS		(%f14 results at G18)
-
-	faligndata	%f8, %f10, %f24			! FGA	Group16	(%f24 results at G19)
-	ldd		[%o1 + 0x040], %f0		! AX		(%f0 results at G19)
-	prefetch	[%o1 + 0x180], #one_read	! MS
-	faligndata	%f10, %f12, %f26		! FGA	Group17	(%f26 results at G20)
-	subcc		%o4, 0x40, %o4			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3memcpy_loop1		! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
-
-U3memcpy_loop2_enter:
-	mov		5, %o3				! A1
-
-	/* This loop performs on the copy, no new prefetches are
-	 * queued.  We do things this way so that we do not perform
-	 * any spurious prefetches past the end of the src buffer.
-	 */
-U3memcpy_loop2:
-	ldd		[%o1 + 0x008], %f2		! MS
-	faligndata	%f12, %f14, %f28		! FGA	Group2
-	ldd		[%o1 + 0x010], %f4		! MS
-	faligndata	%f14, %f0, %f30			! FGA	Group4	(1-cycle stall)
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	ldd		[%o1 + 0x018], %f6		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group12 (7-cycle stall)
-
-	ldd		[%o1 + 0x020], %f8		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group13
-	ldd		[%o1 + 0x028], %f10		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group14
-	ldd		[%o1 + 0x030], %f12		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group15
-	ldd		[%o1 + 0x038], %f14		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group16
-
-	ldd		[%o1 + 0x040], %f0		! AX
-	faligndata	%f10, %f12, %f26		! FGA	Group17
-	subcc		%o3, 0x01, %o3			! A0
-	add		%o1, 0x40, %o1			! A1
-	bg,pt		%xcc, U3memcpy_loop2		! BR
-	 add		%o0, 0x40, %o0			! A0	Group18
+	prefetch	[%o1 + 0x000], #one_read
+	prefetch	[%o1 + 0x040], #one_read
+	andn		%o2, (0x40 - 1), %o4
+	prefetch	[%o1 + 0x080], #one_read
+	prefetch	[%o1 + 0x0c0], #one_read
+	ldd		[%o1 + 0x000], %f0
+	prefetch	[%o1 + 0x100], #one_read
+	ldd		[%o1 + 0x008], %f2
+	prefetch	[%o1 + 0x140], #one_read
+	ldd		[%o1 + 0x010], %f4
+	prefetch	[%o1 + 0x180], #one_read
+	faligndata	%f0, %f2, %f16
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f6, %f8, %f22
+
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f8, %f10, %f24
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f10, %f12, %f26
+	ldd		[%o1 + 0x040], %f0
+
+	sub		%o4, 0x80, %o4
+	add		%o1, 0x40, %o1
+	ba,pt		%xcc, loop
+	 srl		%o4, 6, %o3
+
+	.align		64
+loop:
+	ldd		[%o1 + 0x008], %f2
+	faligndata	%f12, %f14, %f28
+	ldd		[%o1 + 0x010], %f4
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f0, %f2, %f16
+
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f6, %f8, %f22
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f8, %f10, %f24
+
+	ldd		[%o1 + 0x040], %f0
+	prefetch	[%o1 + 0x180], #one_read
+	faligndata	%f10, %f12, %f26
+	subcc		%o3, 0x01, %o3
+	add		%o1, 0x40, %o1
+	bg,pt		%XCC, loop
+	 add		%o0, 0x40, %o0
 
 	/* Finally we copy the last full 64-byte block. */
-U3memcpy_loopfini:
-	ldd		[%o1 + 0x008], %f2		! MS
-	faligndata	%f12, %f14, %f28		! FGA
-	ldd		[%o1 + 0x010], %f4		! MS	Group19
-	faligndata	%f14, %f0, %f30			! FGA
-	stda		%f16, [%o0] ASI_BLK_P		! MS	Group20
-	ldd		[%o1 + 0x018], %f6		! AX
-	faligndata	%f0, %f2, %f16			! FGA	Group11 (7-cycle stall)
-	ldd		[%o1 + 0x020], %f8		! MS
-	faligndata	%f2, %f4, %f18			! FGA	Group12
-	ldd		[%o1 + 0x028], %f10		! MS
-	faligndata	%f4, %f6, %f20			! FGA	Group13
-	ldd		[%o1 + 0x030], %f12		! MS
-	faligndata	%f6, %f8, %f22			! FGA	Group14
-	ldd		[%o1 + 0x038], %f14		! MS
-	faligndata	%f8, %f10, %f24			! FGA	Group15
-	cmp		%g1, 0				! A0
-	be,pt		%icc, 1f			! BR
-	 add		%o0, 0x40, %o0			! A1
-	ldd		[%o1 + 0x040], %f0		! MS
-1:	faligndata	%f10, %f12, %f26		! FGA	Group16
-	faligndata	%f12, %f14, %f28		! FGA	Group17
-	faligndata	%f14, %f0, %f30			! FGA	Group18
-	stda		%f16, [%o0] ASI_BLK_P		! MS
-	add		%o0, 0x40, %o0			! A0
-	add		%o1, 0x40, %o1			! A1
+loopfini:
+	ldd		[%o1 + 0x008], %f2
+	faligndata	%f12, %f14, %f28
+	ldd		[%o1 + 0x010], %f4
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	ldd		[%o1 + 0x018], %f6
+	faligndata	%f0, %f2, %f16
+	ldd		[%o1 + 0x020], %f8
+	faligndata	%f2, %f4, %f18
+	ldd		[%o1 + 0x028], %f10
+	faligndata	%f4, %f6, %f20
+	ldd		[%o1 + 0x030], %f12
+	faligndata	%f6, %f8, %f22
+	ldd		[%o1 + 0x038], %f14
+	faligndata	%f8, %f10, %f24
+	cmp		%g1, 0
+	be,pt		%XCC, 1f
+	 add		%o0, 0x40, %o0
+	ldd		[%o1 + 0x040], %f0
+1:	faligndata	%f10, %f12, %f26
+	faligndata	%f12, %f14, %f28
+	faligndata	%f14, %f0, %f30
+	stda		%f16, [%o0] ASI_BLK_P
+	add		%o0, 0x40, %o0
+	add		%o1, 0x40, %o1
 #ifdef __KERNEL__
 	.globl		U3memcpy_nop_2_3
 U3memcpy_nop_2_3:
@@ -268,161 +191,143 @@ U3memcpy_nop_2_3:
 	stxa		%g0, [%o3] ASI_DMMU		! Flush P-cache
 	stxa		%g3, [%g0] ASI_DCU_CONTROL_REG	! Disable P-cache
 #endif
-	membar		#Sync				! MS	Group26 (7-cycle stall)
+	membar		#Sync
 
 	/* Now we copy the (len modulo 64) bytes at the end.
 	 * Note how we borrow the %f0 loaded above.
 	 *
 	 * Also notice how this code is careful not to perform a
-	 * load past the end of the src buffer just like similar
-	 * code found in U3memcpy_toosmall processing.
+	 * load past the end of the src buffer.
 	 */
-U3memcpy_loopend:
-	and		%o2, 0x3f, %o2			! A0	Group
-	andcc		%o2, 0x38, %g2			! A0	Group
-	be,pn		%icc, U3memcpy_endcruft		! BR
-	 subcc		%g2, 0x8, %g2			! A1
-	be,pn		%icc, U3memcpy_endcruft		! BR	Group
-	 cmp		%g1, 0				! A0
-
-	be,a,pt		%icc, 1f			! BR	Group
-	 ldd		[%o1 + 0x00], %f0		! MS
-
-1:	ldd		[%o1 + 0x08], %f2		! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f0, %f2, %f8			! FGA	Group
-	std		%f8, [%o0 + 0x00]		! MS	(XXX does it stall here? XXX)
-	be,pn		%icc, U3memcpy_endcruft		! BR
-	 add		%o0, 0x8, %o0			! A0
-	ldd		[%o1 + 0x08], %f0		! MS	Group
-	add		%o1, 0x8, %o1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA
-	std		%f8, [%o0 + 0x00]		! MS	(XXX does it stall here? XXX)
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A0	Group
+loopend:
+	and		%o2, 0x3f, %o2
+	andcc		%o2, 0x38, %g2
+	be,pn		%XCC, endcruft
+	 subcc		%g2, 0x8, %g2
+	be,pn		%XCC, endcruft
+	 cmp		%g1, 0
+
+	be,a,pt		%XCC, 1f
+	 ldd		[%o1 + 0x00], %f0
+
+1:	ldd		[%o1 + 0x08], %f2
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f0, %f2, %f8
+	std		%f8, [%o0 + 0x00]
+	be,pn		%XCC, endcruft
+	 add		%o0, 0x8, %o0
+	ldd		[%o1 + 0x08], %f0
+	add		%o1, 0x8, %o1
+	sub		%o2, 0x8, %o2
+	subcc		%g2, 0x8, %g2
+	faligndata	%f2, %f0, %f8
+	std		%f8, [%o0 + 0x00]
+	bne,pn		%XCC, 1b
+	 add		%o0, 0x8, %o0
 
 	/* If anything is left, we copy it one byte at a time.
 	 * Note that %g1 is (src & 0x3) saved above before the
 	 * alignaddr was performed.
 	 */
-U3memcpy_endcruft:
+endcruft:
 	cmp		%o2, 0
 	add		%o1, %g1, %o1
 	VISExitHalf
-	be,pn		%icc, U3memcpy_short_ret
-	 nop
-	ba,a,pt		%xcc, U3memcpy_short
-
-	/* If we get here, then 32 <= len < (6 * 64) */
-U3memcpy_toosmall:
-
-#ifdef SMALL_COPY_USES_FPU
+	be,pn		%XCC, out
+	 sub		%o0, %o1, %o3
 
-	/* Is 'dst' already aligned on an 8-byte boundary? */
-	be,pt		%xcc, 2f			! BR	Group
-
-	/* Compute abs((dst & 7) - 8) into %g2.  This is the number
-	 * of bytes to copy to make 'dst' 8-byte aligned.  We pre-
-	 * subtract this from 'len'.
-	 */
-	 sub		%g2, 0x8, %g2			! A0
-	sub		%g0, %g2, %g2			! A0	Group (reg-dep)
-	sub		%o2, %g2, %o2			! A0	Group (reg-dep)
-
-	/* Copy %g2 bytes from src to dst, one byte at a time. */
-1:	ldub		[%o1 + 0x00], %o3		! MS	(Group) (%o3 in 3 cycles)
-	add		%o1, 0x1, %o1			! A1
-	add		%o0, 0x1, %o0			! A0	Group
-	subcc		%g2, 0x1, %g2			! A1
-
-	bg,pt		%icc, 1b			! BR	Group
-	 stb		%o3, [%o0 + -1]			! MS	Group
-
-2:	VISEntryHalf					! MS+MS
-
-	/* Compute (len - (len % 8)) into %g2.  This is guarenteed
-	 * to be nonzero.
-	 */
-	andn		%o2, 0x7, %g2			! A0	Group
-
-	/* You may read this and believe that it allows reading
-	 * one 8-byte longword past the end of src.  It actually
-	 * does not, as %g2 is subtracted as loads are done from
-	 * src, so we always stop before running off the end.
-	 * Also, we are guarenteed to have at least 0x10 bytes
-	 * to move here.
-	 */
-	sub		%g2, 0x8, %g2			! A0	Group (reg-dep)
-	alignaddr	%o1, %g0, %g1			! MS	      (Break-after)
-	ldd		[%g1 + 0x00], %f0		! MS	Group (1-cycle stall)
-	add		%g1, 0x8, %g1			! A0
-
-1:	ldd		[%g1 + 0x00], %f2		! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-	subcc		%g2, 0x8, %g2			! A0	Group
-
-	faligndata	%f0, %f2, %f8			! FGA	Group (1-cycle stall)
-	std		%f8, [%o0 + 0x00]		! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-	be,pn		%icc, 2f			! BR
-
-	 add		%o0, 0x8, %o0			! A1
-	ldd		[%g1 + 0x00], %f0		! MS	Group
-	add		%g1, 0x8, %g1			! A0
-	sub		%o2, 0x8, %o2			! A1
-
-	subcc		%g2, 0x8, %g2			! A0	Group
-	faligndata	%f2, %f0, %f8			! FGA	Group (1-cycle stall)
-	std		%f8, [%o0 + 0x00]		! MS	Group (2-cycle stall)
-	add		%o1, 0x8, %o1			! A0
-
-	bne,pn		%icc, 1b			! BR
-	 add		%o0, 0x8, %o0			! A1
-
-	/* Nothing left to copy? */
-2:	cmp		%o2, 0				! A0	Group
-	VISExitHalf					! A0+MS
-	be,pn		%icc, U3memcpy_short_ret	! BR	Group
-	 nop						! A0
-	ba,a,pt		%xcc, U3memcpy_short		! BR	Group
-
-#else /* !(SMALL_COPY_USES_FPU) */
-
-	xor		%o1, %o0, %g2
-	andcc		%g2, 0x7, %g0
-	bne,pn		%icc, U3memcpy_short
-	 andcc		%o1, 0x7, %g2
+	andcc		%g1, 0x7, %g0
+	bne,pn		%icc, small_copy_unaligned
+	 andcc		%o2, 0x8, %g0
+	be,pt		%icc, 1f
+	 nop
+	ldx		[%o1], %o5
+	stx		%o5, [%o1 + %o3]
+	add		%o1, 0x8, %o1
 
-	be,pt		%xcc, 2f
-	 sub		%g2, 0x8, %g2
-	sub		%g0, %g2, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x4, %g0
+	be,pt		%icc, 1f
+	 nop
+	lduw		[%o1], %o5
+	stw		%o5, [%o1 + %o3]
+	add		%o1, 0x4, %o1
 
-1:	ldub		[%o1 + 0x00], %o3
-	add		%o1, 0x1, %o1
-	add		%o0, 0x1, %o0
-	subcc		%g2, 0x1, %g2
-	bg,pt		%icc, 1b
-	 stb		%o3, [%o0 + -1]
+1:	andcc		%o2, 0x2, %g0
+	be,pt		%icc, 1f
+	 nop
+	lduh		[%o1], %o5
+	sth		%o5, [%o1 + %o3]
+	add		%o1, 0x2, %o1
 
-2:	andn		%o2, 0x7, %g2
-	sub		%o2, %g2, %o2
+1:	andcc		%o2, 0x1, %g0
+	be,pt		%icc, out
+	 nop
+	ldub		[%o1], %o5
+	ba,pt		%xcc, out
+	 stb		%o5, [%o1 + %o3]
+
+medium_copy: /* 16 < len <= 64 */
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+medium_copy_aligned:
+	andn		%o2, 0x7, %o4
+	and		%o2, 0x7, %o2
+1:	subcc		%o4, 0x8, %o4
+	ldx		[%o1], %o5
+	stx		%o5, [%o1 + %o3]
+	bgu,pt		%XCC, 1b
+	 add		%o1, 0x8, %o1
+	andcc		%o2, 0x4, %g0
+	be,pt		%XCC, 1f
+	 nop
+	sub		%o2, 0x4, %o2
+	lduw		[%o1], %o5
+	stw		%o5, [%o1 + %o3]
+	add		%o1, 0x4, %o1
+1:	cmp		%o2, 0
+	be,pt		%XCC, out
+	 nop
+	ba,pt		%xcc, small_copy_unaligned
+	 nop
 
-3:	ldx		[%o1 + 0x00], %o3
-	add		%o1, 0x8, %o1
-	add		%o0, 0x8, %o0
-	subcc		%g2, 0x8, %g2
-	bg,pt		%icc, 3b
-	 stx		%o3, [%o0 + -8]
+small_copy: /* 0 < len <= 16 */
+	andcc		%o3, 0x3, %g0
+	bne,pn		%XCC, small_copy_unaligned
+	 sub		%o0, %o1, %o3
+
+small_copy_aligned:
+	subcc		%o2, 4, %o2
+	lduw		[%o1], %g1
+	stw		%g1, [%o1 + %o3]
+	bgu,pt		%XCC, small_copy_aligned
+	 add		%o1, 4, %o1
 
-	cmp		%o2, 0
-	bne,pn		%icc, U3memcpy_short
-	 nop
-	ba,a,pt		%xcc, U3memcpy_short_ret
+out:	retl
+	 mov		%g5, %o0
 
-#endif /* !(SMALL_COPY_USES_FPU) */
+	.align	32
+small_copy_unaligned:
+	subcc		%o2, 1, %o2
+	ldub		[%o1], %g1
+	stb		%g1, [%o1 + %o3]
+	bgu,pt		%XCC, small_copy_unaligned
+	 add		%o1, 1, %o1
+	retl
+	 mov		%g5, %o0
+
+	/* Act like copy_{to,in}_user(), ie. return zero instead
+	 * of original destination pointer.  This is invoked when
+	 * copy_{to,in}_user() finds that %asi is kernel space.
+	 */
+	.globl	U3memcpy_user_stub
+U3memcpy_user_stub:
+	save		%sp, -192, %sp
+	mov		%i0, %o0
+	mov		%i1, %o1
+	call		U3memcpy
+	 mov		%i2, %o2
+	ret
+	 restore	%g0, %g0, %o0
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/lib/VIScopy.S linux-2.4.28-pre1/arch/sparc64/lib/VIScopy.S
--- linux-2.4.27/arch/sparc64/lib/VIScopy.S	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/lib/VIScopy.S	2004-08-15 19:47:59.000000000 +0000
@@ -306,11 +306,7 @@
 		.globl			__memcpy_begin
 __memcpy_begin:
 
-		.globl			__memcpy
-		.type			__memcpy,@function
-
 memcpy_private:
-__memcpy:
 memcpy:		mov		ASI_P, asi_src			! IEU0	Group
 		brnz,pt		%o2, __memcpy_entry		! CTI
 		 mov		ASI_P, asi_dest			! IEU1
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/sparc64/mm/fault.c linux-2.4.28-pre1/arch/sparc64/mm/fault.c
--- linux-2.4.27/arch/sparc64/mm/fault.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/arch/sparc64/mm/fault.c	2004-08-15 19:51:52.000000000 +0000
@@ -253,7 +253,7 @@ static void do_kernel_fault(struct pt_re
 	 * in that case.
 	 */
 
-	if (!(fault_code & FAULT_CODE_WRITE) &&
+	if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) &&
 	    (insn & 0xc0800000) == 0xc0800000) {
 		if (insn & 0x2000)
 			asi = (regs->tstate >> 24);
@@ -404,6 +404,16 @@ continue_fault:
 	 */
 good_area:
 	si_code = SEGV_ACCERR;
+
+	/* If we took a ITLB miss on a non-executable page, catch
+	 * that here.
+	 */
+	if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) {
+		BUG_ON(address != regs->tpc);
+		BUG_ON(regs->tstate & TSTATE_PRIV);
+		goto bad_area;
+	}
+
 	if (fault_code & FAULT_CODE_WRITE) {
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/x86_64/boot/compressed/misc.c linux-2.4.28-pre1/arch/x86_64/boot/compressed/misc.c
--- linux-2.4.27/arch/x86_64/boot/compressed/misc.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.28-pre1/arch/x86_64/boot/compressed/misc.c	2004-08-15 19:48:49.000000000 +0000
@@ -96,7 +96,7 @@ static void error(char *m);
 static void gzip_mark(void **);
 static void gzip_release(void **);
  
-static void puts(const char *);
+static void putstr(const char *);
   
 extern int end;
 static long free_mem_ptr = (long)&end;
@@ -157,7 +157,7 @@ static void scroll(void)
 		vidmem[i] = ' ';
 }
 
-static void puts(const char *s)
+static void putstr(const char *s)
 {
 	int x,y,pos;
 	char c;
@@ -275,9 +275,9 @@ static void flush_window(void)
 
 static void error(char *x)
 {
-	puts("\n\n");
-	puts(x);
-	puts("\n\n -- System halted");
+	putstr("\n\n");
+	putstr(x);
+	putstr("\n\n -- System halted");
 
 	while(1);
 }
@@ -351,9 +351,9 @@ int decompress_kernel(struct moveparams 
 	else setup_output_buffer_if_we_run_high(mv);
 
 	makecrc();
-	puts(".\nDecompressing Linux...");
+	putstr(".\nDecompressing Linux...");
 	gunzip();
-	puts("done.\nBooting the kernel.\n");
+	putstr("done.\nBooting the kernel.\n");
 	if (high_loaded) close_output_buffer_if_we_run_high(mv);
 	return high_loaded;
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.28-pre1/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.27/arch/x86_64/ia32/ia32_ioctl.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/arch/x86_64/ia32/ia32_ioctl.c	2004-08-15 19:51:23.000000000 +0000
@@ -1171,6 +1171,7 @@ static int fd_ioctl_trans(unsigned int f
 		case FDDEFPRM32:
 		case FDGETPRM32:
 		{
+			u32 name;
 			struct floppy_struct *f;
 
 			f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL);
@@ -1187,7 +1188,8 @@ static int fd_ioctl_trans(unsigned int f
 			err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
 			err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
 			err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
-			err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+			err |= __get_user(name, &((struct floppy_struct32 *)arg)->name);
+			f->name = (void*)(u64)name;
 			if (err) {
 				err = -EFAULT;
 				goto out;
@@ -2726,13 +2728,15 @@ static int blkpg_ioctl_trans(unsigned in
 {
 	struct blkpg_ioctl_arg a;
 	struct blkpg_partition p;
+	u32 udata;
 	int err;
 	mm_segment_t old_fs = get_fs();
 
 	err = get_user(a.op, &arg->op);
 	err |= __get_user(a.flags, &arg->flags);
 	err |= __get_user(a.datalen, &arg->datalen);
-	err |= __get_user((long)a.data, &arg->data);
+	err |= __get_user(udata, &arg->data);
+	a.data = (void*)(u64)udata;
 	if (err) return err;
 	switch (a.op) {
 	case BLKPG_ADD_PARTITION:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/x86_64/ia32/sys_ia32.c linux-2.4.28-pre1/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.27/arch/x86_64/ia32/sys_ia32.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/arch/x86_64/ia32/sys_ia32.c	2004-08-15 19:51:29.000000000 +0000
@@ -384,12 +384,16 @@ sys32_rt_sigaction(int sig, struct sigac
 		return -EINVAL;
 
 	if (act) {
+		u32 handler, restorer;
+
 		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
-		    __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
-		    __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer)||
+		    __get_user(restorer, &act->sa_restorer)||
 		    __copy_from_user(&set32, &act->sa_mask, sizeof(sigset32_t)))
 			return -EFAULT;
+		new_ka.sa.sa_handler = (void*)(u64)handler;
+		new_ka.sa.sa_restorer = (void*)(u64)restorer;
 
 		/* FIXME: here we rely on _IA32_NSIG_WORS to be >= than _NSIG_WORDS << 1 */
 		switch (_NSIG_WORDS) {
@@ -441,13 +445,16 @@ sys32_sigaction (int sig, struct old_sig
 
         if (act) {
 		old_sigset32_t mask;
+		u32 handler, restorer;
 
 		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
-		    __get_user((long)new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
-		    __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer) ||
+		    __get_user(restorer, &act->sa_restorer) ||
 		    __get_user(mask, &act->sa_mask))
 			return -EFAULT;
+		new_ka.sa.sa_handler = (void*)(u64)handler;
+		new_ka.sa.sa_restorer = (void*)(u64)restorer;
 		siginitset(&new_ka.sa.sa_mask, mask);
         }
 
@@ -778,7 +785,7 @@ filldir32 (void *__buf, const char *name
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = ((void *)dirent) + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.28-pre1/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.4.27/arch/x86_64/kernel/x8664_ksyms.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/arch/x86_64/kernel/x8664_ksyms.c	2004-08-15 19:50:35.000000000 +0000
@@ -157,7 +157,7 @@ extern void * memset(void *,int,__kernel
 extern __kernel_size_t strlen(const char *);
 extern int strcmp(const char *,const char *);
 extern char * strcpy(char *,const char *);
-extern char * bcopy(const char * src, char * dest, int count);
+extern void bcopy(const void * src, void * dest, size_t count);
 
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(__memcpy);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/arch/x86_64/lib/usercopy.c linux-2.4.28-pre1/arch/x86_64/lib/usercopy.c
--- linux-2.4.27/arch/x86_64/lib/usercopy.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/arch/x86_64/lib/usercopy.c	2004-08-15 19:50:23.000000000 +0000
@@ -88,7 +88,7 @@ unsigned long __clear_user(void *addr, u
 		"	.quad 1b,2b\n"
 		".previous"
 		: [size8] "=c"(size), [dst] "=&D" (__d0)
-		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr),
+		: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
 		  [zero] "r" (0UL), [eight] "r" (8UL));
 	return size;
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/Config.in linux-2.4.28-pre1/crypto/Config.in
--- linux-2.4.27/crypto/Config.in	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/crypto/Config.in	2004-08-15 19:51:34.000000000 +0000
@@ -73,6 +73,7 @@ if [ "$CONFIG_CRYPTO" = "y" ]; then
   tristate       '  CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5
   tristate       '  CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6
   tristate       '  TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA
+  tristate       '  Khazad cipher algorithm' CONFIG_CRYPTO_KHAZAD
   tristate       '  ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4
   if [ "$CONFIG_INET_IPCOMP" = "y" -o \
        "$CONFIG_INET_IPCOMP" = "m" -o \
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/Makefile linux-2.4.28-pre1/crypto/Makefile
--- linux-2.4.27/crypto/Makefile	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/crypto/Makefile	2004-08-15 19:48:44.000000000 +0000
@@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_TEA) += tea.o
+obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/aes.c linux-2.4.28-pre1/crypto/aes.c
--- linux-2.4.27/crypto/aes.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/crypto/aes.c	2004-08-15 19:48:29.000000000 +0000
@@ -160,7 +160,7 @@ gen_tabs (void)
 	u8 p, q;
 
 	/* log and power tables for GF(2**8) finite field with
-	   0x011b as modular polynomial - the simplest prmitive
+	   0x011b as modular polynomial - the simplest primitive
 	   root is 0x03, used here to generate the tables */
 
 	for (i = 0, p = 1; i < 256; ++i) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/arc4.c linux-2.4.28-pre1/crypto/arc4.c
--- linux-2.4.27/crypto/arc4.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/crypto/arc4.c	2004-08-15 19:50:06.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * ARC4 Cipher Algorithm
  *
- * Jon Oberheide <jon@focalhost.com>
+ * Jon Oberheide <jon@oberheide.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -100,4 +100,4 @@ module_exit(arc4_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ARC4 Cipher Algorithm");
-MODULE_AUTHOR("Jon Oberheide <jon@focalhost.com>");
+MODULE_AUTHOR("Jon Oberheide <jon@oberheide.org>");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/blowfish.c linux-2.4.28-pre1/crypto/blowfish.c
--- linux-2.4.27/crypto/blowfish.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/crypto/blowfish.c	2004-08-15 19:50:48.000000000 +0000
@@ -3,9 +3,9 @@
  *
  * Blowfish Cipher Algorithm, by Bruce Schneier.
  * http://www.counterpane.com/blowfish.html
- * 
- * Adapated from Kerneli implementation.
- * 
+ *
+ * Adapted from Kerneli implementation.
+ *
  * Copyright (c) Herbert Valerio Riedel <hvr@hvrlab.org>
  * Copyright (c) Kyle McMartin <kyle@debian.org>
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/khazad.c linux-2.4.28-pre1/crypto/khazad.c
--- linux-2.4.27/crypto/khazad.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/crypto/khazad.c	2004-08-15 19:50:57.000000000 +0000
@@ -0,0 +1,915 @@
+/*
+ * Cryptographic API.
+ *
+ * Khazad Algorithm
+ *
+ * The Khazad algorithm was developed by Paulo S. L. M. Barreto and
+ * Vincent Rijmen.  It was a finalist in the NESSIE encryption contest.
+ *
+ * The original authors have disclaimed all copyright interest in this
+ * code and thus put it in the public domain. The subsequent authors
+ * have put this under the GNU General Public License.
+ *
+ * By Aaron Grothe ajgrothe@yahoo.com, August 1, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define KHAZAD_KEY_SIZE		16
+#define KHAZAD_BLOCK_SIZE	8
+#define KHAZAD_ROUNDS		8
+
+struct khazad_ctx {
+	u64 E[KHAZAD_ROUNDS + 1];
+	u64 D[KHAZAD_ROUNDS + 1];
+};
+
+static const u64 T0[256] = {
+	0xbad3d268bbb96a01ULL, 0x54fc4d19e59a66b1ULL, 0x2f71bc93e26514cdULL,
+	0x749ccdb925871b51ULL, 0x53f55102f7a257a4ULL, 0xd3686bb8d0d6be03ULL,
+	0xd26b6fbdd6deb504ULL, 0x4dd72964b35285feULL, 0x50f05d0dfdba4aadULL,
+	0xace98a26cf09e063ULL, 0x8d8a0e83091c9684ULL, 0xbfdcc679a5914d1aULL,
+	0x7090ddad3da7374dULL, 0x52f65507f1aa5ca3ULL, 0x9ab352c87ba417e1ULL,
+	0x4cd42d61b55a8ef9ULL, 0xea238f65460320acULL, 0xd56273a6c4e68411ULL,
+	0x97a466f155cc68c2ULL, 0xd16e63b2dcc6a80dULL, 0x3355ccffaa85d099ULL,
+	0x51f35908fbb241aaULL, 0x5bed712ac7e20f9cULL, 0xa6f7a204f359ae55ULL,
+	0xde7f5f81febec120ULL, 0x48d83d75ad7aa2e5ULL, 0xa8e59a32d729cc7fULL,
+	0x99b65ec771bc0ae8ULL, 0xdb704b90e096e63bULL, 0x3256c8faac8ddb9eULL,
+	0xb7c4e65195d11522ULL, 0xfc19d72b32b3aaceULL, 0xe338ab48704b7393ULL,
+	0x9ebf42dc63843bfdULL, 0x91ae7eef41fc52d0ULL, 0x9bb056cd7dac1ce6ULL,
+	0xe23baf4d76437894ULL, 0xbbd0d66dbdb16106ULL, 0x41c319589b32f1daULL,
+	0x6eb2a5cb7957e517ULL, 0xa5f2ae0bf941b35cULL, 0xcb400bc08016564bULL,
+	0x6bbdb1da677fc20cULL, 0x95a26efb59dc7eccULL, 0xa1febe1fe1619f40ULL,
+	0xf308eb1810cbc3e3ULL, 0xb1cefe4f81e12f30ULL, 0x0206080a0c10160eULL,
+	0xcc4917db922e675eULL, 0xc45137f3a26e3f66ULL, 0x1d2774694ee8cf53ULL,
+	0x143c504478a09c6cULL, 0xc3582be8b0560e73ULL, 0x63a591f2573f9a34ULL,
+	0xda734f95e69eed3cULL, 0x5de76934d3d2358eULL, 0x5fe1613edfc22380ULL,
+	0xdc79578bf2aed72eULL, 0x7d87e99413cf486eULL, 0xcd4a13de94266c59ULL,
+	0x7f81e19e1fdf5e60ULL, 0x5aee752fc1ea049bULL, 0x6cb4adc17547f319ULL,
+	0x5ce46d31d5da3e89ULL, 0xf704fb0c08ebefffULL, 0x266a98bed42d47f2ULL,
+	0xff1cdb2438abb7c7ULL, 0xed2a937e543b11b9ULL, 0xe825876f4a1336a2ULL,
+	0x9dba4ed3699c26f4ULL, 0x6fb1a1ce7f5fee10ULL, 0x8e8f028c03048b8dULL,
+	0x192b647d56c8e34fULL, 0xa0fdba1ae7699447ULL, 0xf00de7171ad3deeaULL,
+	0x89861e97113cba98ULL, 0x0f113c332278692dULL, 0x07091c1b12383115ULL,
+	0xafec8629c511fd6aULL, 0xfb10cb30208b9bdbULL, 0x0818202830405838ULL,
+	0x153f54417ea8976bULL, 0x0d1734392e687f23ULL, 0x040c101418202c1cULL,
+	0x0103040506080b07ULL, 0x64ac8de94507ab21ULL, 0xdf7c5b84f8b6ca27ULL,
+	0x769ac5b329970d5fULL, 0x798bf9800bef6472ULL, 0xdd7a538ef4a6dc29ULL,
+	0x3d47f4c98ef5b2b3ULL, 0x163a584e74b08a62ULL, 0x3f41fcc382e5a4bdULL,
+	0x3759dcebb2a5fc85ULL, 0x6db7a9c4734ff81eULL, 0x3848e0d890dd95a8ULL,
+	0xb9d6de67b1a17708ULL, 0x7395d1a237bf2a44ULL, 0xe926836a4c1b3da5ULL,
+	0x355fd4e1beb5ea8bULL, 0x55ff491ce3926db6ULL, 0x7193d9a83baf3c4aULL,
+	0x7b8df18a07ff727cULL, 0x8c890a860f149d83ULL, 0x7296d5a731b72143ULL,
+	0x88851a921734b19fULL, 0xf607ff090ee3e4f8ULL, 0x2a7ea882fc4d33d6ULL,
+	0x3e42f8c684edafbaULL, 0x5ee2653bd9ca2887ULL, 0x27699cbbd2254cf5ULL,
+	0x46ca0543890ac0cfULL, 0x0c14303c28607424ULL, 0x65af89ec430fa026ULL,
+	0x68b8bdd56d67df05ULL, 0x61a399f85b2f8c3aULL, 0x03050c0f0a181d09ULL,
+	0xc15e23e2bc46187dULL, 0x57f94116ef827bb8ULL, 0xd6677fa9cefe9918ULL,
+	0xd976439aec86f035ULL, 0x58e87d25cdfa1295ULL, 0xd875479fea8efb32ULL,
+	0x66aa85e34917bd2fULL, 0xd7647bacc8f6921fULL, 0x3a4ee8d29ccd83a6ULL,
+	0xc84507cf8a0e4b42ULL, 0x3c44f0cc88fdb9b4ULL, 0xfa13cf35268390dcULL,
+	0x96a762f453c463c5ULL, 0xa7f4a601f551a552ULL, 0x98b55ac277b401efULL,
+	0xec29977b52331abeULL, 0xb8d5da62b7a97c0fULL, 0xc7543bfca876226fULL,
+	0xaeef822cc319f66dULL, 0x69bbb9d06b6fd402ULL, 0x4bdd317aa762bfecULL,
+	0xabe0963ddd31d176ULL, 0xa9e69e37d121c778ULL, 0x67a981e64f1fb628ULL,
+	0x0a1e28223c504e36ULL, 0x47c901468f02cbc8ULL, 0xf20bef1d16c3c8e4ULL,
+	0xb5c2ee5b99c1032cULL, 0x226688aacc0d6beeULL, 0xe532b356647b4981ULL,
+	0xee2f9f715e230cb0ULL, 0xbedfc27ca399461dULL, 0x2b7dac87fa4538d1ULL,
+	0x819e3ebf217ce2a0ULL, 0x1236485a6c90a67eULL, 0x839836b52d6cf4aeULL,
+	0x1b2d6c775ad8f541ULL, 0x0e1238362470622aULL, 0x23658cafca0560e9ULL,
+	0xf502f30604fbf9f1ULL, 0x45cf094c8312ddc6ULL, 0x216384a5c61576e7ULL,
+	0xce4f1fd19e3e7150ULL, 0x49db3970ab72a9e2ULL, 0x2c74b09ce87d09c4ULL,
+	0xf916c33a2c9b8dd5ULL, 0xe637bf596e635488ULL, 0xb6c7e25493d91e25ULL,
+	0x2878a088f05d25d8ULL, 0x17395c4b72b88165ULL, 0x829b32b02b64ffa9ULL,
+	0x1a2e68725cd0fe46ULL, 0x8b80169d1d2cac96ULL, 0xfe1fdf213ea3bcc0ULL,
+	0x8a8312981b24a791ULL, 0x091b242d3648533fULL, 0xc94603ca8c064045ULL,
+	0x879426a1354cd8b2ULL, 0x4ed2256bb94a98f7ULL, 0xe13ea3427c5b659dULL,
+	0x2e72b896e46d1fcaULL, 0xe431b75362734286ULL, 0xe03da7477a536e9aULL,
+	0xeb208b60400b2babULL, 0x90ad7aea47f459d7ULL, 0xa4f1aa0eff49b85bULL,
+	0x1e22786644f0d25aULL, 0x85922eab395ccebcULL, 0x60a09dfd5d27873dULL,
+	0x0000000000000000ULL, 0x256f94b1de355afbULL, 0xf401f70302f3f2f6ULL,
+	0xf10ee3121cdbd5edULL, 0x94a16afe5fd475cbULL, 0x0b1d2c273a584531ULL,
+	0xe734bb5c686b5f8fULL, 0x759fc9bc238f1056ULL, 0xef2c9b74582b07b7ULL,
+	0x345cd0e4b8bde18cULL, 0x3153c4f5a695c697ULL, 0xd46177a3c2ee8f16ULL,
+	0xd06d67b7dacea30aULL, 0x869722a43344d3b5ULL, 0x7e82e59b19d75567ULL,
+	0xadea8e23c901eb64ULL, 0xfd1ad32e34bba1c9ULL, 0x297ba48df6552edfULL,
+	0x3050c0f0a09dcd90ULL, 0x3b4decd79ac588a1ULL, 0x9fbc46d9658c30faULL,
+	0xf815c73f2a9386d2ULL, 0xc6573ff9ae7e2968ULL, 0x13354c5f6a98ad79ULL,
+	0x060a181e14303a12ULL, 0x050f14111e28271bULL, 0xc55233f6a4663461ULL,
+	0x113344556688bb77ULL, 0x7799c1b62f9f0658ULL, 0x7c84ed9115c74369ULL,
+	0x7a8ef58f01f7797bULL, 0x7888fd850de76f75ULL, 0x365ad8eeb4adf782ULL,
+	0x1c24706c48e0c454ULL, 0x394be4dd96d59eafULL, 0x59eb7920cbf21992ULL,
+	0x1828607850c0e848ULL, 0x56fa4513e98a70bfULL, 0xb3c8f6458df1393eULL,
+	0xb0cdfa4a87e92437ULL, 0x246c90b4d83d51fcULL, 0x206080a0c01d7de0ULL,
+	0xb2cbf2408bf93239ULL, 0x92ab72e04be44fd9ULL, 0xa3f8b615ed71894eULL,
+	0xc05d27e7ba4e137aULL, 0x44cc0d49851ad6c1ULL, 0x62a695f751379133ULL,
+	0x103040506080b070ULL, 0xb4c1ea5e9fc9082bULL, 0x84912aae3f54c5bbULL,
+	0x43c511529722e7d4ULL, 0x93a876e54dec44deULL, 0xc25b2fedb65e0574ULL,
+	0x4ade357fa16ab4ebULL, 0xbddace73a9815b14ULL, 0x8f8c0689050c808aULL,
+	0x2d77b499ee7502c3ULL, 0xbcd9ca76af895013ULL, 0x9cb94ad66f942df3ULL,
+	0x6abeb5df6177c90bULL, 0x40c01d5d9d3afaddULL, 0xcf4c1bd498367a57ULL,
+	0xa2fbb210eb798249ULL, 0x809d3aba2774e9a7ULL, 0x4fd1216ebf4293f0ULL,
+	0x1f217c6342f8d95dULL, 0xca430fc5861e5d4cULL, 0xaae39238db39da71ULL,
+	0x42c61557912aecd3ULL
+};
+
+static const u64 T1[256] = {
+	0xd3ba68d2b9bb016aULL, 0xfc54194d9ae5b166ULL, 0x712f93bc65e2cd14ULL,
+	0x9c74b9cd8725511bULL, 0xf5530251a2f7a457ULL, 0x68d3b86bd6d003beULL,
+	0x6bd2bd6fded604b5ULL, 0xd74d642952b3fe85ULL, 0xf0500d5dbafdad4aULL,
+	0xe9ac268a09cf63e0ULL, 0x8a8d830e1c098496ULL, 0xdcbf79c691a51a4dULL,
+	0x9070addda73d4d37ULL, 0xf6520755aaf1a35cULL, 0xb39ac852a47be117ULL,
+	0xd44c612d5ab5f98eULL, 0x23ea658f0346ac20ULL, 0x62d5a673e6c41184ULL,
+	0xa497f166cc55c268ULL, 0x6ed1b263c6dc0da8ULL, 0x5533ffcc85aa99d0ULL,
+	0xf3510859b2fbaa41ULL, 0xed5b2a71e2c79c0fULL, 0xf7a604a259f355aeULL,
+	0x7fde815fbefe20c1ULL, 0xd848753d7aade5a2ULL, 0xe5a8329a29d77fccULL,
+	0xb699c75ebc71e80aULL, 0x70db904b96e03be6ULL, 0x5632fac88dac9edbULL,
+	0xc4b751e6d1952215ULL, 0x19fc2bd7b332ceaaULL, 0x38e348ab4b709373ULL,
+	0xbf9edc428463fd3bULL, 0xae91ef7efc41d052ULL, 0xb09bcd56ac7de61cULL,
+	0x3be24daf43769478ULL, 0xd0bb6dd6b1bd0661ULL, 0xc3415819329bdaf1ULL,
+	0xb26ecba5577917e5ULL, 0xf2a50bae41f95cb3ULL, 0x40cbc00b16804b56ULL,
+	0xbd6bdab17f670cc2ULL, 0xa295fb6edc59cc7eULL, 0xfea11fbe61e1409fULL,
+	0x08f318ebcb10e3c3ULL, 0xceb14ffee181302fULL, 0x06020a08100c0e16ULL,
+	0x49ccdb172e925e67ULL, 0x51c4f3376ea2663fULL, 0x271d6974e84e53cfULL,
+	0x3c144450a0786c9cULL, 0x58c3e82b56b0730eULL, 0xa563f2913f57349aULL,
+	0x73da954f9ee63cedULL, 0xe75d3469d2d38e35ULL, 0xe15f3e61c2df8023ULL,
+	0x79dc8b57aef22ed7ULL, 0x877d94e9cf136e48ULL, 0x4acdde132694596cULL,
+	0x817f9ee1df1f605eULL, 0xee5a2f75eac19b04ULL, 0xb46cc1ad477519f3ULL,
+	0xe45c316ddad5893eULL, 0x04f70cfbeb08ffefULL, 0x6a26be982dd4f247ULL,
+	0x1cff24dbab38c7b7ULL, 0x2aed7e933b54b911ULL, 0x25e86f87134aa236ULL,
+	0xba9dd34e9c69f426ULL, 0xb16fcea15f7f10eeULL, 0x8f8e8c0204038d8bULL,
+	0x2b197d64c8564fe3ULL, 0xfda01aba69e74794ULL, 0x0df017e7d31aeadeULL,
+	0x8689971e3c1198baULL, 0x110f333c78222d69ULL, 0x09071b1c38121531ULL,
+	0xecaf298611c56afdULL, 0x10fb30cb8b20db9bULL, 0x1808282040303858ULL,
+	0x3f154154a87e6b97ULL, 0x170d3934682e237fULL, 0x0c04141020181c2cULL,
+	0x030105040806070bULL, 0xac64e98d074521abULL, 0x7cdf845bb6f827caULL,
+	0x9a76b3c597295f0dULL, 0x8b7980f9ef0b7264ULL, 0x7add8e53a6f429dcULL,
+	0x473dc9f4f58eb3b2ULL, 0x3a164e58b074628aULL, 0x413fc3fce582bda4ULL,
+	0x5937ebdca5b285fcULL, 0xb76dc4a94f731ef8ULL, 0x4838d8e0dd90a895ULL,
+	0xd6b967dea1b10877ULL, 0x9573a2d1bf37442aULL, 0x26e96a831b4ca53dULL,
+	0x5f35e1d4b5be8beaULL, 0xff551c4992e3b66dULL, 0x9371a8d9af3b4a3cULL,
+	0x8d7b8af1ff077c72ULL, 0x898c860a140f839dULL, 0x9672a7d5b7314321ULL,
+	0x8588921a34179fb1ULL, 0x07f609ffe30ef8e4ULL, 0x7e2a82a84dfcd633ULL,
+	0x423ec6f8ed84baafULL, 0xe25e3b65cad98728ULL, 0x6927bb9c25d2f54cULL,
+	0xca4643050a89cfc0ULL, 0x140c3c3060282474ULL, 0xaf65ec890f4326a0ULL,
+	0xb868d5bd676d05dfULL, 0xa361f8992f5b3a8cULL, 0x05030f0c180a091dULL,
+	0x5ec1e22346bc7d18ULL, 0xf957164182efb87bULL, 0x67d6a97ffece1899ULL,
+	0x76d99a4386ec35f0ULL, 0xe858257dfacd9512ULL, 0x75d89f478eea32fbULL,
+	0xaa66e38517492fbdULL, 0x64d7ac7bf6c81f92ULL, 0x4e3ad2e8cd9ca683ULL,
+	0x45c8cf070e8a424bULL, 0x443cccf0fd88b4b9ULL, 0x13fa35cf8326dc90ULL,
+	0xa796f462c453c563ULL, 0xf4a701a651f552a5ULL, 0xb598c25ab477ef01ULL,
+	0x29ec7b973352be1aULL, 0xd5b862daa9b70f7cULL, 0x54c7fc3b76a86f22ULL,
+	0xefae2c8219c36df6ULL, 0xbb69d0b96f6b02d4ULL, 0xdd4b7a3162a7ecbfULL,
+	0xe0ab3d9631dd76d1ULL, 0xe6a9379e21d178c7ULL, 0xa967e6811f4f28b6ULL,
+	0x1e0a2228503c364eULL, 0xc9474601028fc8cbULL, 0x0bf21defc316e4c8ULL,
+	0xc2b55beec1992c03ULL, 0x6622aa880dccee6bULL, 0x32e556b37b648149ULL,
+	0x2fee719f235eb00cULL, 0xdfbe7cc299a31d46ULL, 0x7d2b87ac45fad138ULL,
+	0x9e81bf3e7c21a0e2ULL, 0x36125a48906c7ea6ULL, 0x9883b5366c2daef4ULL,
+	0x2d1b776cd85a41f5ULL, 0x120e363870242a62ULL, 0x6523af8c05cae960ULL,
+	0x02f506f3fb04f1f9ULL, 0xcf454c091283c6ddULL, 0x6321a58415c6e776ULL,
+	0x4fced11f3e9e5071ULL, 0xdb49703972abe2a9ULL, 0x742c9cb07de8c409ULL,
+	0x16f93ac39b2cd58dULL, 0x37e659bf636e8854ULL, 0xc7b654e2d993251eULL,
+	0x782888a05df0d825ULL, 0x39174b5cb8726581ULL, 0x9b82b032642ba9ffULL,
+	0x2e1a7268d05c46feULL, 0x808b9d162c1d96acULL, 0x1ffe21dfa33ec0bcULL,
+	0x838a9812241b91a7ULL, 0x1b092d2448363f53ULL, 0x46c9ca03068c4540ULL,
+	0x9487a1264c35b2d8ULL, 0xd24e6b254ab9f798ULL, 0x3ee142a35b7c9d65ULL,
+	0x722e96b86de4ca1fULL, 0x31e453b773628642ULL, 0x3de047a7537a9a6eULL,
+	0x20eb608b0b40ab2bULL, 0xad90ea7af447d759ULL, 0xf1a40eaa49ff5bb8ULL,
+	0x221e6678f0445ad2ULL, 0x9285ab2e5c39bcceULL, 0xa060fd9d275d3d87ULL,
+	0x0000000000000000ULL, 0x6f25b19435defb5aULL, 0x01f403f7f302f6f2ULL,
+	0x0ef112e3db1cedd5ULL, 0xa194fe6ad45fcb75ULL, 0x1d0b272c583a3145ULL,
+	0x34e75cbb6b688f5fULL, 0x9f75bcc98f235610ULL, 0x2cef749b2b58b707ULL,
+	0x5c34e4d0bdb88ce1ULL, 0x5331f5c495a697c6ULL, 0x61d4a377eec2168fULL,
+	0x6dd0b767ceda0aa3ULL, 0x9786a4224433b5d3ULL, 0x827e9be5d7196755ULL,
+	0xeaad238e01c964ebULL, 0x1afd2ed3bb34c9a1ULL, 0x7b298da455f6df2eULL,
+	0x5030f0c09da090cdULL, 0x4d3bd7ecc59aa188ULL, 0xbc9fd9468c65fa30ULL,
+	0x15f83fc7932ad286ULL, 0x57c6f93f7eae6829ULL, 0x35135f4c986a79adULL,
+	0x0a061e183014123aULL, 0x0f051114281e1b27ULL, 0x52c5f63366a46134ULL,
+	0x33115544886677bbULL, 0x9977b6c19f2f5806ULL, 0x847c91edc7156943ULL,
+	0x8e7a8ff5f7017b79ULL, 0x887885fde70d756fULL, 0x5a36eed8adb482f7ULL,
+	0x241c6c70e04854c4ULL, 0x4b39dde4d596af9eULL, 0xeb592079f2cb9219ULL,
+	0x28187860c05048e8ULL, 0xfa5613458ae9bf70ULL, 0xc8b345f6f18d3e39ULL,
+	0xcdb04afae9873724ULL, 0x6c24b4903dd8fc51ULL, 0x6020a0801dc0e07dULL,
+	0xcbb240f2f98b3932ULL, 0xab92e072e44bd94fULL, 0xf8a315b671ed4e89ULL,
+	0x5dc0e7274eba7a13ULL, 0xcc44490d1a85c1d6ULL, 0xa662f79537513391ULL,
+	0x30105040806070b0ULL, 0xc1b45eeac99f2b08ULL, 0x9184ae2a543fbbc5ULL,
+	0xc54352112297d4e7ULL, 0xa893e576ec4dde44ULL, 0x5bc2ed2f5eb67405ULL,
+	0xde4a7f356aa1ebb4ULL, 0xdabd73ce81a9145bULL, 0x8c8f89060c058a80ULL,
+	0x772d99b475eec302ULL, 0xd9bc76ca89af1350ULL, 0xb99cd64a946ff32dULL,
+	0xbe6adfb577610bc9ULL, 0xc0405d1d3a9dddfaULL, 0x4ccfd41b3698577aULL,
+	0xfba210b279eb4982ULL, 0x9d80ba3a7427a7e9ULL, 0xd14f6e2142bff093ULL,
+	0x211f637cf8425dd9ULL, 0x43cac50f1e864c5dULL, 0xe3aa389239db71daULL,
+	0xc64257152a91d3ecULL
+};
+
+static const u64 T2[256] = {
+	0xd268bad36a01bbb9ULL, 0x4d1954fc66b1e59aULL, 0xbc932f7114cde265ULL,
+	0xcdb9749c1b512587ULL, 0x510253f557a4f7a2ULL, 0x6bb8d368be03d0d6ULL,
+	0x6fbdd26bb504d6deULL, 0x29644dd785feb352ULL, 0x5d0d50f04aadfdbaULL,
+	0x8a26ace9e063cf09ULL, 0x0e838d8a9684091cULL, 0xc679bfdc4d1aa591ULL,
+	0xddad7090374d3da7ULL, 0x550752f65ca3f1aaULL, 0x52c89ab317e17ba4ULL,
+	0x2d614cd48ef9b55aULL, 0x8f65ea2320ac4603ULL, 0x73a6d5628411c4e6ULL,
+	0x66f197a468c255ccULL, 0x63b2d16ea80ddcc6ULL, 0xccff3355d099aa85ULL,
+	0x590851f341aafbb2ULL, 0x712a5bed0f9cc7e2ULL, 0xa204a6f7ae55f359ULL,
+	0x5f81de7fc120febeULL, 0x3d7548d8a2e5ad7aULL, 0x9a32a8e5cc7fd729ULL,
+	0x5ec799b60ae871bcULL, 0x4b90db70e63be096ULL, 0xc8fa3256db9eac8dULL,
+	0xe651b7c4152295d1ULL, 0xd72bfc19aace32b3ULL, 0xab48e3387393704bULL,
+	0x42dc9ebf3bfd6384ULL, 0x7eef91ae52d041fcULL, 0x56cd9bb01ce67dacULL,
+	0xaf4de23b78947643ULL, 0xd66dbbd06106bdb1ULL, 0x195841c3f1da9b32ULL,
+	0xa5cb6eb2e5177957ULL, 0xae0ba5f2b35cf941ULL, 0x0bc0cb40564b8016ULL,
+	0xb1da6bbdc20c677fULL, 0x6efb95a27ecc59dcULL, 0xbe1fa1fe9f40e161ULL,
+	0xeb18f308c3e310cbULL, 0xfe4fb1ce2f3081e1ULL, 0x080a0206160e0c10ULL,
+	0x17dbcc49675e922eULL, 0x37f3c4513f66a26eULL, 0x74691d27cf534ee8ULL,
+	0x5044143c9c6c78a0ULL, 0x2be8c3580e73b056ULL, 0x91f263a59a34573fULL,
+	0x4f95da73ed3ce69eULL, 0x69345de7358ed3d2ULL, 0x613e5fe12380dfc2ULL,
+	0x578bdc79d72ef2aeULL, 0xe9947d87486e13cfULL, 0x13decd4a6c599426ULL,
+	0xe19e7f815e601fdfULL, 0x752f5aee049bc1eaULL, 0xadc16cb4f3197547ULL,
+	0x6d315ce43e89d5daULL, 0xfb0cf704efff08ebULL, 0x98be266a47f2d42dULL,
+	0xdb24ff1cb7c738abULL, 0x937eed2a11b9543bULL, 0x876fe82536a24a13ULL,
+	0x4ed39dba26f4699cULL, 0xa1ce6fb1ee107f5fULL, 0x028c8e8f8b8d0304ULL,
+	0x647d192be34f56c8ULL, 0xba1aa0fd9447e769ULL, 0xe717f00ddeea1ad3ULL,
+	0x1e978986ba98113cULL, 0x3c330f11692d2278ULL, 0x1c1b070931151238ULL,
+	0x8629afecfd6ac511ULL, 0xcb30fb109bdb208bULL, 0x2028081858383040ULL,
+	0x5441153f976b7ea8ULL, 0x34390d177f232e68ULL, 0x1014040c2c1c1820ULL,
+	0x040501030b070608ULL, 0x8de964acab214507ULL, 0x5b84df7cca27f8b6ULL,
+	0xc5b3769a0d5f2997ULL, 0xf980798b64720befULL, 0x538edd7adc29f4a6ULL,
+	0xf4c93d47b2b38ef5ULL, 0x584e163a8a6274b0ULL, 0xfcc33f41a4bd82e5ULL,
+	0xdceb3759fc85b2a5ULL, 0xa9c46db7f81e734fULL, 0xe0d8384895a890ddULL,
+	0xde67b9d67708b1a1ULL, 0xd1a273952a4437bfULL, 0x836ae9263da54c1bULL,
+	0xd4e1355fea8bbeb5ULL, 0x491c55ff6db6e392ULL, 0xd9a871933c4a3bafULL,
+	0xf18a7b8d727c07ffULL, 0x0a868c899d830f14ULL, 0xd5a77296214331b7ULL,
+	0x1a928885b19f1734ULL, 0xff09f607e4f80ee3ULL, 0xa8822a7e33d6fc4dULL,
+	0xf8c63e42afba84edULL, 0x653b5ee22887d9caULL, 0x9cbb27694cf5d225ULL,
+	0x054346cac0cf890aULL, 0x303c0c1474242860ULL, 0x89ec65afa026430fULL,
+	0xbdd568b8df056d67ULL, 0x99f861a38c3a5b2fULL, 0x0c0f03051d090a18ULL,
+	0x23e2c15e187dbc46ULL, 0x411657f97bb8ef82ULL, 0x7fa9d6679918cefeULL,
+	0x439ad976f035ec86ULL, 0x7d2558e81295cdfaULL, 0x479fd875fb32ea8eULL,
+	0x85e366aabd2f4917ULL, 0x7bacd764921fc8f6ULL, 0xe8d23a4e83a69ccdULL,
+	0x07cfc8454b428a0eULL, 0xf0cc3c44b9b488fdULL, 0xcf35fa1390dc2683ULL,
+	0x62f496a763c553c4ULL, 0xa601a7f4a552f551ULL, 0x5ac298b501ef77b4ULL,
+	0x977bec291abe5233ULL, 0xda62b8d57c0fb7a9ULL, 0x3bfcc754226fa876ULL,
+	0x822caeeff66dc319ULL, 0xb9d069bbd4026b6fULL, 0x317a4bddbfeca762ULL,
+	0x963dabe0d176dd31ULL, 0x9e37a9e6c778d121ULL, 0x81e667a9b6284f1fULL,
+	0x28220a1e4e363c50ULL, 0x014647c9cbc88f02ULL, 0xef1df20bc8e416c3ULL,
+	0xee5bb5c2032c99c1ULL, 0x88aa22666beecc0dULL, 0xb356e5324981647bULL,
+	0x9f71ee2f0cb05e23ULL, 0xc27cbedf461da399ULL, 0xac872b7d38d1fa45ULL,
+	0x3ebf819ee2a0217cULL, 0x485a1236a67e6c90ULL, 0x36b58398f4ae2d6cULL,
+	0x6c771b2df5415ad8ULL, 0x38360e12622a2470ULL, 0x8caf236560e9ca05ULL,
+	0xf306f502f9f104fbULL, 0x094c45cfddc68312ULL, 0x84a5216376e7c615ULL,
+	0x1fd1ce4f71509e3eULL, 0x397049dba9e2ab72ULL, 0xb09c2c7409c4e87dULL,
+	0xc33af9168dd52c9bULL, 0xbf59e63754886e63ULL, 0xe254b6c71e2593d9ULL,
+	0xa088287825d8f05dULL, 0x5c4b1739816572b8ULL, 0x32b0829bffa92b64ULL,
+	0x68721a2efe465cd0ULL, 0x169d8b80ac961d2cULL, 0xdf21fe1fbcc03ea3ULL,
+	0x12988a83a7911b24ULL, 0x242d091b533f3648ULL, 0x03cac94640458c06ULL,
+	0x26a18794d8b2354cULL, 0x256b4ed298f7b94aULL, 0xa342e13e659d7c5bULL,
+	0xb8962e721fcae46dULL, 0xb753e43142866273ULL, 0xa747e03d6e9a7a53ULL,
+	0x8b60eb202bab400bULL, 0x7aea90ad59d747f4ULL, 0xaa0ea4f1b85bff49ULL,
+	0x78661e22d25a44f0ULL, 0x2eab8592cebc395cULL, 0x9dfd60a0873d5d27ULL,
+	0x0000000000000000ULL, 0x94b1256f5afbde35ULL, 0xf703f401f2f602f3ULL,
+	0xe312f10ed5ed1cdbULL, 0x6afe94a175cb5fd4ULL, 0x2c270b1d45313a58ULL,
+	0xbb5ce7345f8f686bULL, 0xc9bc759f1056238fULL, 0x9b74ef2c07b7582bULL,
+	0xd0e4345ce18cb8bdULL, 0xc4f53153c697a695ULL, 0x77a3d4618f16c2eeULL,
+	0x67b7d06da30adaceULL, 0x22a48697d3b53344ULL, 0xe59b7e82556719d7ULL,
+	0x8e23adeaeb64c901ULL, 0xd32efd1aa1c934bbULL, 0xa48d297b2edff655ULL,
+	0xc0f03050cd90a09dULL, 0xecd73b4d88a19ac5ULL, 0x46d99fbc30fa658cULL,
+	0xc73ff81586d22a93ULL, 0x3ff9c6572968ae7eULL, 0x4c5f1335ad796a98ULL,
+	0x181e060a3a121430ULL, 0x1411050f271b1e28ULL, 0x33f6c5523461a466ULL,
+	0x44551133bb776688ULL, 0xc1b6779906582f9fULL, 0xed917c84436915c7ULL,
+	0xf58f7a8e797b01f7ULL, 0xfd8578886f750de7ULL, 0xd8ee365af782b4adULL,
+	0x706c1c24c45448e0ULL, 0xe4dd394b9eaf96d5ULL, 0x792059eb1992cbf2ULL,
+	0x60781828e84850c0ULL, 0x451356fa70bfe98aULL, 0xf645b3c8393e8df1ULL,
+	0xfa4ab0cd243787e9ULL, 0x90b4246c51fcd83dULL, 0x80a020607de0c01dULL,
+	0xf240b2cb32398bf9ULL, 0x72e092ab4fd94be4ULL, 0xb615a3f8894eed71ULL,
+	0x27e7c05d137aba4eULL, 0x0d4944ccd6c1851aULL, 0x95f762a691335137ULL,
+	0x40501030b0706080ULL, 0xea5eb4c1082b9fc9ULL, 0x2aae8491c5bb3f54ULL,
+	0x115243c5e7d49722ULL, 0x76e593a844de4decULL, 0x2fedc25b0574b65eULL,
+	0x357f4adeb4eba16aULL, 0xce73bdda5b14a981ULL, 0x06898f8c808a050cULL,
+	0xb4992d7702c3ee75ULL, 0xca76bcd95013af89ULL, 0x4ad69cb92df36f94ULL,
+	0xb5df6abec90b6177ULL, 0x1d5d40c0fadd9d3aULL, 0x1bd4cf4c7a579836ULL,
+	0xb210a2fb8249eb79ULL, 0x3aba809de9a72774ULL, 0x216e4fd193f0bf42ULL,
+	0x7c631f21d95d42f8ULL, 0x0fc5ca435d4c861eULL, 0x9238aae3da71db39ULL,
+	0x155742c6ecd3912aULL
+};
+
+static const u64 T3[256] = {
+	0x68d2d3ba016ab9bbULL, 0x194dfc54b1669ae5ULL, 0x93bc712fcd1465e2ULL,
+	0xb9cd9c74511b8725ULL, 0x0251f553a457a2f7ULL, 0xb86b68d303bed6d0ULL,
+	0xbd6f6bd204b5ded6ULL, 0x6429d74dfe8552b3ULL, 0x0d5df050ad4abafdULL,
+	0x268ae9ac63e009cfULL, 0x830e8a8d84961c09ULL, 0x79c6dcbf1a4d91a5ULL,
+	0xaddd90704d37a73dULL, 0x0755f652a35caaf1ULL, 0xc852b39ae117a47bULL,
+	0x612dd44cf98e5ab5ULL, 0x658f23eaac200346ULL, 0xa67362d51184e6c4ULL,
+	0xf166a497c268cc55ULL, 0xb2636ed10da8c6dcULL, 0xffcc553399d085aaULL,
+	0x0859f351aa41b2fbULL, 0x2a71ed5b9c0fe2c7ULL, 0x04a2f7a655ae59f3ULL,
+	0x815f7fde20c1befeULL, 0x753dd848e5a27aadULL, 0x329ae5a87fcc29d7ULL,
+	0xc75eb699e80abc71ULL, 0x904b70db3be696e0ULL, 0xfac856329edb8dacULL,
+	0x51e6c4b72215d195ULL, 0x2bd719fcceaab332ULL, 0x48ab38e393734b70ULL,
+	0xdc42bf9efd3b8463ULL, 0xef7eae91d052fc41ULL, 0xcd56b09be61cac7dULL,
+	0x4daf3be294784376ULL, 0x6dd6d0bb0661b1bdULL, 0x5819c341daf1329bULL,
+	0xcba5b26e17e55779ULL, 0x0baef2a55cb341f9ULL, 0xc00b40cb4b561680ULL,
+	0xdab1bd6b0cc27f67ULL, 0xfb6ea295cc7edc59ULL, 0x1fbefea1409f61e1ULL,
+	0x18eb08f3e3c3cb10ULL, 0x4ffeceb1302fe181ULL, 0x0a0806020e16100cULL,
+	0xdb1749cc5e672e92ULL, 0xf33751c4663f6ea2ULL, 0x6974271d53cfe84eULL,
+	0x44503c146c9ca078ULL, 0xe82b58c3730e56b0ULL, 0xf291a563349a3f57ULL,
+	0x954f73da3ced9ee6ULL, 0x3469e75d8e35d2d3ULL, 0x3e61e15f8023c2dfULL,
+	0x8b5779dc2ed7aef2ULL, 0x94e9877d6e48cf13ULL, 0xde134acd596c2694ULL,
+	0x9ee1817f605edf1fULL, 0x2f75ee5a9b04eac1ULL, 0xc1adb46c19f34775ULL,
+	0x316de45c893edad5ULL, 0x0cfb04f7ffefeb08ULL, 0xbe986a26f2472dd4ULL,
+	0x24db1cffc7b7ab38ULL, 0x7e932aedb9113b54ULL, 0x6f8725e8a236134aULL,
+	0xd34eba9df4269c69ULL, 0xcea1b16f10ee5f7fULL, 0x8c028f8e8d8b0403ULL,
+	0x7d642b194fe3c856ULL, 0x1abafda0479469e7ULL, 0x17e70df0eaded31aULL,
+	0x971e868998ba3c11ULL, 0x333c110f2d697822ULL, 0x1b1c090715313812ULL,
+	0x2986ecaf6afd11c5ULL, 0x30cb10fbdb9b8b20ULL, 0x2820180838584030ULL,
+	0x41543f156b97a87eULL, 0x3934170d237f682eULL, 0x14100c041c2c2018ULL,
+	0x05040301070b0806ULL, 0xe98dac6421ab0745ULL, 0x845b7cdf27cab6f8ULL,
+	0xb3c59a765f0d9729ULL, 0x80f98b797264ef0bULL, 0x8e537add29dca6f4ULL,
+	0xc9f4473db3b2f58eULL, 0x4e583a16628ab074ULL, 0xc3fc413fbda4e582ULL,
+	0xebdc593785fca5b2ULL, 0xc4a9b76d1ef84f73ULL, 0xd8e04838a895dd90ULL,
+	0x67ded6b90877a1b1ULL, 0xa2d19573442abf37ULL, 0x6a8326e9a53d1b4cULL,
+	0xe1d45f358beab5beULL, 0x1c49ff55b66d92e3ULL, 0xa8d993714a3caf3bULL,
+	0x8af18d7b7c72ff07ULL, 0x860a898c839d140fULL, 0xa7d596724321b731ULL,
+	0x921a85889fb13417ULL, 0x09ff07f6f8e4e30eULL, 0x82a87e2ad6334dfcULL,
+	0xc6f8423ebaafed84ULL, 0x3b65e25e8728cad9ULL, 0xbb9c6927f54c25d2ULL,
+	0x4305ca46cfc00a89ULL, 0x3c30140c24746028ULL, 0xec89af6526a00f43ULL,
+	0xd5bdb86805df676dULL, 0xf899a3613a8c2f5bULL, 0x0f0c0503091d180aULL,
+	0xe2235ec17d1846bcULL, 0x1641f957b87b82efULL, 0xa97f67d61899feceULL,
+	0x9a4376d935f086ecULL, 0x257de8589512facdULL, 0x9f4775d832fb8eeaULL,
+	0xe385aa662fbd1749ULL, 0xac7b64d71f92f6c8ULL, 0xd2e84e3aa683cd9cULL,
+	0xcf0745c8424b0e8aULL, 0xccf0443cb4b9fd88ULL, 0x35cf13fadc908326ULL,
+	0xf462a796c563c453ULL, 0x01a6f4a752a551f5ULL, 0xc25ab598ef01b477ULL,
+	0x7b9729ecbe1a3352ULL, 0x62dad5b80f7ca9b7ULL, 0xfc3b54c76f2276a8ULL,
+	0x2c82efae6df619c3ULL, 0xd0b9bb6902d46f6bULL, 0x7a31dd4becbf62a7ULL,
+	0x3d96e0ab76d131ddULL, 0x379ee6a978c721d1ULL, 0xe681a96728b61f4fULL,
+	0x22281e0a364e503cULL, 0x4601c947c8cb028fULL, 0x1def0bf2e4c8c316ULL,
+	0x5beec2b52c03c199ULL, 0xaa886622ee6b0dccULL, 0x56b332e581497b64ULL,
+	0x719f2feeb00c235eULL, 0x7cc2dfbe1d4699a3ULL, 0x87ac7d2bd13845faULL,
+	0xbf3e9e81a0e27c21ULL, 0x5a4836127ea6906cULL, 0xb5369883aef46c2dULL,
+	0x776c2d1b41f5d85aULL, 0x3638120e2a627024ULL, 0xaf8c6523e96005caULL,
+	0x06f302f5f1f9fb04ULL, 0x4c09cf45c6dd1283ULL, 0xa5846321e77615c6ULL,
+	0xd11f4fce50713e9eULL, 0x7039db49e2a972abULL, 0x9cb0742cc4097de8ULL,
+	0x3ac316f9d58d9b2cULL, 0x59bf37e68854636eULL, 0x54e2c7b6251ed993ULL,
+	0x88a07828d8255df0ULL, 0x4b5c39176581b872ULL, 0xb0329b82a9ff642bULL,
+	0x72682e1a46fed05cULL, 0x9d16808b96ac2c1dULL, 0x21df1ffec0bca33eULL,
+	0x9812838a91a7241bULL, 0x2d241b093f534836ULL, 0xca0346c94540068cULL,
+	0xa1269487b2d84c35ULL, 0x6b25d24ef7984ab9ULL, 0x42a33ee19d655b7cULL,
+	0x96b8722eca1f6de4ULL, 0x53b731e486427362ULL, 0x47a73de09a6e537aULL,
+	0x608b20ebab2b0b40ULL, 0xea7aad90d759f447ULL, 0x0eaaf1a45bb849ffULL,
+	0x6678221e5ad2f044ULL, 0xab2e9285bcce5c39ULL, 0xfd9da0603d87275dULL,
+	0x0000000000000000ULL, 0xb1946f25fb5a35deULL, 0x03f701f4f6f2f302ULL,
+	0x12e30ef1edd5db1cULL, 0xfe6aa194cb75d45fULL, 0x272c1d0b3145583aULL,
+	0x5cbb34e78f5f6b68ULL, 0xbcc99f7556108f23ULL, 0x749b2cefb7072b58ULL,
+	0xe4d05c348ce1bdb8ULL, 0xf5c4533197c695a6ULL, 0xa37761d4168feec2ULL,
+	0xb7676dd00aa3cedaULL, 0xa4229786b5d34433ULL, 0x9be5827e6755d719ULL,
+	0x238eeaad64eb01c9ULL, 0x2ed31afdc9a1bb34ULL, 0x8da47b29df2e55f6ULL,
+	0xf0c0503090cd9da0ULL, 0xd7ec4d3ba188c59aULL, 0xd946bc9ffa308c65ULL,
+	0x3fc715f8d286932aULL, 0xf93f57c668297eaeULL, 0x5f4c351379ad986aULL,
+	0x1e180a06123a3014ULL, 0x11140f051b27281eULL, 0xf63352c5613466a4ULL,
+	0x5544331177bb8866ULL, 0xb6c1997758069f2fULL, 0x91ed847c6943c715ULL,
+	0x8ff58e7a7b79f701ULL, 0x85fd8878756fe70dULL, 0xeed85a3682f7adb4ULL,
+	0x6c70241c54c4e048ULL, 0xdde44b39af9ed596ULL, 0x2079eb599219f2cbULL,
+	0x7860281848e8c050ULL, 0x1345fa56bf708ae9ULL, 0x45f6c8b33e39f18dULL,
+	0x4afacdb03724e987ULL, 0xb4906c24fc513dd8ULL, 0xa0806020e07d1dc0ULL,
+	0x40f2cbb23932f98bULL, 0xe072ab92d94fe44bULL, 0x15b6f8a34e8971edULL,
+	0xe7275dc07a134ebaULL, 0x490dcc44c1d61a85ULL, 0xf795a66233913751ULL,
+	0x5040301070b08060ULL, 0x5eeac1b42b08c99fULL, 0xae2a9184bbc5543fULL,
+	0x5211c543d4e72297ULL, 0xe576a893de44ec4dULL, 0xed2f5bc274055eb6ULL,
+	0x7f35de4aebb46aa1ULL, 0x73cedabd145b81a9ULL, 0x89068c8f8a800c05ULL,
+	0x99b4772dc30275eeULL, 0x76cad9bc135089afULL, 0xd64ab99cf32d946fULL,
+	0xdfb5be6a0bc97761ULL, 0x5d1dc040ddfa3a9dULL, 0xd41b4ccf577a3698ULL,
+	0x10b2fba2498279ebULL, 0xba3a9d80a7e97427ULL, 0x6e21d14ff09342bfULL,
+	0x637c211f5dd9f842ULL, 0xc50f43ca4c5d1e86ULL, 0x3892e3aa71da39dbULL,
+	0x5715c642d3ec2a91ULL
+};
+
+static const u64 T4[256] = {
+	0xbbb96a01bad3d268ULL, 0xe59a66b154fc4d19ULL, 0xe26514cd2f71bc93ULL,
+	0x25871b51749ccdb9ULL, 0xf7a257a453f55102ULL, 0xd0d6be03d3686bb8ULL,
+	0xd6deb504d26b6fbdULL, 0xb35285fe4dd72964ULL, 0xfdba4aad50f05d0dULL,
+	0xcf09e063ace98a26ULL, 0x091c96848d8a0e83ULL, 0xa5914d1abfdcc679ULL,
+	0x3da7374d7090ddadULL, 0xf1aa5ca352f65507ULL, 0x7ba417e19ab352c8ULL,
+	0xb55a8ef94cd42d61ULL, 0x460320acea238f65ULL, 0xc4e68411d56273a6ULL,
+	0x55cc68c297a466f1ULL, 0xdcc6a80dd16e63b2ULL, 0xaa85d0993355ccffULL,
+	0xfbb241aa51f35908ULL, 0xc7e20f9c5bed712aULL, 0xf359ae55a6f7a204ULL,
+	0xfebec120de7f5f81ULL, 0xad7aa2e548d83d75ULL, 0xd729cc7fa8e59a32ULL,
+	0x71bc0ae899b65ec7ULL, 0xe096e63bdb704b90ULL, 0xac8ddb9e3256c8faULL,
+	0x95d11522b7c4e651ULL, 0x32b3aacefc19d72bULL, 0x704b7393e338ab48ULL,
+	0x63843bfd9ebf42dcULL, 0x41fc52d091ae7eefULL, 0x7dac1ce69bb056cdULL,
+	0x76437894e23baf4dULL, 0xbdb16106bbd0d66dULL, 0x9b32f1da41c31958ULL,
+	0x7957e5176eb2a5cbULL, 0xf941b35ca5f2ae0bULL, 0x8016564bcb400bc0ULL,
+	0x677fc20c6bbdb1daULL, 0x59dc7ecc95a26efbULL, 0xe1619f40a1febe1fULL,
+	0x10cbc3e3f308eb18ULL, 0x81e12f30b1cefe4fULL, 0x0c10160e0206080aULL,
+	0x922e675ecc4917dbULL, 0xa26e3f66c45137f3ULL, 0x4ee8cf531d277469ULL,
+	0x78a09c6c143c5044ULL, 0xb0560e73c3582be8ULL, 0x573f9a3463a591f2ULL,
+	0xe69eed3cda734f95ULL, 0xd3d2358e5de76934ULL, 0xdfc223805fe1613eULL,
+	0xf2aed72edc79578bULL, 0x13cf486e7d87e994ULL, 0x94266c59cd4a13deULL,
+	0x1fdf5e607f81e19eULL, 0xc1ea049b5aee752fULL, 0x7547f3196cb4adc1ULL,
+	0xd5da3e895ce46d31ULL, 0x08ebeffff704fb0cULL, 0xd42d47f2266a98beULL,
+	0x38abb7c7ff1cdb24ULL, 0x543b11b9ed2a937eULL, 0x4a1336a2e825876fULL,
+	0x699c26f49dba4ed3ULL, 0x7f5fee106fb1a1ceULL, 0x03048b8d8e8f028cULL,
+	0x56c8e34f192b647dULL, 0xe7699447a0fdba1aULL, 0x1ad3deeaf00de717ULL,
+	0x113cba9889861e97ULL, 0x2278692d0f113c33ULL, 0x1238311507091c1bULL,
+	0xc511fd6aafec8629ULL, 0x208b9bdbfb10cb30ULL, 0x3040583808182028ULL,
+	0x7ea8976b153f5441ULL, 0x2e687f230d173439ULL, 0x18202c1c040c1014ULL,
+	0x06080b0701030405ULL, 0x4507ab2164ac8de9ULL, 0xf8b6ca27df7c5b84ULL,
+	0x29970d5f769ac5b3ULL, 0x0bef6472798bf980ULL, 0xf4a6dc29dd7a538eULL,
+	0x8ef5b2b33d47f4c9ULL, 0x74b08a62163a584eULL, 0x82e5a4bd3f41fcc3ULL,
+	0xb2a5fc853759dcebULL, 0x734ff81e6db7a9c4ULL, 0x90dd95a83848e0d8ULL,
+	0xb1a17708b9d6de67ULL, 0x37bf2a447395d1a2ULL, 0x4c1b3da5e926836aULL,
+	0xbeb5ea8b355fd4e1ULL, 0xe3926db655ff491cULL, 0x3baf3c4a7193d9a8ULL,
+	0x07ff727c7b8df18aULL, 0x0f149d838c890a86ULL, 0x31b721437296d5a7ULL,
+	0x1734b19f88851a92ULL, 0x0ee3e4f8f607ff09ULL, 0xfc4d33d62a7ea882ULL,
+	0x84edafba3e42f8c6ULL, 0xd9ca28875ee2653bULL, 0xd2254cf527699cbbULL,
+	0x890ac0cf46ca0543ULL, 0x286074240c14303cULL, 0x430fa02665af89ecULL,
+	0x6d67df0568b8bdd5ULL, 0x5b2f8c3a61a399f8ULL, 0x0a181d0903050c0fULL,
+	0xbc46187dc15e23e2ULL, 0xef827bb857f94116ULL, 0xcefe9918d6677fa9ULL,
+	0xec86f035d976439aULL, 0xcdfa129558e87d25ULL, 0xea8efb32d875479fULL,
+	0x4917bd2f66aa85e3ULL, 0xc8f6921fd7647bacULL, 0x9ccd83a63a4ee8d2ULL,
+	0x8a0e4b42c84507cfULL, 0x88fdb9b43c44f0ccULL, 0x268390dcfa13cf35ULL,
+	0x53c463c596a762f4ULL, 0xf551a552a7f4a601ULL, 0x77b401ef98b55ac2ULL,
+	0x52331abeec29977bULL, 0xb7a97c0fb8d5da62ULL, 0xa876226fc7543bfcULL,
+	0xc319f66daeef822cULL, 0x6b6fd40269bbb9d0ULL, 0xa762bfec4bdd317aULL,
+	0xdd31d176abe0963dULL, 0xd121c778a9e69e37ULL, 0x4f1fb62867a981e6ULL,
+	0x3c504e360a1e2822ULL, 0x8f02cbc847c90146ULL, 0x16c3c8e4f20bef1dULL,
+	0x99c1032cb5c2ee5bULL, 0xcc0d6bee226688aaULL, 0x647b4981e532b356ULL,
+	0x5e230cb0ee2f9f71ULL, 0xa399461dbedfc27cULL, 0xfa4538d12b7dac87ULL,
+	0x217ce2a0819e3ebfULL, 0x6c90a67e1236485aULL, 0x2d6cf4ae839836b5ULL,
+	0x5ad8f5411b2d6c77ULL, 0x2470622a0e123836ULL, 0xca0560e923658cafULL,
+	0x04fbf9f1f502f306ULL, 0x8312ddc645cf094cULL, 0xc61576e7216384a5ULL,
+	0x9e3e7150ce4f1fd1ULL, 0xab72a9e249db3970ULL, 0xe87d09c42c74b09cULL,
+	0x2c9b8dd5f916c33aULL, 0x6e635488e637bf59ULL, 0x93d91e25b6c7e254ULL,
+	0xf05d25d82878a088ULL, 0x72b8816517395c4bULL, 0x2b64ffa9829b32b0ULL,
+	0x5cd0fe461a2e6872ULL, 0x1d2cac968b80169dULL, 0x3ea3bcc0fe1fdf21ULL,
+	0x1b24a7918a831298ULL, 0x3648533f091b242dULL, 0x8c064045c94603caULL,
+	0x354cd8b2879426a1ULL, 0xb94a98f74ed2256bULL, 0x7c5b659de13ea342ULL,
+	0xe46d1fca2e72b896ULL, 0x62734286e431b753ULL, 0x7a536e9ae03da747ULL,
+	0x400b2babeb208b60ULL, 0x47f459d790ad7aeaULL, 0xff49b85ba4f1aa0eULL,
+	0x44f0d25a1e227866ULL, 0x395ccebc85922eabULL, 0x5d27873d60a09dfdULL,
+	0x0000000000000000ULL, 0xde355afb256f94b1ULL, 0x02f3f2f6f401f703ULL,
+	0x1cdbd5edf10ee312ULL, 0x5fd475cb94a16afeULL, 0x3a5845310b1d2c27ULL,
+	0x686b5f8fe734bb5cULL, 0x238f1056759fc9bcULL, 0x582b07b7ef2c9b74ULL,
+	0xb8bde18c345cd0e4ULL, 0xa695c6973153c4f5ULL, 0xc2ee8f16d46177a3ULL,
+	0xdacea30ad06d67b7ULL, 0x3344d3b5869722a4ULL, 0x19d755677e82e59bULL,
+	0xc901eb64adea8e23ULL, 0x34bba1c9fd1ad32eULL, 0xf6552edf297ba48dULL,
+	0xa09dcd903050c0f0ULL, 0x9ac588a13b4decd7ULL, 0x658c30fa9fbc46d9ULL,
+	0x2a9386d2f815c73fULL, 0xae7e2968c6573ff9ULL, 0x6a98ad7913354c5fULL,
+	0x14303a12060a181eULL, 0x1e28271b050f1411ULL, 0xa4663461c55233f6ULL,
+	0x6688bb7711334455ULL, 0x2f9f06587799c1b6ULL, 0x15c743697c84ed91ULL,
+	0x01f7797b7a8ef58fULL, 0x0de76f757888fd85ULL, 0xb4adf782365ad8eeULL,
+	0x48e0c4541c24706cULL, 0x96d59eaf394be4ddULL, 0xcbf2199259eb7920ULL,
+	0x50c0e84818286078ULL, 0xe98a70bf56fa4513ULL, 0x8df1393eb3c8f645ULL,
+	0x87e92437b0cdfa4aULL, 0xd83d51fc246c90b4ULL, 0xc01d7de0206080a0ULL,
+	0x8bf93239b2cbf240ULL, 0x4be44fd992ab72e0ULL, 0xed71894ea3f8b615ULL,
+	0xba4e137ac05d27e7ULL, 0x851ad6c144cc0d49ULL, 0x5137913362a695f7ULL,
+	0x6080b07010304050ULL, 0x9fc9082bb4c1ea5eULL, 0x3f54c5bb84912aaeULL,
+	0x9722e7d443c51152ULL, 0x4dec44de93a876e5ULL, 0xb65e0574c25b2fedULL,
+	0xa16ab4eb4ade357fULL, 0xa9815b14bddace73ULL, 0x050c808a8f8c0689ULL,
+	0xee7502c32d77b499ULL, 0xaf895013bcd9ca76ULL, 0x6f942df39cb94ad6ULL,
+	0x6177c90b6abeb5dfULL, 0x9d3afadd40c01d5dULL, 0x98367a57cf4c1bd4ULL,
+	0xeb798249a2fbb210ULL, 0x2774e9a7809d3abaULL, 0xbf4293f04fd1216eULL,
+	0x42f8d95d1f217c63ULL, 0x861e5d4cca430fc5ULL, 0xdb39da71aae39238ULL,
+	0x912aecd342c61557ULL
+};
+
+static const u64 T5[256] = {
+	0xb9bb016ad3ba68d2ULL, 0x9ae5b166fc54194dULL, 0x65e2cd14712f93bcULL,
+	0x8725511b9c74b9cdULL, 0xa2f7a457f5530251ULL, 0xd6d003be68d3b86bULL,
+	0xded604b56bd2bd6fULL, 0x52b3fe85d74d6429ULL, 0xbafdad4af0500d5dULL,
+	0x09cf63e0e9ac268aULL, 0x1c0984968a8d830eULL, 0x91a51a4ddcbf79c6ULL,
+	0xa73d4d379070adddULL, 0xaaf1a35cf6520755ULL, 0xa47be117b39ac852ULL,
+	0x5ab5f98ed44c612dULL, 0x0346ac2023ea658fULL, 0xe6c4118462d5a673ULL,
+	0xcc55c268a497f166ULL, 0xc6dc0da86ed1b263ULL, 0x85aa99d05533ffccULL,
+	0xb2fbaa41f3510859ULL, 0xe2c79c0fed5b2a71ULL, 0x59f355aef7a604a2ULL,
+	0xbefe20c17fde815fULL, 0x7aade5a2d848753dULL, 0x29d77fcce5a8329aULL,
+	0xbc71e80ab699c75eULL, 0x96e03be670db904bULL, 0x8dac9edb5632fac8ULL,
+	0xd1952215c4b751e6ULL, 0xb332ceaa19fc2bd7ULL, 0x4b70937338e348abULL,
+	0x8463fd3bbf9edc42ULL, 0xfc41d052ae91ef7eULL, 0xac7de61cb09bcd56ULL,
+	0x437694783be24dafULL, 0xb1bd0661d0bb6dd6ULL, 0x329bdaf1c3415819ULL,
+	0x577917e5b26ecba5ULL, 0x41f95cb3f2a50baeULL, 0x16804b5640cbc00bULL,
+	0x7f670cc2bd6bdab1ULL, 0xdc59cc7ea295fb6eULL, 0x61e1409ffea11fbeULL,
+	0xcb10e3c308f318ebULL, 0xe181302fceb14ffeULL, 0x100c0e1606020a08ULL,
+	0x2e925e6749ccdb17ULL, 0x6ea2663f51c4f337ULL, 0xe84e53cf271d6974ULL,
+	0xa0786c9c3c144450ULL, 0x56b0730e58c3e82bULL, 0x3f57349aa563f291ULL,
+	0x9ee63ced73da954fULL, 0xd2d38e35e75d3469ULL, 0xc2df8023e15f3e61ULL,
+	0xaef22ed779dc8b57ULL, 0xcf136e48877d94e9ULL, 0x2694596c4acdde13ULL,
+	0xdf1f605e817f9ee1ULL, 0xeac19b04ee5a2f75ULL, 0x477519f3b46cc1adULL,
+	0xdad5893ee45c316dULL, 0xeb08ffef04f70cfbULL, 0x2dd4f2476a26be98ULL,
+	0xab38c7b71cff24dbULL, 0x3b54b9112aed7e93ULL, 0x134aa23625e86f87ULL,
+	0x9c69f426ba9dd34eULL, 0x5f7f10eeb16fcea1ULL, 0x04038d8b8f8e8c02ULL,
+	0xc8564fe32b197d64ULL, 0x69e74794fda01abaULL, 0xd31aeade0df017e7ULL,
+	0x3c1198ba8689971eULL, 0x78222d69110f333cULL, 0x3812153109071b1cULL,
+	0x11c56afdecaf2986ULL, 0x8b20db9b10fb30cbULL, 0x4030385818082820ULL,
+	0xa87e6b973f154154ULL, 0x682e237f170d3934ULL, 0x20181c2c0c041410ULL,
+	0x0806070b03010504ULL, 0x074521abac64e98dULL, 0xb6f827ca7cdf845bULL,
+	0x97295f0d9a76b3c5ULL, 0xef0b72648b7980f9ULL, 0xa6f429dc7add8e53ULL,
+	0xf58eb3b2473dc9f4ULL, 0xb074628a3a164e58ULL, 0xe582bda4413fc3fcULL,
+	0xa5b285fc5937ebdcULL, 0x4f731ef8b76dc4a9ULL, 0xdd90a8954838d8e0ULL,
+	0xa1b10877d6b967deULL, 0xbf37442a9573a2d1ULL, 0x1b4ca53d26e96a83ULL,
+	0xb5be8bea5f35e1d4ULL, 0x92e3b66dff551c49ULL, 0xaf3b4a3c9371a8d9ULL,
+	0xff077c728d7b8af1ULL, 0x140f839d898c860aULL, 0xb73143219672a7d5ULL,
+	0x34179fb18588921aULL, 0xe30ef8e407f609ffULL, 0x4dfcd6337e2a82a8ULL,
+	0xed84baaf423ec6f8ULL, 0xcad98728e25e3b65ULL, 0x25d2f54c6927bb9cULL,
+	0x0a89cfc0ca464305ULL, 0x60282474140c3c30ULL, 0x0f4326a0af65ec89ULL,
+	0x676d05dfb868d5bdULL, 0x2f5b3a8ca361f899ULL, 0x180a091d05030f0cULL,
+	0x46bc7d185ec1e223ULL, 0x82efb87bf9571641ULL, 0xfece189967d6a97fULL,
+	0x86ec35f076d99a43ULL, 0xfacd9512e858257dULL, 0x8eea32fb75d89f47ULL,
+	0x17492fbdaa66e385ULL, 0xf6c81f9264d7ac7bULL, 0xcd9ca6834e3ad2e8ULL,
+	0x0e8a424b45c8cf07ULL, 0xfd88b4b9443cccf0ULL, 0x8326dc9013fa35cfULL,
+	0xc453c563a796f462ULL, 0x51f552a5f4a701a6ULL, 0xb477ef01b598c25aULL,
+	0x3352be1a29ec7b97ULL, 0xa9b70f7cd5b862daULL, 0x76a86f2254c7fc3bULL,
+	0x19c36df6efae2c82ULL, 0x6f6b02d4bb69d0b9ULL, 0x62a7ecbfdd4b7a31ULL,
+	0x31dd76d1e0ab3d96ULL, 0x21d178c7e6a9379eULL, 0x1f4f28b6a967e681ULL,
+	0x503c364e1e0a2228ULL, 0x028fc8cbc9474601ULL, 0xc316e4c80bf21defULL,
+	0xc1992c03c2b55beeULL, 0x0dccee6b6622aa88ULL, 0x7b64814932e556b3ULL,
+	0x235eb00c2fee719fULL, 0x99a31d46dfbe7cc2ULL, 0x45fad1387d2b87acULL,
+	0x7c21a0e29e81bf3eULL, 0x906c7ea636125a48ULL, 0x6c2daef49883b536ULL,
+	0xd85a41f52d1b776cULL, 0x70242a62120e3638ULL, 0x05cae9606523af8cULL,
+	0xfb04f1f902f506f3ULL, 0x1283c6ddcf454c09ULL, 0x15c6e7766321a584ULL,
+	0x3e9e50714fced11fULL, 0x72abe2a9db497039ULL, 0x7de8c409742c9cb0ULL,
+	0x9b2cd58d16f93ac3ULL, 0x636e885437e659bfULL, 0xd993251ec7b654e2ULL,
+	0x5df0d825782888a0ULL, 0xb872658139174b5cULL, 0x642ba9ff9b82b032ULL,
+	0xd05c46fe2e1a7268ULL, 0x2c1d96ac808b9d16ULL, 0xa33ec0bc1ffe21dfULL,
+	0x241b91a7838a9812ULL, 0x48363f531b092d24ULL, 0x068c454046c9ca03ULL,
+	0x4c35b2d89487a126ULL, 0x4ab9f798d24e6b25ULL, 0x5b7c9d653ee142a3ULL,
+	0x6de4ca1f722e96b8ULL, 0x7362864231e453b7ULL, 0x537a9a6e3de047a7ULL,
+	0x0b40ab2b20eb608bULL, 0xf447d759ad90ea7aULL, 0x49ff5bb8f1a40eaaULL,
+	0xf0445ad2221e6678ULL, 0x5c39bcce9285ab2eULL, 0x275d3d87a060fd9dULL,
+	0x0000000000000000ULL, 0x35defb5a6f25b194ULL, 0xf302f6f201f403f7ULL,
+	0xdb1cedd50ef112e3ULL, 0xd45fcb75a194fe6aULL, 0x583a31451d0b272cULL,
+	0x6b688f5f34e75cbbULL, 0x8f2356109f75bcc9ULL, 0x2b58b7072cef749bULL,
+	0xbdb88ce15c34e4d0ULL, 0x95a697c65331f5c4ULL, 0xeec2168f61d4a377ULL,
+	0xceda0aa36dd0b767ULL, 0x4433b5d39786a422ULL, 0xd7196755827e9be5ULL,
+	0x01c964ebeaad238eULL, 0xbb34c9a11afd2ed3ULL, 0x55f6df2e7b298da4ULL,
+	0x9da090cd5030f0c0ULL, 0xc59aa1884d3bd7ecULL, 0x8c65fa30bc9fd946ULL,
+	0x932ad28615f83fc7ULL, 0x7eae682957c6f93fULL, 0x986a79ad35135f4cULL,
+	0x3014123a0a061e18ULL, 0x281e1b270f051114ULL, 0x66a4613452c5f633ULL,
+	0x886677bb33115544ULL, 0x9f2f58069977b6c1ULL, 0xc7156943847c91edULL,
+	0xf7017b798e7a8ff5ULL, 0xe70d756f887885fdULL, 0xadb482f75a36eed8ULL,
+	0xe04854c4241c6c70ULL, 0xd596af9e4b39dde4ULL, 0xf2cb9219eb592079ULL,
+	0xc05048e828187860ULL, 0x8ae9bf70fa561345ULL, 0xf18d3e39c8b345f6ULL,
+	0xe9873724cdb04afaULL, 0x3dd8fc516c24b490ULL, 0x1dc0e07d6020a080ULL,
+	0xf98b3932cbb240f2ULL, 0xe44bd94fab92e072ULL, 0x71ed4e89f8a315b6ULL,
+	0x4eba7a135dc0e727ULL, 0x1a85c1d6cc44490dULL, 0x37513391a662f795ULL,
+	0x806070b030105040ULL, 0xc99f2b08c1b45eeaULL, 0x543fbbc59184ae2aULL,
+	0x2297d4e7c5435211ULL, 0xec4dde44a893e576ULL, 0x5eb674055bc2ed2fULL,
+	0x6aa1ebb4de4a7f35ULL, 0x81a9145bdabd73ceULL, 0x0c058a808c8f8906ULL,
+	0x75eec302772d99b4ULL, 0x89af1350d9bc76caULL, 0x946ff32db99cd64aULL,
+	0x77610bc9be6adfb5ULL, 0x3a9dddfac0405d1dULL, 0x3698577a4ccfd41bULL,
+	0x79eb4982fba210b2ULL, 0x7427a7e99d80ba3aULL, 0x42bff093d14f6e21ULL,
+	0xf8425dd9211f637cULL, 0x1e864c5d43cac50fULL, 0x39db71dae3aa3892ULL,
+	0x2a91d3ecc6425715ULL
+};
+
+static const u64 T6[256] = {
+	0x6a01bbb9d268bad3ULL, 0x66b1e59a4d1954fcULL, 0x14cde265bc932f71ULL,
+	0x1b512587cdb9749cULL, 0x57a4f7a2510253f5ULL, 0xbe03d0d66bb8d368ULL,
+	0xb504d6de6fbdd26bULL, 0x85feb35229644dd7ULL, 0x4aadfdba5d0d50f0ULL,
+	0xe063cf098a26ace9ULL, 0x9684091c0e838d8aULL, 0x4d1aa591c679bfdcULL,
+	0x374d3da7ddad7090ULL, 0x5ca3f1aa550752f6ULL, 0x17e17ba452c89ab3ULL,
+	0x8ef9b55a2d614cd4ULL, 0x20ac46038f65ea23ULL, 0x8411c4e673a6d562ULL,
+	0x68c255cc66f197a4ULL, 0xa80ddcc663b2d16eULL, 0xd099aa85ccff3355ULL,
+	0x41aafbb2590851f3ULL, 0x0f9cc7e2712a5bedULL, 0xae55f359a204a6f7ULL,
+	0xc120febe5f81de7fULL, 0xa2e5ad7a3d7548d8ULL, 0xcc7fd7299a32a8e5ULL,
+	0x0ae871bc5ec799b6ULL, 0xe63be0964b90db70ULL, 0xdb9eac8dc8fa3256ULL,
+	0x152295d1e651b7c4ULL, 0xaace32b3d72bfc19ULL, 0x7393704bab48e338ULL,
+	0x3bfd638442dc9ebfULL, 0x52d041fc7eef91aeULL, 0x1ce67dac56cd9bb0ULL,
+	0x78947643af4de23bULL, 0x6106bdb1d66dbbd0ULL, 0xf1da9b32195841c3ULL,
+	0xe5177957a5cb6eb2ULL, 0xb35cf941ae0ba5f2ULL, 0x564b80160bc0cb40ULL,
+	0xc20c677fb1da6bbdULL, 0x7ecc59dc6efb95a2ULL, 0x9f40e161be1fa1feULL,
+	0xc3e310cbeb18f308ULL, 0x2f3081e1fe4fb1ceULL, 0x160e0c10080a0206ULL,
+	0x675e922e17dbcc49ULL, 0x3f66a26e37f3c451ULL, 0xcf534ee874691d27ULL,
+	0x9c6c78a05044143cULL, 0x0e73b0562be8c358ULL, 0x9a34573f91f263a5ULL,
+	0xed3ce69e4f95da73ULL, 0x358ed3d269345de7ULL, 0x2380dfc2613e5fe1ULL,
+	0xd72ef2ae578bdc79ULL, 0x486e13cfe9947d87ULL, 0x6c59942613decd4aULL,
+	0x5e601fdfe19e7f81ULL, 0x049bc1ea752f5aeeULL, 0xf3197547adc16cb4ULL,
+	0x3e89d5da6d315ce4ULL, 0xefff08ebfb0cf704ULL, 0x47f2d42d98be266aULL,
+	0xb7c738abdb24ff1cULL, 0x11b9543b937eed2aULL, 0x36a24a13876fe825ULL,
+	0x26f4699c4ed39dbaULL, 0xee107f5fa1ce6fb1ULL, 0x8b8d0304028c8e8fULL,
+	0xe34f56c8647d192bULL, 0x9447e769ba1aa0fdULL, 0xdeea1ad3e717f00dULL,
+	0xba98113c1e978986ULL, 0x692d22783c330f11ULL, 0x311512381c1b0709ULL,
+	0xfd6ac5118629afecULL, 0x9bdb208bcb30fb10ULL, 0x5838304020280818ULL,
+	0x976b7ea85441153fULL, 0x7f232e6834390d17ULL, 0x2c1c18201014040cULL,
+	0x0b07060804050103ULL, 0xab2145078de964acULL, 0xca27f8b65b84df7cULL,
+	0x0d5f2997c5b3769aULL, 0x64720beff980798bULL, 0xdc29f4a6538edd7aULL,
+	0xb2b38ef5f4c93d47ULL, 0x8a6274b0584e163aULL, 0xa4bd82e5fcc33f41ULL,
+	0xfc85b2a5dceb3759ULL, 0xf81e734fa9c46db7ULL, 0x95a890dde0d83848ULL,
+	0x7708b1a1de67b9d6ULL, 0x2a4437bfd1a27395ULL, 0x3da54c1b836ae926ULL,
+	0xea8bbeb5d4e1355fULL, 0x6db6e392491c55ffULL, 0x3c4a3bafd9a87193ULL,
+	0x727c07fff18a7b8dULL, 0x9d830f140a868c89ULL, 0x214331b7d5a77296ULL,
+	0xb19f17341a928885ULL, 0xe4f80ee3ff09f607ULL, 0x33d6fc4da8822a7eULL,
+	0xafba84edf8c63e42ULL, 0x2887d9ca653b5ee2ULL, 0x4cf5d2259cbb2769ULL,
+	0xc0cf890a054346caULL, 0x74242860303c0c14ULL, 0xa026430f89ec65afULL,
+	0xdf056d67bdd568b8ULL, 0x8c3a5b2f99f861a3ULL, 0x1d090a180c0f0305ULL,
+	0x187dbc4623e2c15eULL, 0x7bb8ef82411657f9ULL, 0x9918cefe7fa9d667ULL,
+	0xf035ec86439ad976ULL, 0x1295cdfa7d2558e8ULL, 0xfb32ea8e479fd875ULL,
+	0xbd2f491785e366aaULL, 0x921fc8f67bacd764ULL, 0x83a69ccde8d23a4eULL,
+	0x4b428a0e07cfc845ULL, 0xb9b488fdf0cc3c44ULL, 0x90dc2683cf35fa13ULL,
+	0x63c553c462f496a7ULL, 0xa552f551a601a7f4ULL, 0x01ef77b45ac298b5ULL,
+	0x1abe5233977bec29ULL, 0x7c0fb7a9da62b8d5ULL, 0x226fa8763bfcc754ULL,
+	0xf66dc319822caeefULL, 0xd4026b6fb9d069bbULL, 0xbfeca762317a4bddULL,
+	0xd176dd31963dabe0ULL, 0xc778d1219e37a9e6ULL, 0xb6284f1f81e667a9ULL,
+	0x4e363c5028220a1eULL, 0xcbc88f02014647c9ULL, 0xc8e416c3ef1df20bULL,
+	0x032c99c1ee5bb5c2ULL, 0x6beecc0d88aa2266ULL, 0x4981647bb356e532ULL,
+	0x0cb05e239f71ee2fULL, 0x461da399c27cbedfULL, 0x38d1fa45ac872b7dULL,
+	0xe2a0217c3ebf819eULL, 0xa67e6c90485a1236ULL, 0xf4ae2d6c36b58398ULL,
+	0xf5415ad86c771b2dULL, 0x622a247038360e12ULL, 0x60e9ca058caf2365ULL,
+	0xf9f104fbf306f502ULL, 0xddc68312094c45cfULL, 0x76e7c61584a52163ULL,
+	0x71509e3e1fd1ce4fULL, 0xa9e2ab72397049dbULL, 0x09c4e87db09c2c74ULL,
+	0x8dd52c9bc33af916ULL, 0x54886e63bf59e637ULL, 0x1e2593d9e254b6c7ULL,
+	0x25d8f05da0882878ULL, 0x816572b85c4b1739ULL, 0xffa92b6432b0829bULL,
+	0xfe465cd068721a2eULL, 0xac961d2c169d8b80ULL, 0xbcc03ea3df21fe1fULL,
+	0xa7911b2412988a83ULL, 0x533f3648242d091bULL, 0x40458c0603cac946ULL,
+	0xd8b2354c26a18794ULL, 0x98f7b94a256b4ed2ULL, 0x659d7c5ba342e13eULL,
+	0x1fcae46db8962e72ULL, 0x42866273b753e431ULL, 0x6e9a7a53a747e03dULL,
+	0x2bab400b8b60eb20ULL, 0x59d747f47aea90adULL, 0xb85bff49aa0ea4f1ULL,
+	0xd25a44f078661e22ULL, 0xcebc395c2eab8592ULL, 0x873d5d279dfd60a0ULL,
+	0x0000000000000000ULL, 0x5afbde3594b1256fULL, 0xf2f602f3f703f401ULL,
+	0xd5ed1cdbe312f10eULL, 0x75cb5fd46afe94a1ULL, 0x45313a582c270b1dULL,
+	0x5f8f686bbb5ce734ULL, 0x1056238fc9bc759fULL, 0x07b7582b9b74ef2cULL,
+	0xe18cb8bdd0e4345cULL, 0xc697a695c4f53153ULL, 0x8f16c2ee77a3d461ULL,
+	0xa30adace67b7d06dULL, 0xd3b5334422a48697ULL, 0x556719d7e59b7e82ULL,
+	0xeb64c9018e23adeaULL, 0xa1c934bbd32efd1aULL, 0x2edff655a48d297bULL,
+	0xcd90a09dc0f03050ULL, 0x88a19ac5ecd73b4dULL, 0x30fa658c46d99fbcULL,
+	0x86d22a93c73ff815ULL, 0x2968ae7e3ff9c657ULL, 0xad796a984c5f1335ULL,
+	0x3a121430181e060aULL, 0x271b1e281411050fULL, 0x3461a46633f6c552ULL,
+	0xbb77668844551133ULL, 0x06582f9fc1b67799ULL, 0x436915c7ed917c84ULL,
+	0x797b01f7f58f7a8eULL, 0x6f750de7fd857888ULL, 0xf782b4add8ee365aULL,
+	0xc45448e0706c1c24ULL, 0x9eaf96d5e4dd394bULL, 0x1992cbf2792059ebULL,
+	0xe84850c060781828ULL, 0x70bfe98a451356faULL, 0x393e8df1f645b3c8ULL,
+	0x243787e9fa4ab0cdULL, 0x51fcd83d90b4246cULL, 0x7de0c01d80a02060ULL,
+	0x32398bf9f240b2cbULL, 0x4fd94be472e092abULL, 0x894eed71b615a3f8ULL,
+	0x137aba4e27e7c05dULL, 0xd6c1851a0d4944ccULL, 0x9133513795f762a6ULL,
+	0xb070608040501030ULL, 0x082b9fc9ea5eb4c1ULL, 0xc5bb3f542aae8491ULL,
+	0xe7d49722115243c5ULL, 0x44de4dec76e593a8ULL, 0x0574b65e2fedc25bULL,
+	0xb4eba16a357f4adeULL, 0x5b14a981ce73bddaULL, 0x808a050c06898f8cULL,
+	0x02c3ee75b4992d77ULL, 0x5013af89ca76bcd9ULL, 0x2df36f944ad69cb9ULL,
+	0xc90b6177b5df6abeULL, 0xfadd9d3a1d5d40c0ULL, 0x7a5798361bd4cf4cULL,
+	0x8249eb79b210a2fbULL, 0xe9a727743aba809dULL, 0x93f0bf42216e4fd1ULL,
+	0xd95d42f87c631f21ULL, 0x5d4c861e0fc5ca43ULL, 0xda71db399238aae3ULL,
+	0xecd3912a155742c6ULL
+};
+
+static const u64 T7[256] = {
+	0x016ab9bb68d2d3baULL, 0xb1669ae5194dfc54ULL, 0xcd1465e293bc712fULL,
+	0x511b8725b9cd9c74ULL, 0xa457a2f70251f553ULL, 0x03bed6d0b86b68d3ULL,
+	0x04b5ded6bd6f6bd2ULL, 0xfe8552b36429d74dULL, 0xad4abafd0d5df050ULL,
+	0x63e009cf268ae9acULL, 0x84961c09830e8a8dULL, 0x1a4d91a579c6dcbfULL,
+	0x4d37a73daddd9070ULL, 0xa35caaf10755f652ULL, 0xe117a47bc852b39aULL,
+	0xf98e5ab5612dd44cULL, 0xac200346658f23eaULL, 0x1184e6c4a67362d5ULL,
+	0xc268cc55f166a497ULL, 0x0da8c6dcb2636ed1ULL, 0x99d085aaffcc5533ULL,
+	0xaa41b2fb0859f351ULL, 0x9c0fe2c72a71ed5bULL, 0x55ae59f304a2f7a6ULL,
+	0x20c1befe815f7fdeULL, 0xe5a27aad753dd848ULL, 0x7fcc29d7329ae5a8ULL,
+	0xe80abc71c75eb699ULL, 0x3be696e0904b70dbULL, 0x9edb8dacfac85632ULL,
+	0x2215d19551e6c4b7ULL, 0xceaab3322bd719fcULL, 0x93734b7048ab38e3ULL,
+	0xfd3b8463dc42bf9eULL, 0xd052fc41ef7eae91ULL, 0xe61cac7dcd56b09bULL,
+	0x947843764daf3be2ULL, 0x0661b1bd6dd6d0bbULL, 0xdaf1329b5819c341ULL,
+	0x17e55779cba5b26eULL, 0x5cb341f90baef2a5ULL, 0x4b561680c00b40cbULL,
+	0x0cc27f67dab1bd6bULL, 0xcc7edc59fb6ea295ULL, 0x409f61e11fbefea1ULL,
+	0xe3c3cb1018eb08f3ULL, 0x302fe1814ffeceb1ULL, 0x0e16100c0a080602ULL,
+	0x5e672e92db1749ccULL, 0x663f6ea2f33751c4ULL, 0x53cfe84e6974271dULL,
+	0x6c9ca07844503c14ULL, 0x730e56b0e82b58c3ULL, 0x349a3f57f291a563ULL,
+	0x3ced9ee6954f73daULL, 0x8e35d2d33469e75dULL, 0x8023c2df3e61e15fULL,
+	0x2ed7aef28b5779dcULL, 0x6e48cf1394e9877dULL, 0x596c2694de134acdULL,
+	0x605edf1f9ee1817fULL, 0x9b04eac12f75ee5aULL, 0x19f34775c1adb46cULL,
+	0x893edad5316de45cULL, 0xffefeb080cfb04f7ULL, 0xf2472dd4be986a26ULL,
+	0xc7b7ab3824db1cffULL, 0xb9113b547e932aedULL, 0xa236134a6f8725e8ULL,
+	0xf4269c69d34eba9dULL, 0x10ee5f7fcea1b16fULL, 0x8d8b04038c028f8eULL,
+	0x4fe3c8567d642b19ULL, 0x479469e71abafda0ULL, 0xeaded31a17e70df0ULL,
+	0x98ba3c11971e8689ULL, 0x2d697822333c110fULL, 0x153138121b1c0907ULL,
+	0x6afd11c52986ecafULL, 0xdb9b8b2030cb10fbULL, 0x3858403028201808ULL,
+	0x6b97a87e41543f15ULL, 0x237f682e3934170dULL, 0x1c2c201814100c04ULL,
+	0x070b080605040301ULL, 0x21ab0745e98dac64ULL, 0x27cab6f8845b7cdfULL,
+	0x5f0d9729b3c59a76ULL, 0x7264ef0b80f98b79ULL, 0x29dca6f48e537addULL,
+	0xb3b2f58ec9f4473dULL, 0x628ab0744e583a16ULL, 0xbda4e582c3fc413fULL,
+	0x85fca5b2ebdc5937ULL, 0x1ef84f73c4a9b76dULL, 0xa895dd90d8e04838ULL,
+	0x0877a1b167ded6b9ULL, 0x442abf37a2d19573ULL, 0xa53d1b4c6a8326e9ULL,
+	0x8beab5bee1d45f35ULL, 0xb66d92e31c49ff55ULL, 0x4a3caf3ba8d99371ULL,
+	0x7c72ff078af18d7bULL, 0x839d140f860a898cULL, 0x4321b731a7d59672ULL,
+	0x9fb13417921a8588ULL, 0xf8e4e30e09ff07f6ULL, 0xd6334dfc82a87e2aULL,
+	0xbaafed84c6f8423eULL, 0x8728cad93b65e25eULL, 0xf54c25d2bb9c6927ULL,
+	0xcfc00a894305ca46ULL, 0x247460283c30140cULL, 0x26a00f43ec89af65ULL,
+	0x05df676dd5bdb868ULL, 0x3a8c2f5bf899a361ULL, 0x091d180a0f0c0503ULL,
+	0x7d1846bce2235ec1ULL, 0xb87b82ef1641f957ULL, 0x1899fecea97f67d6ULL,
+	0x35f086ec9a4376d9ULL, 0x9512facd257de858ULL, 0x32fb8eea9f4775d8ULL,
+	0x2fbd1749e385aa66ULL, 0x1f92f6c8ac7b64d7ULL, 0xa683cd9cd2e84e3aULL,
+	0x424b0e8acf0745c8ULL, 0xb4b9fd88ccf0443cULL, 0xdc90832635cf13faULL,
+	0xc563c453f462a796ULL, 0x52a551f501a6f4a7ULL, 0xef01b477c25ab598ULL,
+	0xbe1a33527b9729ecULL, 0x0f7ca9b762dad5b8ULL, 0x6f2276a8fc3b54c7ULL,
+	0x6df619c32c82efaeULL, 0x02d46f6bd0b9bb69ULL, 0xecbf62a77a31dd4bULL,
+	0x76d131dd3d96e0abULL, 0x78c721d1379ee6a9ULL, 0x28b61f4fe681a967ULL,
+	0x364e503c22281e0aULL, 0xc8cb028f4601c947ULL, 0xe4c8c3161def0bf2ULL,
+	0x2c03c1995beec2b5ULL, 0xee6b0dccaa886622ULL, 0x81497b6456b332e5ULL,
+	0xb00c235e719f2feeULL, 0x1d4699a37cc2dfbeULL, 0xd13845fa87ac7d2bULL,
+	0xa0e27c21bf3e9e81ULL, 0x7ea6906c5a483612ULL, 0xaef46c2db5369883ULL,
+	0x41f5d85a776c2d1bULL, 0x2a6270243638120eULL, 0xe96005caaf8c6523ULL,
+	0xf1f9fb0406f302f5ULL, 0xc6dd12834c09cf45ULL, 0xe77615c6a5846321ULL,
+	0x50713e9ed11f4fceULL, 0xe2a972ab7039db49ULL, 0xc4097de89cb0742cULL,
+	0xd58d9b2c3ac316f9ULL, 0x8854636e59bf37e6ULL, 0x251ed99354e2c7b6ULL,
+	0xd8255df088a07828ULL, 0x6581b8724b5c3917ULL, 0xa9ff642bb0329b82ULL,
+	0x46fed05c72682e1aULL, 0x96ac2c1d9d16808bULL, 0xc0bca33e21df1ffeULL,
+	0x91a7241b9812838aULL, 0x3f5348362d241b09ULL, 0x4540068cca0346c9ULL,
+	0xb2d84c35a1269487ULL, 0xf7984ab96b25d24eULL, 0x9d655b7c42a33ee1ULL,
+	0xca1f6de496b8722eULL, 0x8642736253b731e4ULL, 0x9a6e537a47a73de0ULL,
+	0xab2b0b40608b20ebULL, 0xd759f447ea7aad90ULL, 0x5bb849ff0eaaf1a4ULL,
+	0x5ad2f0446678221eULL, 0xbcce5c39ab2e9285ULL, 0x3d87275dfd9da060ULL,
+	0x0000000000000000ULL, 0xfb5a35deb1946f25ULL, 0xf6f2f30203f701f4ULL,
+	0xedd5db1c12e30ef1ULL, 0xcb75d45ffe6aa194ULL, 0x3145583a272c1d0bULL,
+	0x8f5f6b685cbb34e7ULL, 0x56108f23bcc99f75ULL, 0xb7072b58749b2cefULL,
+	0x8ce1bdb8e4d05c34ULL, 0x97c695a6f5c45331ULL, 0x168feec2a37761d4ULL,
+	0x0aa3cedab7676dd0ULL, 0xb5d34433a4229786ULL, 0x6755d7199be5827eULL,
+	0x64eb01c9238eeaadULL, 0xc9a1bb342ed31afdULL, 0xdf2e55f68da47b29ULL,
+	0x90cd9da0f0c05030ULL, 0xa188c59ad7ec4d3bULL, 0xfa308c65d946bc9fULL,
+	0xd286932a3fc715f8ULL, 0x68297eaef93f57c6ULL, 0x79ad986a5f4c3513ULL,
+	0x123a30141e180a06ULL, 0x1b27281e11140f05ULL, 0x613466a4f63352c5ULL,
+	0x77bb886655443311ULL, 0x58069f2fb6c19977ULL, 0x6943c71591ed847cULL,
+	0x7b79f7018ff58e7aULL, 0x756fe70d85fd8878ULL, 0x82f7adb4eed85a36ULL,
+	0x54c4e0486c70241cULL, 0xaf9ed596dde44b39ULL, 0x9219f2cb2079eb59ULL,
+	0x48e8c05078602818ULL, 0xbf708ae91345fa56ULL, 0x3e39f18d45f6c8b3ULL,
+	0x3724e9874afacdb0ULL, 0xfc513dd8b4906c24ULL, 0xe07d1dc0a0806020ULL,
+	0x3932f98b40f2cbb2ULL, 0xd94fe44be072ab92ULL, 0x4e8971ed15b6f8a3ULL,
+	0x7a134ebae7275dc0ULL, 0xc1d61a85490dcc44ULL, 0x33913751f795a662ULL,
+	0x70b0806050403010ULL, 0x2b08c99f5eeac1b4ULL, 0xbbc5543fae2a9184ULL,
+	0xd4e722975211c543ULL, 0xde44ec4de576a893ULL, 0x74055eb6ed2f5bc2ULL,
+	0xebb46aa17f35de4aULL, 0x145b81a973cedabdULL, 0x8a800c0589068c8fULL,
+	0xc30275ee99b4772dULL, 0x135089af76cad9bcULL, 0xf32d946fd64ab99cULL,
+	0x0bc97761dfb5be6aULL, 0xddfa3a9d5d1dc040ULL, 0x577a3698d41b4ccfULL,
+	0x498279eb10b2fba2ULL, 0xa7e97427ba3a9d80ULL, 0xf09342bf6e21d14fULL,
+	0x5dd9f842637c211fULL, 0x4c5d1e86c50f43caULL, 0x71da39db3892e3aaULL,
+	0xd3ec2a915715c642ULL
+};
+
+static const u64 c[KHAZAD_ROUNDS + 1] = {
+	0xba542f7453d3d24dULL, 0x50ac8dbf70529a4cULL, 0xead597d133515ba6ULL,
+	0xde48a899db32b7fcULL, 0xe39e919be2bb416eULL, 0xa5cb6b95a1f3b102ULL,
+	0xccc41d14c363da5dULL, 0x5fdc7dcd7f5a6c5cULL, 0xf726ffede89d6f8eULL
+};
+
+static int khazad_setkey(void *ctx_arg, const u8 *in_key,
+                       unsigned int key_len, u32 *flags)
+{
+
+	struct khazad_ctx *ctx = ctx_arg;
+	int r;
+	const u64 *S = T7;
+	u64 K2, K1;
+	
+	if (key_len != 16)
+	{
+		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	K2 = ((u64)in_key[ 0] << 56) ^
+	     ((u64)in_key[ 1] << 48) ^
+	     ((u64)in_key[ 2] << 40) ^
+	     ((u64)in_key[ 3] << 32) ^
+	     ((u64)in_key[ 4] << 24) ^
+	     ((u64)in_key[ 5] << 16) ^
+	     ((u64)in_key[ 6] <<  8) ^
+	     ((u64)in_key[ 7]      );
+	K1 = ((u64)in_key[ 8] << 56) ^
+	     ((u64)in_key[ 9] << 48) ^
+	     ((u64)in_key[10] << 40) ^
+	     ((u64)in_key[11] << 32) ^
+	     ((u64)in_key[12] << 24) ^
+	     ((u64)in_key[13] << 16) ^
+	     ((u64)in_key[14] <<  8) ^
+	     ((u64)in_key[15]      );
+
+	/* setup the encrypt key */
+	for (r = 0; r <= KHAZAD_ROUNDS; r++) {
+		ctx->E[r] = T0[(int)(K1 >> 56)       ] ^
+			    T1[(int)(K1 >> 48) & 0xff] ^
+			    T2[(int)(K1 >> 40) & 0xff] ^
+			    T3[(int)(K1 >> 32) & 0xff] ^
+			    T4[(int)(K1 >> 24) & 0xff] ^
+			    T5[(int)(K1 >> 16) & 0xff] ^
+			    T6[(int)(K1 >>  8) & 0xff] ^
+			    T7[(int)(K1      ) & 0xff] ^
+			    c[r] ^ K2;
+		K2 = K1; 
+		K1 = ctx->E[r];
+	}
+	/* Setup the decrypt key */
+	ctx->D[0] = ctx->E[KHAZAD_ROUNDS];
+	for (r = 1; r < KHAZAD_ROUNDS; r++) {
+		K1 = ctx->E[KHAZAD_ROUNDS - r];
+		ctx->D[r] = T0[(int)S[(int)(K1 >> 56)       ] & 0xff] ^
+			    T1[(int)S[(int)(K1 >> 48) & 0xff] & 0xff] ^
+			    T2[(int)S[(int)(K1 >> 40) & 0xff] & 0xff] ^
+			    T3[(int)S[(int)(K1 >> 32) & 0xff] & 0xff] ^
+			    T4[(int)S[(int)(K1 >> 24) & 0xff] & 0xff] ^
+			    T5[(int)S[(int)(K1 >> 16) & 0xff] & 0xff] ^
+			    T6[(int)S[(int)(K1 >>  8) & 0xff] & 0xff] ^
+			    T7[(int)S[(int)(K1      ) & 0xff] & 0xff];
+	}
+	ctx->D[KHAZAD_ROUNDS] = ctx->E[0];
+
+	return 0;
+
+}
+
+static void khazad_crypt(const u64 roundKey[KHAZAD_ROUNDS + 1],
+		u8 *ciphertext, const u8 *plaintext)
+{
+
+	int r;
+	u64 state;
+
+	state = ((u64)plaintext[0] << 56) ^
+		((u64)plaintext[1] << 48) ^
+		((u64)plaintext[2] << 40) ^
+		((u64)plaintext[3] << 32) ^
+		((u64)plaintext[4] << 24) ^
+		((u64)plaintext[5] << 16) ^
+		((u64)plaintext[6] <<  8) ^
+		((u64)plaintext[7]      ) ^
+		roundKey[0];
+
+	for (r = 1; r < KHAZAD_ROUNDS; r++) {
+		state = T0[(int)(state >> 56)       ] ^
+			T1[(int)(state >> 48) & 0xff] ^
+			T2[(int)(state >> 40) & 0xff] ^
+			T3[(int)(state >> 32) & 0xff] ^
+			T4[(int)(state >> 24) & 0xff] ^
+			T5[(int)(state >> 16) & 0xff] ^
+			T6[(int)(state >>  8) & 0xff] ^
+			T7[(int)(state      ) & 0xff] ^
+			roundKey[r];
+    	}
+
+	state = (T0[(int)(state >> 56)       ] & 0xff00000000000000ULL) ^
+		(T1[(int)(state >> 48) & 0xff] & 0x00ff000000000000ULL) ^
+		(T2[(int)(state >> 40) & 0xff] & 0x0000ff0000000000ULL) ^
+		(T3[(int)(state >> 32) & 0xff] & 0x000000ff00000000ULL) ^
+		(T4[(int)(state >> 24) & 0xff] & 0x00000000ff000000ULL) ^
+		(T5[(int)(state >> 16) & 0xff] & 0x0000000000ff0000ULL) ^
+		(T6[(int)(state >>  8) & 0xff] & 0x000000000000ff00ULL) ^
+		(T7[(int)(state      ) & 0xff] & 0x00000000000000ffULL) ^
+		roundKey[KHAZAD_ROUNDS];
+
+	ciphertext[0] = (u8)(state >> 56);
+	ciphertext[1] = (u8)(state >> 48);
+	ciphertext[2] = (u8)(state >> 40);
+	ciphertext[3] = (u8)(state >> 32);
+	ciphertext[4] = (u8)(state >> 24);
+	ciphertext[5] = (u8)(state >> 16);
+	ciphertext[6] = (u8)(state >>  8);
+	ciphertext[7] = (u8)(state      );
+
+}
+
+static void khazad_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+	struct khazad_ctx *ctx = ctx_arg;
+	khazad_crypt(ctx->E, dst, src);
+}
+
+static void khazad_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+	struct khazad_ctx *ctx = ctx_arg;
+	khazad_crypt(ctx->D, dst, src);
+}
+
+static struct crypto_alg khazad_alg = {
+	.cra_name		=	"khazad",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	KHAZAD_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof (struct khazad_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(khazad_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	KHAZAD_KEY_SIZE,
+	.cia_max_keysize	=	KHAZAD_KEY_SIZE,
+	.cia_setkey		= 	khazad_setkey,
+	.cia_encrypt		=	khazad_encrypt,
+	.cia_decrypt		=	khazad_decrypt } }
+};
+
+static int __init init(void)
+{
+	int ret = 0;
+	
+	ret = crypto_register_alg(&khazad_alg);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&khazad_alg);
+}
+
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Khazad Cryptographic Algorithm");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/scatterwalk.c linux-2.4.28-pre1/crypto/scatterwalk.c
--- linux-2.4.27/crypto/scatterwalk.c	2004-04-14 13:05:28.000000000 +0000
+++ linux-2.4.28-pre1/crypto/scatterwalk.c	2004-08-15 19:47:21.000000000 +0000
@@ -70,7 +70,7 @@ static void scatterwalk_pagedone(struct 
 {
 	/* walk->data may be pointing the first byte of the next page;
 	   however, we know we transfered at least one byte.  So,
-	   walk->data - 1 will be a virutual address in the mapped page. */
+	   walk->data - 1 will be a virtual address in the mapped page. */
 
 	if (out)
 		flush_dcache_page(walk->page);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/tcrypt.c linux-2.4.28-pre1/crypto/tcrypt.c
--- linux-2.4.27/crypto/tcrypt.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/crypto/tcrypt.c	2004-08-15 19:50:39.000000000 +0000
@@ -575,6 +575,10 @@ do_test(void)
 		test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS);
 		test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS);
 
+		//KHAZAD
+		test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS);
+		test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS);
+
 		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
 		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
 		test_deflate();		
@@ -678,6 +682,11 @@ do_test(void)
 		test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS);
 		break;
 
+	case 21:
+		test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS);
+		test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS);
+		break;
+
 #ifdef CONFIG_CRYPTO_HMAC
 	case 100:
 		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/tcrypt.h linux-2.4.28-pre1/crypto/tcrypt.h
--- linux-2.4.27/crypto/tcrypt.h	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/crypto/tcrypt.h	2004-08-15 19:51:52.000000000 +0000
@@ -1186,7 +1186,7 @@ struct cipher_testvec tf_cbc_dec_tv_temp
 
 /*
  * Serpent test vectors.  These are backwards because Serpent writes
- * octect sequences in right-to-left mode.
+ * octet sequences in right-to-left mode.
  */
 #define SERPENT_ENC_TEST_VECTORS	4
 #define SERPENT_DEC_TEST_VECTORS	4
@@ -1818,7 +1818,103 @@ struct cipher_testvec xtea_dec_tv_templa
 	}
 };
 
+/*
+ * KHAZAD test vectors.
+ */
+#define KHAZAD_ENC_TEST_VECTORS 5
+#define KHAZAD_DEC_TEST_VECTORS 5
+
+struct cipher_testvec khazad_enc_tv_template[] = { 
+	{ 
+		.key	= { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 16,
+		.input	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ilen	= 8,
+		.result	= { 0x49, 0xa4, 0xce, 0x32, 0xac, 0x19, 0x0e, 0x3f },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+			    0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 },
+		.klen	= 16,
+		.input	= { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 },
+		.ilen	= 8,
+		.result	= { 0x7e, 0x82, 0x12, 0xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2,
+			    0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 },
+		.klen	= 16,
+		.input	= { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 },
+		.ilen	= 8,
+		.result	= { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c },
+		.rlen	= 8,
+	}, {
+		.key	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.klen	= 16,
+		.input	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.ilen	= 8,
+		.result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.klen	= 16,
+		.input	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f ,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.ilen	= 16,
+		.result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 ,
+			    0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 },
+		.rlen	= 16,
+	},
+};
 
+struct cipher_testvec khazad_dec_tv_template[] = { 
+	{
+		.key	= { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.klen	= 16,
+		.input	= { 0X49, 0Xa4, 0Xce, 0X32, 0Xac, 0X19, 0X0e, 0X3f },
+		.ilen	= 8,
+		.result	= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+			    0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 },
+		.klen	= 16,
+		.input	= { 0X7e, 0X82, 0X12, 0Xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 },
+		.ilen	= 8,
+		.result	= { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2,
+			    0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 },
+		.klen	= 16,
+		.input	= { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c },
+		.ilen	= 8,
+		.result	= { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 },
+		.rlen	= 8,
+	}, {
+		.key	= { 0x2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.klen	= 16,
+		.input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 },
+		.ilen	= 8,
+		.result	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.rlen	= 8,
+	}, {
+		.key	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.klen	= 16,
+		.input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 ,
+			    0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 },
+		.ilen	= 16,
+		.result	= { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f ,
+			    0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f },
+		.rlen	= 16,
+	},
+};
 
 /*
  * Compression stuff.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/crypto/twofish.c linux-2.4.28-pre1/crypto/twofish.c
--- linux-2.4.27/crypto/twofish.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/crypto/twofish.c	2004-08-15 19:48:02.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Twofish for CryptoAPI
  *
- * Originaly Twofish for GPG
+ * Originally Twofish for GPG
  * By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
  * 256-bit key length added March 20, 1999
  * Some modifications to reduce the text size by Werner Koch, April, 1998
@@ -514,7 +514,7 @@ static const u8 calc_sb_tbl[512] = {
  * preprocessed through q0 and q1 respectively; for longer keys they are the
  * output of previous stages.  j is the index of the first key byte to use.
  * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
- * twice, doing the Psuedo-Hadamard Transform, and doing the necessary
+ * twice, doing the Pseudo-Hadamard Transform, and doing the necessary
  * rotations.  Its parameters are: a, the array to write the results into,
  * j, the index of the first output entry, k and l, the preprocessed indices
  * for index 2i, and m and n, the preprocessed indices for index 2i+1.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/atm/eni.c linux-2.4.28-pre1/drivers/atm/eni.c
--- linux-2.4.27/drivers/atm/eni.c	2003-11-28 18:26:19.000000000 +0000
+++ linux-2.4.28-pre1/drivers/atm/eni.c	2004-08-15 19:48:34.000000000 +0000
@@ -1879,7 +1879,7 @@ static void eni_close(struct atm_vcc *vc
 	DPRINTK("eni_close: done waiting\n");
 	/* deallocate memory */
 	kfree(ENI_VCC(vcc));
-	ENI_VCC(vcc) = NULL;
+	vcc->dev_data = NULL;
 	clear_bit(ATM_VF_ADDR,&vcc->flags);
 	/*foo();*/
 }
@@ -1951,7 +1951,7 @@ static int eni_open(struct atm_vcc *vcc,
 
 	DPRINTK(">eni_open\n");
 	EVENT("eni_open\n",0,0);
-	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL;
+	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL;
 	eni_dev = ENI_DEV(vcc->dev);
 	error = get_ci(vcc,&vpi,&vci);
 	if (error) return error;
@@ -1966,7 +1966,7 @@ static int eni_open(struct atm_vcc *vcc,
 	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
 		eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL);
 		if (!eni_vcc) return -ENOMEM;
-		ENI_VCC(vcc) = eni_vcc;
+		vcc->dev_data = eni_vcc;
 		eni_vcc->tx = NULL; /* for eni_close after open_rx */
 		if ((error = open_rx_first(vcc))) {
 			eni_close(vcc);
@@ -2302,7 +2302,7 @@ static int __devinit eni_init_one(struct
 	if (!dev) goto out2;
 	pci_set_drvdata(pci_dev, dev);
 	eni_dev->pci_dev = pci_dev;
-	ENI_DEV(dev) = eni_dev;
+	dev->dev_data = eni_dev;
 	eni_dev->asic = ent->driver_data;
 	error = eni_do_init(dev);
 	if (error) goto out3;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/atm/fore200e.c linux-2.4.28-pre1/drivers/atm/fore200e.c
--- linux-2.4.27/drivers/atm/fore200e.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/atm/fore200e.c	2004-08-15 19:52:00.000000000 +0000
@@ -101,6 +101,7 @@
 
 
 #if 1
+#undef ASSERT
 #define ASSERT(expr)     if (!(expr)) { \
                              printk(FORE200E "assertion failed! %s[%d]: %s\n", \
 			            __FUNCTION__, __LINE__, #expr); \
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/atm/suni.c linux-2.4.28-pre1/drivers/atm/suni.c
--- linux-2.4.27/drivers/atm/suni.c	2003-06-13 14:51:32.000000000 +0000
+++ linux-2.4.28-pre1/drivers/atm/suni.c	2004-08-15 19:51:15.000000000 +0000
@@ -230,7 +230,7 @@ static int suni_start(struct atm_dev *de
 	unsigned long flags;
 	int first;
 
-	if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
 		return -ENOMEM;
 
 	PRIV(dev)->dev = dev;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/block/cciss.c linux-2.4.28-pre1/drivers/block/cciss.c
--- linux-2.4.27/drivers/block/cciss.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/block/cciss.c	2004-08-15 19:51:53.000000000 +0000
@@ -80,7 +80,7 @@ const struct pci_device_id cciss_pci_dev
                         0x0E11, 0x4091, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
                         0x0E11, 0x409E, 0, 0, 0},
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISS,
                         0x103C, 0x3211, 0, 0, 0},
 	{0,}
 };
@@ -125,7 +125,7 @@ static struct board_type products[] = {
 /* Originally cciss driver only supports 8 major number */
 #define MAX_CTLR_ORIG  COMPAQ_CISS_MAJOR7 - COMPAQ_CISS_MAJOR + 1
 
-#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFF /* 64 bit DMA */
+#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFFULL /* 64 bit DMA */
 
 #ifdef CONFIG_CISS_MONITOR_THREAD
 static int cciss_monitor(void *ctlr);
@@ -592,7 +592,7 @@ int cciss_ioctl32_passthru(unsigned int 
 	set_fs(old_fs);
 	if (err)
 		return err;
-	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info));
+	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(arg32->error_info));
 	if (err) 
 		return -EFAULT; 
 	return err;
@@ -620,7 +620,7 @@ int cciss_ioctl32_big_passthru(unsigned 
 	set_fs(old_fs);
 	if (err)
 		return err;
-	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info));
+	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(arg32->error_info));
 	if (err) 
 		return -EFAULT; 
 	return err;
@@ -942,6 +942,8 @@ static int cciss_ioctl(struct inode *ino
 			{
 				kfree(buff);
 				return -EFAULT;
+			} else {
+				memset(buff, 0, iocommand.buf_size);
 			}
 		}
 		if ((c = cmd_alloc(h , 0)) == NULL) {
@@ -1060,12 +1062,15 @@ static int cciss_ioctl(struct inode *ino
 					goto cleanup1;
 				}
 				if (iocommand.Request.Type.Direction == 
-						XFER_WRITE)
+						XFER_WRITE) {
 				   /* Copy the data into the buffer created */
 				   if (copy_from_user(buff[sg_used], data_ptr, 
 						buff_size[sg_used])) {
 					status = -ENOMEM;
 					goto cleanup1;			
+				   } else {
+					memset(buff[sg_used], 0, buff_size[sg_used]);
+				   }
 				   }
 				size_left_alloc -= buff_size[sg_used];
 				data_ptr += buff_size[sg_used];
@@ -2671,7 +2676,7 @@ static int find_PCI_BAR_index(struct pci
 static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 {
 	ushort subsystem_vendor_id, subsystem_device_id, command;
-	unchar irq = pdev->irq, ready = 0;
+	int ready = 0;
 	__u32 board_id, scratchpad;
 	__u64 cfg_offset;
 	__u32 cfg_base_addr;
@@ -2727,11 +2732,11 @@ static int cciss_pci_init(ctlr_info_t *c
 
 #ifdef CCISS_DEBUG
 	printk("command = %x\n", command);
-	printk("irq = %x\n", irq);
+	printk("irq = %x\n", pdev->irq);
 	printk("board_id = %x\n", board_id);
 #endif /* CCISS_DEBUG */ 
 
-	c->intr = irq;
+	c->intr = pdev->irq;
 
 	/*
 	 * Memory base addr is first addr , the second points to the config
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/block/cciss.h linux-2.4.28-pre1/drivers/block/cciss.h
--- linux-2.4.27/drivers/block/cciss.h	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/block/cciss.h	2004-08-15 19:47:20.000000000 +0000
@@ -51,7 +51,7 @@ struct ctlr_info 
 	unsigned long io_mem_addr;
 	unsigned long io_mem_length;
 	CfgTable_struct *cfgtable;
-	int	intr;
+	unsigned int	intr;
 	int	interrupts_enabled;
 	int 	max_commands;
 	int	commands_outstanding;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/agp/agp.h linux-2.4.28-pre1/drivers/char/agp/agp.h
--- linux-2.4.27/drivers/char/agp/agp.h	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/agp/agp.h	2004-08-15 19:49:39.000000000 +0000
@@ -211,6 +211,12 @@ struct agp_bridge_data {
 #ifndef PCI_DEVICE_ID_INTEL_865_G_1
 #define PCI_DEVICE_ID_INTEL_865_G_1	0x2572
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_915_G_0
+#define PCI_DEVICE_ID_INTEL_915_G_0	0x2580
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_915_G_1
+#define PCI_DEVICE_ID_INTEL_915_G_1	0x2582
+#endif
 #ifndef PCI_DEVICE_ID_INTEL_820_0
 #define PCI_DEVICE_ID_INTEL_820_0       0x2500
 #endif
@@ -441,6 +447,12 @@ struct agp_bridge_data {
 #define I810_DRAM_ROW_0        0x00000001
 #define I810_DRAM_ROW_0_SDRAM  0x00000001
 
+/* intel I915 registers */
+#define I915_GMADDR 0x18
+#define I915_MMADDR 0x10
+#define I915_PTEADDR 0x1C
+#define I915_GMCH_GMS_STOLEN_48M    (0x6 << 4)
+#define I915_GMCH_GMS_STOLEN_64M    (0x7 << 4)
 
 
 /* VIA register */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/agp/agpgart_be.c linux-2.4.28-pre1/drivers/char/agp/agpgart_be.c
--- linux-2.4.27/drivers/char/agp/agpgart_be.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/agp/agpgart_be.c	2004-08-15 19:48:11.000000000 +0000
@@ -794,7 +794,29 @@ static unsigned long agp_generic_alloc_p
 	}
 #endif
 	get_page(page);
-	LockPage(page);
+	set_bit(PG_locked, &page->flags);
+	atomic_inc(&agp_bridge.current_memory_agp);
+	return (unsigned long)page_address(page);
+}
+
+/* Exists to support ARGB cursors */
+static unsigned long i830_alloc_pages(void)
+{
+	struct page * page;
+	
+	page = alloc_pages(GFP_KERNEL, 2);
+	if (page == NULL) {
+		return 0;
+	}
+
+#ifdef CONFIG_X86
+	if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
+		__free_page(page); 
+		return 0;
+	}
+#endif
+	get_page(page);
+	set_bit(PG_locked, &page->flags);
 	atomic_inc(&agp_bridge.current_memory_agp);
 	return (unsigned long)page_address(page);
 }
@@ -818,6 +840,25 @@ static void agp_generic_destroy_page(uns
 	atomic_dec(&agp_bridge.current_memory_agp);
 }
 
+static void i830_destroy_pages(unsigned long addr)
+{
+	void *pt = (void *) addr;
+	struct page *page;
+
+	if (pt == NULL) {
+		return;
+	}
+	
+	page = virt_to_page(pt);
+#ifdef CONFIG_X86
+	change_page_attr(page, 4, PAGE_KERNEL); 
+#endif	
+	put_page(page);
+	UnlockPage(page);
+	free_pages((unsigned long) pt, 2);
+	atomic_dec(&agp_bridge.current_memory_agp);
+}
+
 /* End Basic Page Allocation Routines */
 
 void agp_enable(u32 mode)
@@ -1022,33 +1063,49 @@ static agp_memory *intel_i810_alloc_by_t
 		return new;
 	}
 	if(type == AGP_PHYS_MEMORY) {
+		unsigned long physical;
+
 		/* The I810 requires a physical address to program
 		 * it's mouse pointer into hardware.  However the
 		 * Xserver still writes to it through the agp
 		 * aperture
 		 */
-	   	if (pg_count != 1) {
-		   	return NULL;
-		}
-	   	new = agp_create_memory(1);
+		if (pg_count != 1 && pg_count != 4) return(NULL);
 
-		if (new == NULL) {
-			return NULL;
+		new = agp_create_memory(pg_count);
+
+		if (new == NULL) return(NULL);
+
+		MOD_INC_USE_COUNT;
+		if (pg_count == 1)
+			new->memory[0] = agp_bridge.agp_alloc_page();
+		else {
+			/* kludge to get 4 physical pages for ARGB cursor */
+			new->memory[0] = i830_alloc_pages();
+			new->memory[1] = new->memory[0] + PAGE_SIZE;
+			new->memory[2] = new->memory[1] + PAGE_SIZE;
+			new->memory[3] = new->memory[2] + PAGE_SIZE;
 		}
-	   	MOD_INC_USE_COUNT;
-		new->memory[0] = agp_bridge.agp_alloc_page();
 
 		if (new->memory[0] == 0) {
 			/* Free this structure */
 			agp_free_memory(new);
 			return NULL;
 		}
+		physical = new->memory[0];
+
 		new->memory[0] = virt_to_phys((void *) new->memory[0]);
-		new->page_count = 1;
-	   	new->num_scratch_pages = 1;
-	   	new->type = AGP_PHYS_MEMORY;
-	        new->physical = virt_to_phys((void *) new->memory[0]);
-	   	return new;
+		if (pg_count == 4) {
+			/* kludge to enable 4 physical pages for ARGB cursor */
+			new->memory[1] = virt_to_phys((void *) new->memory[1]);
+			new->memory[2] = virt_to_phys((void *) new->memory[2]);
+			new->memory[3] = virt_to_phys((void *) new->memory[3]);
+		}
+		new->page_count = pg_count;
+		new->num_scratch_pages = pg_count;
+		new->type = AGP_PHYS_MEMORY;
+		new->physical = virt_to_phys((void *) physical);
+		return(new);
 	}
    
 	return NULL;
@@ -1058,7 +1115,11 @@ static void intel_i810_free_by_type(agp_
 {
 	agp_free_key(curr->key);
    	if(curr->type == AGP_PHYS_MEMORY) {
-	   	agp_bridge.agp_destroy_page((unsigned long)
+		if (curr->page_count == 4)
+			i830_destroy_pages((unsigned long)
+				 phys_to_virt(curr->memory[0]));
+		else
+	   		agp_bridge.agp_destroy_page((unsigned long)
 				 phys_to_virt(curr->memory[0]));
 		vfree(curr->memory);
 	}
@@ -1108,15 +1169,20 @@ static aper_size_info_fixed intel_i830_s
 {
 	{128, 32768, 5},
 	/* The 64M mode still requires a 128k gatt */
-	{64, 16384, 5}
+	{64, 16384, 5},
+	/* For I915G */
+	{256, 65536, 6}
 };
 
 static struct _intel_i830_private {
 	struct pci_dev *i830_dev;   /* device one */
 	volatile u8 *registers;
+	volatile u32 *gtt;	/* I915G */
 	int gtt_entries;
 } intel_i830_private;
 
+static int intel_i830_fetch_size(void);
+
 static void intel_i830_init_gtt_entries(void)
 {
 	u16 gmch_ctrl;
@@ -1124,26 +1190,47 @@ static void intel_i830_init_gtt_entries(
 	u8 rdct;
 	int local = 0;
 	static const int ddt[4] = { 0, 16, 32, 64 };
+        int size;
+ 
 
 	pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
 
+	/* We obtain the size of the GTT, which is also stored (for some
+	 * reason) at the top of stolen memory. Then we add 4KB to that
+  	 * for the video BIOS popup, which is also stored in there. */
+	size = intel_i830_fetch_size() + 4;
+
 	if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 &&
 	    agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) {
 		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
 		case I855_GMCH_GMS_STOLEN_1M:
-			gtt_entries = MB(1) - KB(132);
+			gtt_entries = MB(1) - KB(size);
 			break;
 		case I855_GMCH_GMS_STOLEN_4M:
-			gtt_entries = MB(4) - KB(132);
+			gtt_entries = MB(4) - KB(size);
 			break;
 		case I855_GMCH_GMS_STOLEN_8M:
-			gtt_entries = MB(8) - KB(132);
+			gtt_entries = MB(8) - KB(size);
 			break;
 		case I855_GMCH_GMS_STOLEN_16M:
-			gtt_entries = MB(16) - KB(132);
+			gtt_entries = MB(16) - KB(size);
 			break;
 		case I855_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(132);
+			gtt_entries = MB(32) - KB(size);
+			break;
+		case I915_GMCH_GMS_STOLEN_48M:
+			/* Check it's really I915 */
+			if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0)
+				gtt_entries = MB(48) - KB(size);
+			else
+				gtt_entries = 0;
+			break;
+		case I915_GMCH_GMS_STOLEN_64M:
+			/* Check it's really I915 */
+			if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0)
+				gtt_entries = MB(64) - KB(size);
+			else
+				gtt_entries = 0;
 			break;
 		default:
 			gtt_entries = 0;
@@ -1153,13 +1240,13 @@ static void intel_i830_init_gtt_entries(
 	{
 		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
 		case I830_GMCH_GMS_STOLEN_512:
-			gtt_entries = KB(512) - KB(132);
+			gtt_entries = KB(512) - KB(size);
 			break;
 		case I830_GMCH_GMS_STOLEN_1024:
-			gtt_entries = MB(1) - KB(132);
+			gtt_entries = MB(1) - KB(size);
 			break;
 		case I830_GMCH_GMS_STOLEN_8192:
-			gtt_entries = MB(8) - KB(132);
+			gtt_entries = MB(8) - KB(size);
 			break;
 		case I830_GMCH_GMS_LOCAL:
 			rdct = INREG8(intel_i830_private.registers,
@@ -1193,14 +1280,24 @@ static int intel_i830_create_gatt_table(
 	int page_order;
 	aper_size_info_fixed *size;
 	int num_entries;
-	u32 temp;
+	u32 temp, temp2;
 
 	size = agp_bridge.current_size;
 	page_order = size->page_order;
 	num_entries = size->num_entries;
 	agp_bridge.gatt_table_real = 0;
 
-	pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) {
+		pci_read_config_dword(intel_i830_private.i830_dev,
+							I915_MMADDR,&temp);
+		pci_read_config_dword(intel_i830_private.i830_dev,
+							I915_PTEADDR,&temp2);
+		intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024);
+		if (!intel_i830_private.gtt) return (-ENOMEM);
+	} else
+		pci_read_config_dword(intel_i830_private.i830_dev,	
+							I810_MMADDR,&temp);
+
 	temp &= 0xfff80000;
 
 	intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
@@ -1234,6 +1331,20 @@ static int intel_i830_fetch_size(void)
 
 	values = A_SIZE_FIX(agp_bridge.aperture_sizes);
 
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) {
+		u32 temp, offset = 0;
+		pci_read_config_dword(intel_i830_private.i830_dev,
+							I915_GMADDR,&temp);
+#define I915_256MB_ADDRESS_MASK (1<<27)
+		if (temp & I915_256MB_ADDRESS_MASK)
+			offset = 0;	/* 128MB aperture */
+		else
+			offset = 2;	/* 256MB aperture */
+		agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + offset);
+		agp_bridge.aperture_size_idx = offset;
+		return(values[offset].size);
+	}
+
 	if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 &&
 	    agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) {
 		agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
@@ -1247,7 +1358,7 @@ static int intel_i830_fetch_size(void)
 		agp_bridge.aperture_size_idx = 0;
 		return(values[0].size);
 	} else {
-		agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
+		agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + 1);
 		agp_bridge.aperture_size_idx = 1;
 		return(values[1].size);
 	}
@@ -1264,7 +1375,13 @@ static int intel_i830_configure(void)
 
 	current_size = A_SIZE_FIX(agp_bridge.current_size);
 
-	pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0)
+		pci_read_config_dword(intel_i830_private.i830_dev,
+							I915_GMADDR,&temp);
+	else
+		pci_read_config_dword(intel_i830_private.i830_dev,
+							I810_GMADDR,&temp);
+
 	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 
 	pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
@@ -1274,15 +1391,24 @@ static int intel_i830_configure(void)
 	OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
 	CACHE_FLUSH();
 
-	if (agp_bridge.needs_scratch_page == TRUE)
-		for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
-			OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+	if (agp_bridge.needs_scratch_page == TRUE) {
+		if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) {
+			for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
+				OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page);
+		} else {
+			for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
+				OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+		}
+	}
 
 	return (0);
 }
 
 static void intel_i830_cleanup(void)
 {
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0)
+		iounmap((void *)intel_i830_private.gtt);
+
 	iounmap((void *) intel_i830_private.registers);
 }
 
@@ -1315,9 +1441,13 @@ static int intel_i830_insert_entries(agp
 
 	CACHE_FLUSH();
 
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
-			 agp_bridge.mask_memory(mem->memory[i], mem->type));
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) {
+		for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+			OUTREG32(intel_i830_private.gtt, j, agp_bridge.mask_memory(mem->memory[i], mem->type));
+	} else {
+		for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+			OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),agp_bridge.mask_memory(mem->memory[i], mem->type));
+	}
 
 	CACHE_FLUSH();
 
@@ -1337,8 +1467,13 @@ static int intel_i830_remove_entries(agp
 		return (-EINVAL);
 	}
 
-	for (i = pg_start; i < (mem->page_count + pg_start); i++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+	if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) {
+		for (i = pg_start; i < (mem->page_count + pg_start); i++)
+			OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page);
+	} else {
+		for (i = pg_start; i < (mem->page_count + pg_start); i++)
+			OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
+	}
 
 	CACHE_FLUSH();
 
@@ -1363,24 +1498,40 @@ static agp_memory *intel_i830_alloc_by_t
 		 * aperture
 		 */
 
-		if (pg_count != 1) return(NULL);
+		if (pg_count != 1 && pg_count != 4) return(NULL);
 
-		nw = agp_create_memory(1);
+		nw = agp_create_memory(pg_count);
 
 		if (nw == NULL) return(NULL);
 
 		MOD_INC_USE_COUNT;
-		nw->memory[0] = agp_bridge.agp_alloc_page();
-		physical = nw->memory[0];
+		if (pg_count == 1)
+			nw->memory[0] = agp_bridge.agp_alloc_page();
+		else {
+			/* kludge to get 4 physical pages for ARGB cursor */
+			nw->memory[0] = i830_alloc_pages();
+			nw->memory[1] = nw->memory[0] + PAGE_SIZE;
+			nw->memory[2] = nw->memory[1] + PAGE_SIZE;
+			nw->memory[3] = nw->memory[2] + PAGE_SIZE;
+		}
+
 		if (nw->memory[0] == 0) {
 			/* free this structure */
 			agp_free_memory(nw);
 			return(NULL);
 		}
 
+		physical = nw->memory[0];
+
 		nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
-		nw->page_count = 1;
-		nw->num_scratch_pages = 1;
+		if (pg_count == 4) {
+			/* kludge to enable 4 physical pages for ARGB cursor */
+			nw->memory[1] = virt_to_phys((void *) nw->memory[1]);
+			nw->memory[2] = virt_to_phys((void *) nw->memory[2]);
+			nw->memory[3] = virt_to_phys((void *) nw->memory[3]);
+		}
+		nw->page_count = pg_count;
+		nw->num_scratch_pages = pg_count;
 		nw->type = AGP_PHYS_MEMORY;
 		nw->physical = virt_to_phys((void *) physical);
 		return(nw);
@@ -3447,9 +3598,9 @@ static int x86_64_insert_memory(agp_memo
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		tmp = agp_bridge.mask_memory(mem->memory[i], mem->type);
 
-		BUG_ON(tmp & 0xffffff0000000ffc);
-		pte = (tmp & 0x000000ff00000000) >> 28;
-		pte |=(tmp & 0x00000000fffff000);
+		BUG_ON(tmp & 0xffffff0000000ffcULL);
+		pte = (tmp & 0x000000ff00000000ULL) >> 28;
+		pte |=(tmp & 0x00000000fffff000ULL);
 		pte |= 1<<1|1<<0;
 
 		agp_bridge.gatt_table[j] = pte;
@@ -6112,6 +6263,13 @@ static struct {
 		"865G",
 		 intel_845_setup },
 
+	{ PCI_DEVICE_ID_INTEL_915_G_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I915_G,
+		"Intel(R)",
+		"915G",
+		 intel_845_setup },
+
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -6835,6 +6993,34 @@ static int __init agp_init_one(struct pc
 				   "865G Chipset.\n");
 			agp_bridge.type = INTEL_I810;
 			return intel_i830_setup(i810_dev);
+
+		case PCI_DEVICE_ID_INTEL_915_G_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_915_G_1, NULL);
+			if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
+				i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_915_G_1, i810_dev);
+			}
+
+			if (i810_dev == NULL) {
+                                /* 
+                                 * We probably have a 915G chipset
+                                 * with an external graphics
+                                 * card. It will be initialized later 
+                                 */
+				printk(KERN_ERR PFX "Detected an "
+				       "Intel(R) 915G, but could not"
+				       " find the"
+				       " secondary device. Assuming a "
+				       "non-integrated video card.\n");
+				agp_bridge.type = INTEL_I915_G;
+				break;
+			}
+			printk(KERN_INFO PFX "Detected an Intel(R) "
+				   "915G Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i830_setup(i810_dev);
+
 		default:
 			break;
 		}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/applicom.c linux-2.4.28-pre1/drivers/char/applicom.c
--- linux-2.4.27/drivers/char/applicom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/applicom.c	2004-08-15 19:51:43.000000000 +0000
@@ -222,6 +222,7 @@ int __init applicom_init(void)
 
 		if (!RamIO) {
 			printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
+			pci_disable_device(dev);
 			return -EIO;
 		}
 
@@ -233,12 +234,14 @@ int __init applicom_init(void)
 						  (unsigned long)RamIO,0))) {
 			printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
 			iounmap(RamIO);
+			pci_disable_device(dev);
 			continue;
 		}
 
 		if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) {
 			printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
 			iounmap(RamIO);
+			pci_disable_device(dev);
 			apbs[boardno - 1].RamIO = 0;
 			continue;
 		}
@@ -265,12 +268,6 @@ int __init applicom_init(void)
 
 	/* Now try the specified ISA cards */
 
-#warning "LEAK"
-	RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
-
-	if (!RamIO) 
-		printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem);
-
 	for (i = 0; i < MAX_ISA_BOARD; i++) {
 		RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
 
@@ -293,7 +290,8 @@ int __init applicom_init(void)
 				iounmap((void *) RamIO);
 				apbs[boardno - 1].RamIO = 0;
 			}
-			apbs[boardno - 1].irq = irq;
+			else
+				apbs[boardno - 1].irq = irq;
 		}
 		else
 			apbs[boardno - 1].irq = 0;
@@ -368,7 +366,7 @@ static ssize_t ac_write(struct file *fil
 	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
 		static int warncount = 5;
 		if (warncount) {
-			printk(KERN_INFO "Hmmm. write() of Applicom card, length %d != expected %d\n",
+			printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n",
 			       count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
 			warncount--;
 		}
@@ -476,18 +474,17 @@ static ssize_t ac_write(struct file *fil
 	return 0;
 }
 
-static int do_ac_read(int IndexCard, char *buf)
+static int do_ac_read(int IndexCard, char *buf,
+		struct st_ram_io *st_loc, struct mailbox *mailbox)
 {
-	struct st_ram_io st_loc;
-	struct mailbox tmpmailbox;	/* bounce buffer - can't copy to user space with cli() */
 	unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
-	unsigned char *to = (unsigned char *)&tmpmailbox;
+	unsigned char *to = (unsigned char *)&mailbox;
 #ifdef DEBUG
 	int c;
 #endif
 
-	st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
-	st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+	st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
+	st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
 
 
 	{
@@ -510,32 +507,24 @@ static int do_ac_read(int IndexCard, cha
 		printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
 
 		for (c = 0; c < sizeof(struct st_ram_io);) {
-			printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
+			printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]);
 
 			for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
-				printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
+				printk(" %2.2X", ((unsigned char *)st_loc)[c]);
 			}
 		}
 
 		printk("\nstruct mailbox follows:");
 
 		for (c = 0; c < sizeof(struct mailbox);) {
-			printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
+			printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]);
 
 			for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
-				printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
+				printk(" %2.2X", ((unsigned char *)mailbox)[c]);
 			}
 		}
 		printk("\n");
 #endif
-
-#warning "Je suis stupide. DW. - copy*user in cli"
-
-	if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
-		return -EFAULT;
-	if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
-		return -EFAULT;
-
 	return (sizeof(struct st_ram_io) + sizeof(struct mailbox));
 }
 
@@ -551,7 +540,7 @@ static ssize_t ac_read (struct file *fil
 #endif
 	/* No need to ratelimit this. Only root can trigger it anyway */
 	if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
-		printk( KERN_WARNING "Hmmm. read() of Applicom card, length %d != expected %d\n",
+		printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n",
 			count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
 		return -EINVAL;
 	}
@@ -570,11 +559,19 @@ static ssize_t ac_read (struct file *fil
 			tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
 			
 			if (tmp == 2) {
+				struct st_ram_io st_loc;
+				struct mailbox mailbox;
+
 				/* Got a packet for us */
-				ret = do_ac_read(i, buf);
+				ret = do_ac_read(i, buf, &st_loc, &mailbox);
 				spin_unlock_irqrestore(&apbs[i].mutex, flags);
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&FlagSleepRec, &wait);
+
+				if (copy_to_user(buf, &st_loc, sizeof(st_loc)))
+					return -EFAULT;
+				if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox)))
+					return -EFAULT;
 				return tmp;
 			}
 			
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/drm/drm_dma.h linux-2.4.28-pre1/drivers/char/drm/drm_dma.h
--- linux-2.4.27/drivers/char/drm/drm_dma.h	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/drm/drm_dma.h	2004-08-15 19:50:37.000000000 +0000
@@ -648,7 +648,7 @@ int DRM(wait_vblank)(struct inode *inode
 		 * for the same vblank sequence number; nothing to be done in
 		 * that case
 		 */
-		list_for_each( ( (struct list_head *) vbl_sig ), &dev->vbl_sigs.head ) {
+		list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) {
 			if (vbl_sig->sequence == vblwait.request.sequence
 			    && vbl_sig->info.si_signo == vblwait.request.signal
 			    && vbl_sig->task == current)
@@ -699,19 +699,20 @@ done:
 
 void DRM(vbl_send_signals)( drm_device_t *dev )
 {
-	struct list_head *tmp;
+	struct list_head *list, *tmp;
 	drm_vbl_sig_t *vbl_sig;
 	unsigned int vbl_seq = atomic_read( &dev->vbl_received );
 	unsigned long flags;
 
 	spin_lock_irqsave( &dev->vbl_lock, flags );
 
-	list_for_each_safe( ( (struct list_head *) vbl_sig ), tmp, &dev->vbl_sigs.head ) {
+	list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) {
+		vbl_sig = list_entry( list, drm_vbl_sig_t, head );
 		if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
 			vbl_sig->info.si_code = vbl_seq;
 			send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task );
 
-			list_del( (struct list_head *) vbl_sig );
+			list_del( list );
 
 
 			kfree( vbl_sig );
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/drm/radeon_state.c linux-2.4.28-pre1/drivers/char/drm/radeon_state.c
--- linux-2.4.27/drivers/char/drm/radeon_state.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/drm/radeon_state.c	2004-08-15 19:51:20.000000000 +0000
@@ -1223,7 +1223,7 @@ static int radeon_cp_dispatch_texture( d
 		/* Update the input parameters for next time */
 		image->y += height;
 		image->height -= height;
-		(const u8 *)image->data += size;
+		image->data = (const u8 *)image->data + size;
 	} while (image->height > 0);
 
 	/* Flush the pixel cache after the blit completes.  This ensures
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.c linux-2.4.28-pre1/drivers/char/ftape/lowlevel/ftape-bsm.c
--- linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.c	2000-10-16 19:58:51.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/ftape/lowlevel/ftape-bsm.c	2004-08-15 19:48:42.000000000 +0000
@@ -203,6 +203,7 @@ static void print_bad_sector_map(void)
 	    ft_format_code == fmt_1100ft) {
 		SectorCount *ptr = (SectorCount *)bad_sector_map;
 		unsigned int sector;
+		__u16 *ptr16;
 
 		while((sector = get_sector(ptr++)) != 0) {
 			if ((ft_format_code == fmt_big || 
@@ -218,9 +219,10 @@ static void print_bad_sector_map(void)
 		}
 		/*  Display old ftape's end-of-file marks
 		 */
-		while ((sector = get_unaligned(((__u16*)ptr)++)) != 0) {
+		ptr16 = (__u16*)ptr;
+		while ((sector = get_unaligned(ptr16++)) != 0) {
 			TRACE(ft_t_noise, "Old ftape eof mark: %4d/%2d",
-			      sector, get_unaligned(((__u16*)ptr)++));
+			      sector, get_unaligned(ptr16++));
 		}
 	} else { /* fixed size format */
 		for (i = ft_first_data_segment;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.h linux-2.4.28-pre1/drivers/char/ftape/lowlevel/ftape-bsm.h
--- linux-2.4.27/drivers/char/ftape/lowlevel/ftape-bsm.h	1997-11-25 22:45:27.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/ftape/lowlevel/ftape-bsm.h	2004-08-15 19:47:11.000000000 +0000
@@ -47,7 +47,7 @@ typedef __u32 SectorMap;
  */
 typedef struct NewSectorMap {          
 	__u8 bytes[3];
-} SectorCount __attribute__((packed));
+} __attribute__((packed)) SectorCount;
 
 
 /*
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/ftape/zftape/zftape-eof.c linux-2.4.28-pre1/drivers/char/ftape/zftape/zftape-eof.c
--- linux-2.4.27/drivers/char/ftape/zftape/zftape-eof.c	1999-11-23 18:29:15.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/ftape/zftape/zftape-eof.c	2004-08-15 19:52:11.942473920 +0000
@@ -123,7 +123,7 @@ static __u8 * find_end_of_eof_list(__u8 
 	while (ptr + 3 < limit) {
 
 		if (get_unaligned((__u32*)ptr)) {
-			++(__u32*)ptr;
+			ptr += sizeof(__u32);
 		} else {
 			return ptr;
 		}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/nwflash.c linux-2.4.28-pre1/drivers/char/nwflash.c
--- linux-2.4.27/drivers/char/nwflash.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/nwflash.c	2004-08-15 19:52:06.000000000 +0000
@@ -159,7 +159,8 @@ static ssize_t flash_read(struct file *f
 		if (ret == 0) {
 			ret = count;
 			*ppos = p + count;
-		}
+		} else
+			ret = -EFAULT;
 		up(&nwflash_sem);
 	}
 	return ret;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/char/random.c linux-2.4.28-pre1/drivers/char/random.c
--- linux-2.4.27/drivers/char/random.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/char/random.c	2004-08-15 19:47:53.000000000 +0000
@@ -750,6 +750,11 @@ static void add_timer_randomness(struct 
 	__u32 high;
 	rdtsc(time, high);
 	num ^= high;
+#elif defined (__sparc_v9__)
+	unsigned long tick = tick_ops->get_tick();
+
+	time = (unsigned int) tick;
+	num ^= (tick >> 32UL);
 #else
 	time = jiffies;
 #endif
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/fc4/fc.c linux-2.4.28-pre1/drivers/fc4/fc.c
--- linux-2.4.27/drivers/fc4/fc.c	2001-09-14 21:04:08.000000000 +0000
+++ linux-2.4.28-pre1/drivers/fc4/fc.c	2004-08-15 19:50:23.000000000 +0000
@@ -1155,3 +1155,5 @@ int fc_do_prli(fc_channel *fc, unsigned 
 	kfree(p);
 	return status;
 }
+
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/ide/Config.in linux-2.4.28-pre1/drivers/ide/Config.in
--- linux-2.4.27/drivers/ide/Config.in	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/ide/Config.in	2004-08-15 19:51:39.000000000 +0000
@@ -12,6 +12,7 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; the
    dep_bool '  Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86
    define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE
 
+   dep_mbool '  Support for SATA (deprecated; conflicts with libata SATA driver)' CONFIG_BLK_DEV_IDE_SATA $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
    dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/ide/pci/amd74xx.c linux-2.4.28-pre1/drivers/ide/pci/amd74xx.c
--- linux-2.4.27/drivers/ide/pci/amd74xx.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/ide/pci/amd74xx.c	2004-08-15 19:50:23.000000000 +0000
@@ -70,11 +70,7 @@ static struct amd_ide_chip {
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,	0x50, AMD_UDMA_133 },
-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,	0x50, AMD_UDMA_133 },
-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,	0x50, AMD_UDMA_133 },
 	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	0x50, AMD_UDMA_133 },
-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,	0x50, AMD_UDMA_133 },
-	{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,	0x50, AMD_UDMA_133 },
 	{ 0 }
 };
 
@@ -466,17 +462,17 @@ static struct pci_device_id amd74xx_pci_
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  5 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  6 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  7 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  8 },
+#endif
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  9 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+#endif
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
 	{ 0, },
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/ide/pci/amd74xx.h linux-2.4.28-pre1/drivers/ide/pci/amd74xx.h
--- linux-2.4.27/drivers/ide/pci/amd74xx.h	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/ide/pci/amd74xx.h	2004-08-15 19:51:38.000000000 +0000
@@ -188,28 +188,6 @@ static ide_pci_device_t amd74xx_chipsets
 	},
 	{	/* 14 */
 		.vendor		= PCI_VENDOR_ID_NVIDIA,
-		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
-		.name		= "NFORCE-CK804-SATA",
-		.init_chipset	= init_chipset_amd74xx,
-		.init_hwif	= init_hwif_amd74xx,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
-		.bootable	= ON_BOARD,
-	},
-	{	/* 15 */
-		.vendor		= PCI_VENDOR_ID_NVIDIA,
-		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
-		.name		= "NFORCE-CK804-SATA2",
-		.init_chipset	= init_chipset_amd74xx,
-		.init_hwif	= init_hwif_amd74xx,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
-		.bootable	= ON_BOARD,
-	},
-	{	/* 16 */
-		.vendor		= PCI_VENDOR_ID_NVIDIA,
 		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,
 		.name		= "NFORCE-MCP04",
 		.init_chipset	= init_chipset_amd74xx,
@@ -219,28 +197,6 @@ static ide_pci_device_t amd74xx_chipsets
 		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
 		.bootable	= ON_BOARD,
 	},
-	{	/* 17 */
-		.vendor		= PCI_VENDOR_ID_NVIDIA,
-		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
-		.name		= "NFORCE-MCP04-SATA",
-		.init_chipset	= init_chipset_amd74xx,
-		.init_hwif	= init_hwif_amd74xx,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
-		.bootable	= ON_BOARD,
-	},
-	{	/* 18 */
-		.vendor		= PCI_VENDOR_ID_NVIDIA,
-		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
-		.name		= "NFORCE-MCP04-SATA2",
-		.init_chipset	= init_chipset_amd74xx,
-		.init_hwif	= init_hwif_amd74xx,
-		.channels	= 2,
-		.autodma	= AUTODMA,
-		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},
-		.bootable	= ON_BOARD,
-	},
 	{
 		.vendor		= 0,
 		.device		= 0,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/ide/pci/piix.c linux-2.4.28-pre1/drivers/ide/pci/piix.c
--- linux-2.4.27/drivers/ide/pci/piix.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/ide/pci/piix.c	2004-08-15 19:51:43.000000000 +0000
@@ -49,9 +49,9 @@
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, &reg48);
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &reg54);
  *
  * Documentation
  *	Publically available from Intel web site. Errata documentation
@@ -433,15 +433,14 @@ static int piix_tune_chipset (ide_drive_
 	int w_flag		= 0x10 << drive->dn;
 	int u_speed		= 0;
 	int			sitre;
-	u16			reg4042, reg44, reg48, reg4a, reg54;
-	u8			reg55;
+	u16			reg4042, reg4a;
+	u8			reg48, reg54, reg55;
 
 	pci_read_config_word(dev, maslave, &reg4042);
 	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x48, &reg48);
 	pci_read_config_word(dev, 0x4a, &reg4a);
-	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x54, &reg54);
 	pci_read_config_byte(dev, 0x55, &reg55);
 
 	switch(speed) {
@@ -463,30 +462,26 @@ static int piix_tune_chipset (ide_drive_
 
 	if (speed >= XFER_UDMA_0) {
 		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
+			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
 		if (speed == XFER_UDMA_5) {
 			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
 		} else {
 			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
 		}
-		if (!(reg4a & u_speed)) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
+		if ((reg4a & a_speed) != u_speed)
+			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
 		if (speed > XFER_UDMA_2) {
-			if (!(reg54 & v_flag)) {
-				pci_write_config_word(dev, 0x54, reg54|v_flag);
-			}
-		} else {
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		}
+			if (!(reg54 & v_flag))
+				pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+		} else
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
 	} else {
 		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
 		if (reg4a & a_speed)
 			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
 		if (reg54 & v_flag)
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
 		if (reg55 & w_flag)
 			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
 	}
@@ -882,7 +877,9 @@ static struct pci_device_id piix_pci_tbl
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+#ifdef CONFIG_BLK_DEV_IDE_SATA
  	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+#endif
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
 	{ 0, },
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/ide/pci/siimage.c linux-2.4.28-pre1/drivers/ide/pci/siimage.c
--- linux-2.4.27/drivers/ide/pci/siimage.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/ide/pci/siimage.c	2004-08-15 19:51:18.000000000 +0000
@@ -1194,8 +1194,10 @@ static int __devinit siimage_init_one(st
 
 static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#ifdef CONFIG_BLK_DEV_IDE_SATA
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+#endif
 	{ 0, },
 };
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/divert/divert_procfs.c linux-2.4.28-pre1/drivers/isdn/divert/divert_procfs.c
--- linux-2.4.27/drivers/isdn/divert/divert_procfs.c	2004-08-07 23:26:04.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/divert/divert_procfs.c	2004-08-15 19:51:43.000000000 +0000
@@ -92,7 +92,7 @@ isdn_divert_read(struct file *file, char
 		return (0);
 
 	inf->usage_cnt--;	/* new usage count */
-	(struct divert_info **) file->private_data = &inf->next;	/* next structure */
+	file->private_data = &inf->next;	/* next structure */
 	if ((len = strlen(inf->info_start)) <= count) {
 		if (copy_to_user(buf, inf->info_start, len))
 			return -EFAULT;
@@ -141,9 +141,9 @@ isdn_divert_open(struct inode *ino, stru
 	cli();
 	if_used++;
 	if (divert_info_head)
-		(struct divert_info **) filep->private_data = &(divert_info_tail->next);
+		filep->private_data = &(divert_info_tail->next);
 	else
-		(struct divert_info **) filep->private_data = &divert_info_head;
+		filep->private_data = &divert_info_head;
 	restore_flags(flags);
 	/*  start_divert(); */
 	unlock_kernel();
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/hisax/callc.c linux-2.4.28-pre1/drivers/isdn/hisax/callc.c
--- linux-2.4.27/drivers/isdn/hisax/callc.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/hisax/callc.c	2004-08-15 19:50:09.000000000 +0000
@@ -925,7 +925,7 @@ static void stat_redir_result(struct Isd
 	ic.driver = cs->myid;
 	ic.command = ISDN_STAT_REDIR;
 	ic.arg = chan; 
-	(ulong)(ic.parm.num[0]) = result;
+	ic.parm.num[0] = result;
 	cs->iif.statcallb(&ic);
 } /* stat_redir_result */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/hisax/st5481.h linux-2.4.28-pre1/drivers/isdn/hisax/st5481.h
--- linux-2.4.27/drivers/isdn/hisax/st5481.h	2003-06-13 14:51:34.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/hisax/st5481.h	2004-08-15 19:50:45.000000000 +0000
@@ -219,13 +219,13 @@ enum {
 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
 
 #define ERR(format, arg...) \
-printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_ERR "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
 #define WARN(format, arg...) \
-printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
 #define INFO(format, arg...) \
-printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+printk(KERN_INFO "%s:%s: " format "\n" , __FILE__,  __FUNCTION__ , ## arg)
 
 #include "isdnhdlc.h"
 #include "fsm.h"
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/callbacks.c linux-2.4.28-pre1/drivers/isdn/pcbit/callbacks.c
--- linux-2.4.27/drivers/isdn/pcbit/callbacks.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/callbacks.c	2004-08-15 19:52:03.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/callbacks.h linux-2.4.28-pre1/drivers/isdn/pcbit/callbacks.h
--- linux-2.4.27/drivers/isdn/pcbit/callbacks.h	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/callbacks.h	2004-08-15 19:47:16.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/capi.c linux-2.4.28-pre1/drivers/isdn/pcbit/capi.c
--- linux-2.4.27/drivers/isdn/pcbit/capi.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/capi.c	2004-08-15 19:51:00.000000000 +0000
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/capi.h linux-2.4.28-pre1/drivers/isdn/pcbit/capi.h
--- linux-2.4.27/drivers/isdn/pcbit/capi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/capi.h	2004-08-15 19:51:40.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/drv.c linux-2.4.28-pre1/drivers/isdn/pcbit/drv.c
--- linux-2.4.27/drivers/isdn/pcbit/drv.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/drv.c	2004-08-15 19:51:00.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/edss1.c linux-2.4.28-pre1/drivers/isdn/pcbit/edss1.c
--- linux-2.4.27/drivers/isdn/pcbit/edss1.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/edss1.c	2004-08-15 19:47:51.000000000 +0000
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/edss1.h linux-2.4.28-pre1/drivers/isdn/pcbit/edss1.h
--- linux-2.4.27/drivers/isdn/pcbit/edss1.h	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/edss1.h	2004-08-15 19:48:43.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/layer2.c linux-2.4.28-pre1/drivers/isdn/pcbit/layer2.c
--- linux-2.4.27/drivers/isdn/pcbit/layer2.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/layer2.c	2004-08-15 19:51:02.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/layer2.h linux-2.4.28-pre1/drivers/isdn/pcbit/layer2.h
--- linux-2.4.27/drivers/isdn/pcbit/layer2.h	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/layer2.h	2004-08-15 19:48:02.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/module.c linux-2.4.28-pre1/drivers/isdn/pcbit/module.c
--- linux-2.4.27/drivers/isdn/pcbit/module.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/module.c	2004-08-15 19:50:43.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/isdn/pcbit/pcbit.h linux-2.4.28-pre1/drivers/isdn/pcbit/pcbit.h
--- linux-2.4.27/drivers/isdn/pcbit/pcbit.h	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.28-pre1/drivers/isdn/pcbit/pcbit.h	2004-08-15 19:47:59.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 Universidade de Lisboa
  * 
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ * Written by Pedro Roque Marques (pedro_m@yahoo.com)
  *
  * This software may be used and distributed according to the terms of 
  * the GNU General Public License, incorporated herein by reference.
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/message/i2o/i2o_pci.c linux-2.4.28-pre1/drivers/message/i2o/i2o_pci.c
--- linux-2.4.27/drivers/message/i2o/i2o_pci.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.28-pre1/drivers/message/i2o/i2o_pci.c	2004-08-15 19:48:14.000000000 +0000
@@ -390,4 +390,3 @@ MODULE_PARM(dpt, "i");
 MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o");
 module_init(i2o_pci_core_attach);
 module_exit(i2o_pci_core_detach);
- 
\ No newline at end of file
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/mtd/maps/amd76xrom.c linux-2.4.28-pre1/drivers/mtd/maps/amd76xrom.c
--- linux-2.4.27/drivers/mtd/maps/amd76xrom.c	2003-06-13 14:51:34.000000000 +0000
+++ linux-2.4.28-pre1/drivers/mtd/maps/amd76xrom.c	2004-08-15 19:49:12.000000000 +0000
@@ -178,7 +178,7 @@ err_out_iounmap:
 	iounmap((void *)(info->window_addr));
 err_out_free_mmio_region:
 	release_mem_region(window->start, window->size);
-err_out_none:
+//err_out_none:
 	return -ENODEV;
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/fc/iph5526.c linux-2.4.28-pre1/drivers/net/fc/iph5526.c
--- linux-2.4.27/drivers/net/fc/iph5526.c	2003-06-13 14:51:34.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/fc/iph5526.c	2004-08-15 19:48:37.000000000 +0000
@@ -689,8 +689,8 @@ int index, no_of_entries = 0;
 			prev_IMQ_index = current_IMQ_index;
 		}
 	} /*end of for loop*/		
-	return;
 	LEAVE("tachyon_interrupt");
+       return;
 }
 
 
@@ -2933,7 +2933,7 @@ static void iph5526_timeout(struct net_d
 {
 	struct fc_info *fi = (struct fc_info*)dev->priv;
 	printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
-	fi->fc_stats.rx_dropped++;
+	fi->fc_stats.tx_dropped++;
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
 }
@@ -2976,7 +2976,7 @@ static int iph5526_send_packet(struct sk
 		fi->fc_stats.tx_packets++;
 	}
 	else
-		fi->fc_stats.rx_dropped++;
+		fi->fc_stats.tx_dropped++;
 	dev->trans_start = jiffies;
 	/* We free up the IP buffers in the OCI_interrupt handler.
 	 * status == 0 implies that the frame was not transmitted. So the
@@ -3374,8 +3374,8 @@ u_int s_id;
 		q = q->next;
 	}
 	DPRINTK1("Port Name does not match. Txing LOGO.");
-	return 0;
 	LEAVE("validate_login");
+       return 0;
 }
 
 static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr)
@@ -3758,8 +3758,10 @@ struct pci_dev *pdev = NULL;
 		sprintf(fi->name, "fc%d", count);
 
 		host = scsi_register(tmpt, sizeof(struct iph5526_hostdata));
-		if(host==NULL)
+		if(host==NULL) {
+			kfree(fc[count]);
 			return no_of_hosts;
+		}
 			
 		hostdata = (struct iph5526_hostdata *)host->hostdata;
 		memset(hostdata, 0 , sizeof(struct iph5526_hostdata));
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/irda/ma600.c linux-2.4.28-pre1/drivers/net/irda/ma600.c
--- linux-2.4.27/drivers/net/irda/ma600.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/irda/ma600.c	2004-08-15 19:48:47.000000000 +0000
@@ -48,7 +48,7 @@
 	#undef IRDA_DEBUG
 	#define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args))
 
-	#undef ASSERT(expr, func)
+	#undef ASSERT
 	#define ASSERT(expr, func) \
 	if(!(expr)) { \
 		printk( "Assertion failed! %s,%s,%s,line=%d\n",\
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/ns83820.c linux-2.4.28-pre1/drivers/net/ns83820.c
--- linux-2.4.27/drivers/net/ns83820.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/ns83820.c	2004-08-15 19:51:53.000000000 +0000
@@ -587,7 +587,7 @@ static inline int rx_refill(struct ns838
 }
 
 static void FASTCALL(rx_refill_atomic(struct ns83820 *dev));
-static void rx_refill_atomic(struct ns83820 *dev)
+static void fastcall rx_refill_atomic(struct ns83820 *dev)
 {
 	rx_refill(dev, GFP_ATOMIC);
 }
@@ -608,7 +608,7 @@ static inline void clear_rx_desc(struct 
 }
 
 static void FASTCALL(phy_intr(struct ns83820 *dev));
-static void phy_intr(struct ns83820 *dev)
+static void fastcall phy_intr(struct ns83820 *dev)
 {
 	static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
 	u32 cfg, new_cfg;
@@ -793,7 +793,7 @@ static void ns83820_cleanup_rx(struct ns
 }
 
 static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev));
-static void ns83820_rx_kick(struct ns83820 *dev)
+static void fastcall ns83820_rx_kick(struct ns83820 *dev)
 {
 	/*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ {
 		if (dev->rx_info.up) {
@@ -814,7 +814,7 @@ static void ns83820_rx_kick(struct ns838
  *	
  */
 static void FASTCALL(rx_irq(struct ns83820 *dev));
-static void rx_irq(struct ns83820 *dev)
+static void fastcall rx_irq(struct ns83820 *dev)
 {
 	struct rx_info *info = &dev->rx_info;
 	unsigned next_rx;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/sungem.c linux-2.4.28-pre1/drivers/net/sungem.c
--- linux-2.4.27/drivers/net/sungem.c	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/sungem.c	2004-08-15 19:51:51.000000000 +0000
@@ -2920,7 +2920,7 @@ static int __devinit gem_init_one(struct
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_SUN &&
 	    pdev->device == PCI_DEVICE_ID_SUN_GEM &&
-	    !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
+	    !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) {
 		pci_using_dac = 1;
 	} else {
 		err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/sungem.h linux-2.4.28-pre1/drivers/net/sungem.h
--- linux-2.4.27/drivers/net/sungem.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/sungem.h	2004-08-15 19:50:21.000000000 +0000
@@ -805,14 +805,14 @@ struct gem_txd {
 	u64	buffer;
 };
 
-#define TXDCTRL_BUFSZ	0x0000000000007fff	/* Buffer Size		*/
-#define TXDCTRL_CSTART	0x00000000001f8000	/* CSUM Start Offset	*/
-#define TXDCTRL_COFF	0x000000001fe00000	/* CSUM Stuff Offset	*/
-#define TXDCTRL_CENAB	0x0000000020000000	/* CSUM Enable		*/
-#define TXDCTRL_EOF	0x0000000040000000	/* End of Frame		*/
-#define TXDCTRL_SOF	0x0000000080000000	/* Start of Frame	*/
-#define TXDCTRL_INTME	0x0000000100000000	/* "Interrupt Me"	*/
-#define TXDCTRL_NOCRC	0x0000000200000000	/* No CRC Present	*/
+#define TXDCTRL_BUFSZ	0x0000000000007fffULL	/* Buffer Size		*/
+#define TXDCTRL_CSTART	0x00000000001f8000ULL	/* CSUM Start Offset	*/
+#define TXDCTRL_COFF	0x000000001fe00000ULL	/* CSUM Stuff Offset	*/
+#define TXDCTRL_CENAB	0x0000000020000000ULL	/* CSUM Enable		*/
+#define TXDCTRL_EOF	0x0000000040000000ULL	/* End of Frame		*/
+#define TXDCTRL_SOF	0x0000000080000000ULL	/* Start of Frame	*/
+#define TXDCTRL_INTME	0x0000000100000000ULL	/* "Interrupt Me"	*/
+#define TXDCTRL_NOCRC	0x0000000200000000ULL	/* No CRC Present	*/
 
 /* GEM requires that RX descriptors are provided four at a time,
  * aligned.  Also, the RX ring may not wrap around.  This means that
@@ -840,13 +840,13 @@ struct gem_rxd {
 	u64	buffer;
 };
 
-#define RXDCTRL_TCPCSUM	0x000000000000ffff	/* TCP Pseudo-CSUM	*/
-#define RXDCTRL_BUFSZ	0x000000007fff0000	/* Buffer Size		*/
-#define RXDCTRL_OWN	0x0000000080000000	/* GEM owns this entry	*/
-#define RXDCTRL_HASHVAL	0x0ffff00000000000	/* Hash Value		*/
-#define RXDCTRL_HPASS	0x1000000000000000	/* Passed Hash Filter	*/
-#define RXDCTRL_ALTMAC	0x2000000000000000	/* Matched ALT MAC	*/
-#define RXDCTRL_BAD	0x4000000000000000	/* Frame has bad CRC	*/
+#define RXDCTRL_TCPCSUM	0x000000000000ffffULL	/* TCP Pseudo-CSUM	*/
+#define RXDCTRL_BUFSZ	0x000000007fff0000ULL	/* Buffer Size		*/
+#define RXDCTRL_OWN	0x0000000080000000ULL	/* GEM owns this entry	*/
+#define RXDCTRL_HASHVAL	0x0ffff00000000000ULL	/* Hash Value		*/
+#define RXDCTRL_HPASS	0x1000000000000000ULL	/* Passed Hash Filter	*/
+#define RXDCTRL_ALTMAC	0x2000000000000000ULL	/* Matched ALT MAC	*/
+#define RXDCTRL_BAD	0x4000000000000000ULL	/* Frame has bad CRC	*/
 
 #define RXDCTRL_FRESH(gp)	\
 	((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wan/pc300_tty.c linux-2.4.28-pre1/drivers/net/wan/pc300_tty.c
--- linux-2.4.27/drivers/net/wan/pc300_tty.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wan/pc300_tty.c	2004-08-15 19:49:25.000000000 +0000
@@ -702,7 +702,7 @@ static void cpc_tty_rx_task(void * data)
 															
 				if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { 
 					CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
-					cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, buf->data, 
+					cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, 
 													&flags, buf->size);
 				}	
 				cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/Config.in linux-2.4.28-pre1/drivers/net/wireless/Config.in
--- linux-2.4.27/drivers/net/wireless/Config.in	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/Config.in	2004-08-15 19:49:01.000000000 +0000
@@ -27,6 +27,15 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
    dep_tristate '  Atmel at76c502/at76c504 PCMCIA cards' CONFIG_PCMCIA_ATMEL $CONFIG_FW_LOADER
 fi
 
+# If PCI enabled, allow for prism54 driver. CONFIG_FW_LOADER required
+comment 'Prism54 PCI/PCMCIA GT/Duette Driver - 802.11(a/b/g)'
+dep_tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA' CONFIG_PRISM54 $CONFIG_EXPERIMENTAL $CONFIG_PCI $CONFIG_HOTPLUG
+if [ "$CONFIG_PRISM54" != "n" ]; then
+ if [ "$CONFIG_FW_LOADER" != "y" ]; then
+  define_tristate CONFIG_FW_LOADER $CONFIG_PRISM54
+ fi
+fi
+
 # yes, this works even when no drivers are selected
 if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" -o \
      "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" ]; then
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/Makefile linux-2.4.28-pre1/drivers/net/wireless/Makefile
--- linux-2.4.27/drivers/net/wireless/Makefile	2004-04-14 13:05:30.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/Makefile	2004-08-15 19:52:11.000000000 +0000
@@ -25,4 +25,9 @@ obj-$(CONFIG_AIRO)		+= airo.o
 obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o
 obj-$(CONFIG_PCMCIA_ATMEL)	+= atmel_cs.o atmel.o
 
+ifeq ($(CONFIG_PRISM54),y)
+obj-$(CONFIG_PRISM54)		+= prism54/prism54.o
+endif
+subdir-$(CONFIG_PRISM54)	+= prism54
+
 include $(TOPDIR)/Rules.make
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/Makefile linux-2.4.28-pre1/drivers/net/wireless/prism54/Makefile
--- linux-2.4.27/drivers/net/wireless/prism54/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/Makefile	2004-08-15 19:51:51.000000000 +0000
@@ -0,0 +1,12 @@
+
+O_TARGET := prism54.o
+
+EXTRA_CFLAGS += -DPRISM54_COMPAT24
+
+obj-y		:= isl_38xx.o islpci_dev.o islpci_eth.o \
+		   islpci_mgt.o islpci_hotplug.o isl_ioctl.o \
+		   oid_mgt.o
+
+obj-m		+= prism54.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.c linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_38xx.c
--- linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_38xx.c	2004-08-15 19:52:08.000000000 +0000
@@ -0,0 +1,267 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "prismcompat.h"
+#include "isl_38xx.h"
+#include "islpci_dev.h"
+#include "islpci_mgt.h"
+
+/******************************************************************************
+    Device Interface & Control functions
+******************************************************************************/
+
+/**
+ * isl38xx_disable_interrupts - disable all interrupts
+ * @device: pci memory base address
+ *
+ *  Instructs the device to disable all interrupt reporting by asserting 
+ *  the IRQ line. New events may still show up in the interrupt identification
+ *  register located at offset %ISL38XX_INT_IDENT_REG.
+ */
+void
+isl38xx_disable_interrupts(void *device)
+{
+	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
+			     int *powerstate, void *device_base)
+{
+	/* device requests to go into sleep mode
+	 * check whether the transmit queues for data and management are empty */
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
+		/* data tx queue not empty */
+		return;
+
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
+		/* management tx queue not empty */
+		return;
+
+	/* check also whether received frames are pending */
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
+		/* data rx queue not empty */
+		return;
+
+	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
+		/* management rx queue not empty */
+		return;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
+#endif
+
+	/* all queues are empty, allow the device to go into sleep mode */
+	*powerstate = ISL38XX_PSM_POWERSAVE_STATE;
+
+	/* assert the Sleep interrupt in the Device Interrupt Register */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_handle_wakeup(isl38xx_control_block *control_block,
+		      int *powerstate, void *device_base)
+{
+	/* device is in active state, update the powerstate flag */
+	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+	/* now check whether there are frames pending for the card */
+	if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
+	    && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
+		return;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
+#endif
+
+	/* either data or management transmit queue has a frame pending
+	 * trigger the device by setting the Update bit in the Device Int reg */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+void
+isl38xx_trigger_device(int asleep, void *device_base)
+{
+	struct timeval current_time;
+	u32 reg, counter = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
+#endif
+
+	/* check whether the device is in power save mode */
+	if (asleep) {
+		/* device is in powersave, trigger the device for wakeup */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		do_gettimeofday(&current_time);
+		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
+		      current_time.tv_sec, current_time.tv_usec);
+#endif
+
+		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
+		      current_time.tv_sec, current_time.tv_usec,
+		      readl(device_base + ISL38XX_CTRL_STAT_REG));
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		if (reg = readl(device_base + ISL38XX_INT_IDENT_REG),
+		    reg == 0xabadface) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			do_gettimeofday(&current_time);
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device register abadface\n",
+			      current_time.tv_sec, current_time.tv_usec);
+#endif
+			/* read the Device Status Register until Sleepmode bit is set */
+			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
+			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
+				udelay(ISL38XX_WRITEIO_DELAY);
+				counter++;
+			}
+
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device register read %08x\n",
+			      current_time.tv_sec, current_time.tv_usec,
+			      readl(device_base + ISL38XX_CTRL_STAT_REG));
+			udelay(ISL38XX_WRITEIO_DELAY);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			do_gettimeofday(&current_time);
+			DEBUG(SHOW_TRACING,
+			      "%08li.%08li Device asleep counter %i\n",
+			      current_time.tv_sec, current_time.tv_usec,
+			      counter);
+#endif
+		}
+		/* assert the Wakeup interrupt in the Device Interrupt Register */
+		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		/* perform another read on the Device Status Register */
+		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		do_gettimeofday(&current_time);
+		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
+		      current_time.tv_sec, current_time.tv_usec, reg);
+#endif
+	} else {
+		/* device is (still) awake  */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING, "Device is in active state\n");
+#endif
+		/* trigger the device by setting the Update bit in the Device Int reg */
+
+		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+	}
+}
+
+void
+isl38xx_interface_reset(void *device_base, dma_addr_t host_address)
+{
+	u32 reg;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n");
+#endif
+
+	/* load the address of the control block in the device */
+	isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the reset bit in the Device Interrupt Register */
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET,
+			  ISL38XX_DEV_INT_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* enable the interrupt for detecting initialization */
+
+	/* Note: Do not enable other interrupts here. We want the
+	 * device to have come up first 100% before allowing any other 
+	 * interrupts. */
+	reg = ISL38XX_INT_IDENT_INIT;
+
+	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
+}
+
+void
+isl38xx_enable_common_interrupts(void *device_base) {
+	u32 reg;
+	reg = ( ISL38XX_INT_IDENT_UPDATE | 
+			ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
+	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
+	udelay(ISL38XX_WRITEIO_DELAY);
+}
+
+int
+isl38xx_in_queue(isl38xx_control_block *cb, int queue)
+{
+	const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
+			   le32_to_cpu(cb->device_curr_frag[queue]));
+
+	/* determine the amount of fragments in the queue depending on the type
+	 * of the queue, either transmit or receive */
+
+	BUG_ON(delta < 0);	/* driver ptr must be ahead of device ptr */
+
+	switch (queue) {
+		/* send queues */
+	case ISL38XX_CB_TX_MGMTQ:
+		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
+	case ISL38XX_CB_TX_DATA_LQ:
+	case ISL38XX_CB_TX_DATA_HQ:
+		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
+		return delta;
+		break;
+
+		/* receive queues */
+	case ISL38XX_CB_RX_MGMTQ:
+		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
+		return ISL38XX_CB_MGMT_QSIZE - delta;
+		break;
+
+	case ISL38XX_CB_RX_DATA_LQ:
+	case ISL38XX_CB_RX_DATA_HQ:
+		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
+		return ISL38XX_CB_RX_QSIZE - delta;
+		break;
+	}
+	BUG();
+	return 0;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.h linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_38xx.h
--- linux-2.4.27/drivers/net/wireless/prism54/isl_38xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_38xx.h	2004-08-15 19:51:12.000000000 +0000
@@ -0,0 +1,169 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _ISL_38XX_H
+#define _ISL_38XX_H
+
+#include <linux/version.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#define ISL38XX_CB_RX_QSIZE                     8
+#define ISL38XX_CB_TX_QSIZE                     32
+
+/* ISL38XX Access Point Specific definitions */
+#define ISL38XX_MAX_WDS_LINKS                   8
+
+/* ISL38xx Client Specific definitions */
+#define ISL38XX_PSM_ACTIVE_STATE                0
+#define ISL38XX_PSM_POWERSAVE_STATE             1
+
+/* ISL38XX Host Interface Definitions */
+#define ISL38XX_PCI_MEM_SIZE                    0x02000
+#define ISL38XX_MEMORY_WINDOW_SIZE              0x01000
+#define ISL38XX_DEV_FIRMWARE_ADDRES             0x20000
+#define ISL38XX_WRITEIO_DELAY                   10	/* in us */
+#define ISL38XX_RESET_DELAY                     50	/* in ms */
+#define ISL38XX_WAIT_CYCLE                      10	/* in 10ms */
+#define ISL38XX_MAX_WAIT_CYCLES                 10
+
+/* PCI Memory Area */
+#define ISL38XX_HARDWARE_REG                    0x0000
+#define ISL38XX_CARDBUS_CIS                     0x0800
+#define ISL38XX_DIRECT_MEM_WIN                  0x1000
+
+/* Hardware registers */
+#define ISL38XX_DEV_INT_REG                     0x0000
+#define ISL38XX_INT_IDENT_REG                   0x0010
+#define ISL38XX_INT_ACK_REG                     0x0014
+#define ISL38XX_INT_EN_REG                      0x0018
+#define ISL38XX_GEN_PURP_COM_REG_1              0x0020
+#define ISL38XX_GEN_PURP_COM_REG_2              0x0024
+#define ISL38XX_CTRL_BLK_BASE_REG               ISL38XX_GEN_PURP_COM_REG_1
+#define ISL38XX_DIR_MEM_BASE_REG                0x0030
+#define ISL38XX_CTRL_STAT_REG                   0x0078
+
+/* High end mobos queue up pci writes, the following
+ * is used to "read" from after a write to force flush */
+#define ISL38XX_PCI_POSTING_FLUSH		ISL38XX_INT_EN_REG
+
+/**
+ * isl38xx_w32_flush - PCI iomem write helper
+ * @base: (host) memory base address of the device
+ * @val: 32bit value (host order) to write
+ * @offset: byte offset into @base to write value to
+ * 
+ *  This helper takes care of writing a 32bit datum to the
+ *  specified offset into the device's pci memory space, and making sure 
+ *  the pci memory buffers get flushed by performing one harmless read 
+ *  from the %ISL38XX_PCI_POSTING_FLUSH offset.
+ */
+static inline void
+isl38xx_w32_flush(void *base, u32 val, unsigned long offset)
+{
+	writel(val, base + offset);
+	(void) readl(base + ISL38XX_PCI_POSTING_FLUSH);
+}
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET                   0x0001
+#define ISL38XX_DEV_INT_UPDATE                  0x0002
+#define ISL38XX_DEV_INT_WAKEUP                  0x0008
+#define ISL38XX_DEV_INT_SLEEP                   0x0010
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE                0x0002
+#define ISL38XX_INT_IDENT_INIT                  0x0004
+#define ISL38XX_INT_IDENT_WAKEUP                0x0008
+#define ISL38XX_INT_IDENT_SLEEP                 0x0010
+#define ISL38XX_INT_SOURCES                     0x001E
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE             0x00000200
+#define	ISL38XX_CTRL_STAT_CLKRUN		0x00800000
+#define ISL38XX_CTRL_STAT_RESET                 0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT               0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED           0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE         0x80000000
+
+/* Control Block definitions */
+#define ISL38XX_CB_RX_DATA_LQ                   0
+#define ISL38XX_CB_TX_DATA_LQ                   1
+#define ISL38XX_CB_RX_DATA_HQ                   2
+#define ISL38XX_CB_TX_DATA_HQ                   3
+#define ISL38XX_CB_RX_MGMTQ                     4
+#define ISL38XX_CB_TX_MGMTQ                     5
+#define ISL38XX_CB_QCOUNT                       6
+#define ISL38XX_CB_MGMT_QSIZE                   4
+#define ISL38XX_MIN_QTHRESHOLD                  4	/* fragments */
+
+/* Memory Manager definitions */
+#define MGMT_FRAME_SIZE                         1500	/* >= size struct obj_bsslist */
+#define MGMT_TX_FRAME_COUNT                     24	/* max 4 + spare 4 + 8 init */
+#define MGMT_RX_FRAME_COUNT                     24	/* 4*4 + spare 8 */
+#define MGMT_FRAME_COUNT                        (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT)
+#define CONTROL_BLOCK_SIZE                      1024	/* should be enough */
+#define PSM_FRAME_SIZE                          1536
+#define PSM_MINIMAL_STATION_COUNT               64
+#define PSM_FRAME_COUNT                         PSM_MINIMAL_STATION_COUNT
+#define PSM_BUFFER_SIZE                         PSM_FRAME_SIZE * PSM_FRAME_COUNT
+#define MAX_TRAP_RX_QUEUE                       4
+#define HOST_MEM_BLOCK                          CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE
+
+/* Fragment package definitions */
+#define FRAGMENT_FLAG_MF                        0x0001
+#define MAX_FRAGMENT_SIZE                       1536
+
+/* In monitor mode frames have a header. I don't know exactly how big those
+ * frame can be but I've never seen any frame bigger than 1584... :
+ */
+#define MAX_FRAGMENT_SIZE_RX	                1600
+
+typedef struct {
+	u32 address;		/* physical address on host */
+	u16 size;		/* packet size */
+	u16 flags;		/* set of bit-wise flags */
+} isl38xx_fragment;
+
+struct isl38xx_cb {
+	u32 driver_curr_frag[ISL38XX_CB_QCOUNT];
+	u32 device_curr_frag[ISL38XX_CB_QCOUNT];
+	isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE];
+	isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE];
+	isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE];
+	isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE];
+	isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
+	isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE];
+};
+
+typedef struct isl38xx_cb isl38xx_control_block;
+
+/* determine number of entries currently in queue */
+int isl38xx_in_queue(isl38xx_control_block *cb, int queue);
+
+void isl38xx_disable_interrupts(void *);
+void isl38xx_enable_common_interrupts(void *);
+
+void isl38xx_handle_sleep_request(isl38xx_control_block *, int *,
+				  void *);
+void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *);
+void isl38xx_trigger_device(int, void *);
+void isl38xx_interface_reset(void *, dma_addr_t);
+
+#endif				/* _ISL_38XX_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.c linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_ioctl.c
--- linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_ioctl.c	2004-08-15 19:50:58.000000000 +0000
@@ -0,0 +1,2261 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *            (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
+ *            (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/pci.h>
+
+#include <asm/uaccess.h>
+
+#include "prismcompat.h"
+#include "isl_ioctl.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"		/* additional types and defs for isl38xx fw */
+#include "oid_mgt.h"
+
+#include <net/iw_handler.h>	/* New driver API */
+
+static int init_mode = CARD_DEFAULT_IW_MODE;
+static int init_channel = CARD_DEFAULT_CHANNEL;
+static int init_wep = CARD_DEFAULT_WEP;
+static int init_filter = CARD_DEFAULT_FILTER;
+static int init_authen = CARD_DEFAULT_AUTHEN;
+static int init_dot1x = CARD_DEFAULT_DOT1X;
+static int init_conformance = CARD_DEFAULT_CONFORMANCE;
+static int init_mlme = CARD_DEFAULT_MLME_MODE;
+
+module_param(init_mode, int, 0);
+MODULE_PARM_DESC(init_mode,
+		 "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor");
+
+module_param(init_channel, int, 0);
+MODULE_PARM_DESC(init_channel,
+		 "Check `iwpriv ethx channel` for available channels");
+
+module_param(init_wep, int, 0);
+module_param(init_filter, int, 0);
+
+module_param(init_authen, int, 0);
+MODULE_PARM_DESC(init_authen,
+		 "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH");
+
+module_param(init_dot1x, int, 0);
+MODULE_PARM_DESC(init_dot1x,
+		 "\n0: None/not set	(Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
+
+module_param(init_mlme, int, 0);
+MODULE_PARM_DESC(init_mlme,
+		 "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED");
+
+/**
+ * prism54_mib_mode_helper - MIB change mode helper function
+ * @mib: the &struct islpci_mib object to modify
+ * @iw_mode: new mode (%IW_MODE_*)
+ * 
+ *  This is a helper function, hence it does not lock. Make sure
+ *  caller deals with locking *if* necessary. This function sets the 
+ *  mode-dependent mib values and does the mapping of the Linux 
+ *  Wireless API modes to Device firmware modes. It also checks for 
+ *  correct valid Linux wireless modes. 
+ */
+int
+prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
+{
+	u32 config = INL_CONFIG_MANUALRUN;
+	u32 mode, bsstype;
+
+	/* For now, just catch early the Repeater and Secondary modes here */
+	if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
+		printk(KERN_DEBUG
+		       "%s(): Sorry, Repeater mode and Secondary mode "
+		       "are not yet supported by this driver.\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	priv->iw_mode = iw_mode;
+
+	switch (iw_mode) {
+	case IW_MODE_AUTO:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_ANY;
+		break;
+	case IW_MODE_ADHOC:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_IBSS;
+		break;
+	case IW_MODE_INFRA:
+		mode = INL_MODE_CLIENT;
+		bsstype = DOT11_BSSTYPE_INFRA;
+		break;
+	case IW_MODE_MASTER:
+		mode = INL_MODE_AP;
+		bsstype = DOT11_BSSTYPE_INFRA;
+		break;
+	case IW_MODE_MONITOR:
+		mode = INL_MODE_PROMISCUOUS;
+		bsstype = DOT11_BSSTYPE_ANY;
+		config |= INL_CONFIG_RXANNEX;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (init_wds)
+		config |= INL_CONFIG_WDS;
+	mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
+	mgt_set(priv, OID_INL_CONFIG, &config);
+	mgt_set(priv, OID_INL_MODE, &mode);
+
+	return 0;
+}
+
+/**
+ * prism54_mib_init - fill MIB cache with defaults
+ *
+ *  this function initializes the struct given as @mib with defaults,
+ *  of which many are retrieved from the global module parameter
+ *  variables.  
+ */
+
+void
+prism54_mib_init(islpci_private *priv)
+{
+	u32 t;
+	struct obj_buffer psm_buffer = {
+		.size = PSM_BUFFER_SIZE,
+		.addr = priv->device_psm_buffer
+	};
+
+	mgt_set(priv, DOT11_OID_CHANNEL, &init_channel);
+	mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen);
+	mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep);
+
+	mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
+	mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter);
+	mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x);
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme);
+	mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance);
+
+	t = 127;
+	mgt_set(priv, OID_INL_OUTPUTPOWER, &t);
+
+	/* Important: we are setting a default wireless mode and we are 
+	 * forcing a valid one, so prism54_mib_mode_helper should just set
+	 * mib values depending on what the wireless mode given is. No need
+	 * for it save old values */
+	if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) {
+		printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. "
+		       "Using default mode\n", __FUNCTION__);
+		init_mode = CARD_DEFAULT_IW_MODE;
+	}
+	/* This sets all of the mode-dependent values */
+	prism54_mib_mode_helper(priv, init_mode);
+}
+
+/* this will be executed outside of atomic context thanks to
+ * schedule_work(), thus we can as well use sleeping semaphore
+ * locking */
+void
+prism54_update_stats(islpci_private *priv)
+{
+	char *data;
+	int j;
+	struct obj_bss bss, *bss2;
+	union oid_res_t r;
+
+	if (down_interruptible(&priv->stats_sem))
+		return;
+
+/* Noise floor.
+ * I'm not sure if the unit is dBm.
+ * Note : If we are not connected, this value seems to be irrelevant. */
+
+	mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+	priv->local_iwstatistics.qual.noise = r.u;
+
+/* Get the rssi of the link. To do this we need to retrieve a bss. */
+
+	/* First get the MAC address of the AP we are associated with. */
+	mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
+	data = r.ptr;
+
+	/* copy this MAC to the bss */
+	memcpy(bss.address, data, 6);
+	kfree(data);
+
+	/* now ask for the corresponding bss */
+	j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
+	bss2 = r.ptr;
+	/* report the rssi and use it to calculate
+	 *  link quality through a signal-noise
+	 *  ratio */
+	priv->local_iwstatistics.qual.level = bss2->rssi;
+	priv->local_iwstatistics.qual.qual =
+	    bss2->rssi - priv->iwstatistics.qual.noise;
+
+	kfree(bss2);
+
+	/* report that the stats are new */
+	priv->local_iwstatistics.qual.updated = 0x7;
+
+/* Rx : unable to decrypt the MPDU */
+	mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
+	priv->local_iwstatistics.discard.code = r.u;
+
+/* Tx : Max MAC retries num reached */
+	mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
+	priv->local_iwstatistics.discard.retries = r.u;
+
+	up(&priv->stats_sem);
+
+	return;
+}
+
+struct iw_statistics *
+prism54_get_wireless_stats(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	/* If the stats are being updated return old data */
+	if (down_trylock(&priv->stats_sem) == 0) {
+		memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
+		       sizeof (struct iw_statistics));
+		/* They won't be marked updated for the next time */
+		priv->local_iwstatistics.qual.updated = 0;
+		up(&priv->stats_sem);
+	} else
+		priv->iwstatistics.qual.updated = 0;
+
+	/* Update our wireless stats, but do not schedule to often 
+	 * (max 1 HZ) */
+	if ((priv->stats_timestamp == 0) ||
+	    time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
+		schedule_work(&priv->stats_work);
+		priv->stats_timestamp = jiffies;
+	}
+
+	return &priv->iwstatistics;
+}
+
+static int
+prism54_commit(struct net_device *ndev, struct iw_request_info *info,
+	       char *cwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	/* simply re-set the last set SSID, this should commit most stuff */
+
+	/* Commit in Monitor mode is not necessary, also setting essid
+	 * in Monitor mode does not make sense and isn't allowed for this
+	 * device's firmware */
+	if (priv->iw_mode != IW_MODE_MONITOR)
+		return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
+	return 0;
+}
+
+static int
+prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
+		 char *cwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	char *capabilities;
+	union oid_res_t r;
+	int rvalue;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		strncpy(cwrq, "NOT READY!", IFNAMSIZ);
+		return 0;
+	}
+	rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
+
+	switch (r.u) {
+	case INL_PHYCAP_5000MHZ:
+		capabilities = "IEEE 802.11a/b/g";
+		break;
+	case INL_PHYCAP_FAA:
+		capabilities = "IEEE 802.11b/g - FAA Support";
+		break;
+	case INL_PHYCAP_2400MHZ:
+	default:
+		capabilities = "IEEE 802.11b/g";	/* Default */
+		break;
+	}
+	strncpy(cwrq, capabilities, IFNAMSIZ);
+	return rvalue;
+}
+
+static int
+prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_freq *fwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int rvalue;
+	u32 c;
+
+	if (fwrq->m < 1000)
+		/* we have a channel number */
+		c = fwrq->m;
+	else
+		c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
+
+	rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
+
+	/* Call commit handler */
+	return (rvalue ? rvalue : -EINPROGRESS);
+}
+
+static int
+prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_freq *fwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
+
+	fwrq->m = r.u;
+	fwrq->e = 0;
+
+	return rvalue;
+}
+
+static int
+prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
+		 __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
+
+	/* Let's see if the user passed a valid Linux Wireless mode */
+	if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
+		printk(KERN_DEBUG
+		       "%s: %s() You passed a non-valid init_mode.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -EINVAL;
+	}
+
+	down_write(&priv->mib_sem);
+
+	if (prism54_mib_mode_helper(priv, *uwrq)) {
+		up_write(&priv->mib_sem);
+		return -EOPNOTSUPP;
+	}
+
+	/* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
+	 * extended one.
+	 */
+	if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
+		mlmeautolevel = DOT11_MLME_INTERMEDIATE;
+	if (priv->wpa)
+		mlmeautolevel = DOT11_MLME_EXTENDED;
+
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
+
+	mgt_commit(priv);
+	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
+	    ? priv->monitor_type : ARPHRD_ETHER;
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+/* Use mib cache */
+static int
+prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
+		 __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
+						  IW_MODE_MONITOR));
+	*uwrq = priv->iw_mode;
+
+	return 0;
+}
+
+/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
+ * emit data if (sensitivity > rssi - noise) (in dBm).
+ * prism54_set_sens does not seem to work.
+ */
+
+static int
+prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 sens;
+
+	/* by default  the card sets this to 20. */
+	sens = vwrq->disabled ? 20 : vwrq->value;
+
+	return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
+}
+
+static int
+prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
+
+	vwrq->value = r.u;
+	vwrq->disabled = (vwrq->value == 0);
+	vwrq->fixed = 1;
+
+	return rvalue;
+}
+
+static int
+prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	struct iw_range *range = (struct iw_range *) extra;
+	islpci_private *priv = netdev_priv(ndev);
+	char *data;
+	int i, m, rvalue;
+	struct obj_frequencies *freq;
+	union oid_res_t r;
+
+	memset(range, 0, sizeof (struct iw_range));
+	dwrq->length = sizeof (struct iw_range);
+
+	/* set the wireless extension version number */
+	range->we_version_source = SUPPORTED_WIRELESS_EXT;
+	range->we_version_compiled = WIRELESS_EXT;
+
+	/* Now the encoding capabilities */
+	range->num_encoding_sizes = 3;
+	/* 64(40) bits WEP */
+	range->encoding_size[0] = 5;
+	/* 128(104) bits WEP */
+	range->encoding_size[1] = 13;
+	/* 256 bits for WPA-PSK */
+	range->encoding_size[2] = 32;
+	/* 4 keys are allowed */
+	range->max_encoding_tokens = 4;
+
+	/* we don't know the quality range... */
+	range->max_qual.level = 0;
+	range->max_qual.noise = 0;
+	range->max_qual.qual = 0;
+	/* these value describe an average quality. Needs more tweaking... */
+	range->avg_qual.level = -80;	/* -80 dBm */
+	range->avg_qual.noise = 0;	/* don't know what to put here */
+	range->avg_qual.qual = 0;
+
+	range->sensitivity = 200;
+
+	/* retry limit capabilities */
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+
+	/* I don't know the range. Put stupid things here */
+	range->min_retry = 1;
+	range->max_retry = 65535;
+	range->min_r_time = 1024;
+	range->max_r_time = 65535 * 1024;
+
+	/* txpower is supported in dBm's */
+	range->txpower_capa = IW_TXPOW_DBM;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* Request the device for the supported frequencies
+	 * not really relevant since some devices will report the 5 GHz band
+	 * frequencies even if they don't support them.
+	 */
+	rvalue =
+	    mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
+	freq = r.ptr;
+
+	range->num_channels = freq->nr;
+	range->num_frequency = freq->nr;
+
+	m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
+	for (i = 0; i < m; i++) {
+		range->freq[i].m = freq->mhz[i];
+		range->freq[i].e = 6;
+		range->freq[i].i = channel_of_freq(freq->mhz[i]);
+	}
+	kfree(freq);
+
+	rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
+	data = r.ptr;
+
+	/* We got an array of char. It is NULL terminated. */
+	i = 0;
+	while ((i < IW_MAX_BITRATES) && (*data != 0)) {
+		/*       the result must be in bps. The card gives us 500Kbps */
+		range->bitrate[i] = (__s32) (*data >> 1);
+		range->bitrate[i] *= 1000000;
+		i++;
+		data++;
+	}
+	range->num_bitrates = i;
+	kfree(r.ptr);
+
+	return rvalue;
+}
+
+/* Set AP address*/
+
+static int
+prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	char bssid[6];
+	int rvalue;
+
+	if (awrq->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+
+	/* prepare the structure for the set object */
+	memcpy(&bssid[0], awrq->sa_data, 6);
+
+	/* set the bssid -- does this make sense when in AP mode? */
+	rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
+
+	return (rvalue ? rvalue : -EINPROGRESS);	/* Call commit handler */
+}
+
+/* get AP address*/
+
+static int
+prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
+	memcpy(awrq->sa_data, r.ptr, 6);
+	awrq->sa_family = ARPHRD_ETHER;
+	kfree(r.ptr);
+
+	return rvalue;
+}
+
+static int
+prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	/* hehe the device does this automagicaly */
+	return 0;
+}
+
+/* a little helper that will translate our data into a card independent
+ * format that the Wireless Tools will understand. This was inspired by
+ * the "Aironet driver for 4500 and 4800 series cards" (GPL)
+ */
+
+static char *
+prism54_translate_bss(struct net_device *ndev, char *current_ev,
+		      char *end_buf, struct obj_bss *bss, char noise)
+{
+	struct iw_event iwe;	/* Temporary buffer */
+	short cap;
+	islpci_private *priv = netdev_priv(ndev);
+
+	/* The first entry must be the MAC address */
+	memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	iwe.cmd = SIOCGIWAP;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* The following entries will be displayed in the same order we give them */
+
+	/* The ESSID. */
+	iwe.u.data.length = bss->ssid.length;
+	iwe.u.data.flags = 1;
+	iwe.cmd = SIOCGIWESSID;
+	current_ev = iwe_stream_add_point(current_ev, end_buf,
+					  &iwe, bss->ssid.octets);
+
+	/* Capabilities */
+#define CAP_ESS 0x01
+#define CAP_IBSS 0x02
+#define CAP_CRYPT 0x10
+
+	/* Mode */
+	cap = bss->capinfo;
+	iwe.u.mode = 0;
+	if (cap & CAP_ESS)
+		iwe.u.mode = IW_MODE_MASTER;
+	else if (cap & CAP_IBSS)
+		iwe.u.mode = IW_MODE_ADHOC;
+	iwe.cmd = SIOCGIWMODE;
+	if (iwe.u.mode)
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe,
+					 IW_EV_UINT_LEN);
+
+	/* Encryption capability */
+	if (cap & CAP_CRYPT)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	iwe.cmd = SIOCGIWENCODE;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
+
+	/* Add frequency. (short) bss->channel is the frequency in MHz */
+	iwe.u.freq.m = channel_of_freq(bss->channel);
+	iwe.u.freq.e = 0;
+	iwe.cmd = SIOCGIWFREQ;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+	/* Add quality statistics */
+	iwe.u.qual.level = bss->rssi;
+	iwe.u.qual.noise = noise;
+	/* do a simple SNR for quality */
+	iwe.u.qual.qual = bss->rssi - noise;
+	iwe.cmd = IWEVQUAL;
+	current_ev =
+	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+	if (priv->wpa) {
+		u8 wpa_ie[MAX_WPA_IE_LEN];
+		char *buf, *p;
+		size_t wpa_ie_len;
+		int i;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
+		if (wpa_ie_len > 0 &&
+		    (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
+			p = buf;
+			p += sprintf(p, "wpa_ie=");
+			for (i = 0; i < wpa_ie_len; i++) {
+				p += sprintf(p, "%02x", wpa_ie[i]);
+			}
+			memset(&iwe, 0, sizeof (iwe));
+			iwe.cmd = IWEVCUSTOM;
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			kfree(buf);
+		}
+	}
+	return current_ev;
+}
+
+int
+prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int i, rvalue;
+	struct obj_bsslist *bsslist;
+	u32 noise = 0;
+	char *current_ev = extra;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		/* device is not ready, fail gently */
+		dwrq->length = 0;
+		return 0;
+	}
+
+	/* first get the noise value. We will use it to report the link quality */
+	rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+	noise = r.u;
+
+	/* Ask the device for a list of known bss. We can report at most
+	 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
+	 * if you change the value of IWMAX_BSS=24.
+	 */
+	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
+	bsslist = r.ptr;
+
+	/* ok now, scan the list and translate its info */
+	for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
+		current_ev = prism54_translate_bss(ndev, current_ev,
+						   extra + IW_SCAN_MAX_DATA,
+						   &(bsslist->bsslist[i]),
+						   noise);
+	kfree(bsslist);
+	dwrq->length = (current_ev - extra);
+	dwrq->flags = 0;	/* todo */
+
+	return rvalue;
+}
+
+static int
+prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct obj_ssid essid;
+
+	memset(essid.octets, 0, 33);
+
+	/* Check if we were asked for `any' */
+	if (dwrq->flags && dwrq->length) {
+		if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
+			return -E2BIG;
+		essid.length = dwrq->length - 1;
+		memcpy(essid.octets, extra, dwrq->length);
+	} else
+		essid.length = 0;
+
+	if (priv->iw_mode != IW_MODE_MONITOR)
+		return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
+
+	/* If in monitor mode, just save to mib */
+	mgt_set(priv, DOT11_OID_SSID, &essid);
+	return 0;
+
+}
+
+static int
+prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct obj_ssid *essid;
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
+	essid = r.ptr;
+
+	if (essid->length) {
+		dwrq->flags = 1;	/* set ESSID to ON for Wireless Extensions */
+		/* if it is to big, trunk it */
+		dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1);
+	} else {
+		dwrq->flags = 0;
+		dwrq->length = 0;
+	}
+	essid->octets[essid->length] = '\0';
+	memcpy(extra, essid->octets, dwrq->length);
+	kfree(essid);
+
+	return rvalue;
+}
+
+/* Provides no functionality, just completes the ioctl. In essence this is a 
+ * just a cosmetic ioctl.
+ */
+static int
+prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	if (dwrq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	down_write(&priv->mib_sem);
+	memset(priv->nickname, 0, sizeof (priv->nickname));
+	memcpy(priv->nickname, extra, dwrq->length);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+static int
+prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	dwrq->length = 0;
+
+	down_read(&priv->mib_sem);
+	dwrq->length = strlen(priv->nickname) + 1;
+	memcpy(extra, priv->nickname, dwrq->length);
+	up_read(&priv->mib_sem);
+
+	return 0;
+}
+
+/* Set the allowed Bitrates */
+
+static int
+prism54_set_rate(struct net_device *ndev,
+		 struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+
+	islpci_private *priv = netdev_priv(ndev);
+	u32 rate, profile;
+	char *data;
+	int ret, i;
+	union oid_res_t r;
+
+	if (vwrq->value == -1) {
+		/* auto mode. No limit. */
+		profile = 1;
+		return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
+	}
+
+	if ((ret =
+	     mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r)))
+		return ret;
+
+	rate = (u32) (vwrq->value / 500000);
+	data = r.ptr;
+	i = 0;
+
+	while (data[i]) {
+		if (rate && (data[i] == rate)) {
+			break;
+		}
+		if (vwrq->value == i) {
+			break;
+		}
+		data[i] |= 0x80;
+		i++;
+	}
+
+	if (!data[i]) {
+		return -EINVAL;
+	}
+
+	data[i] |= 0x80;
+	data[i + 1] = 0;
+
+	/* Now, check if we want a fixed or auto value */
+	if (vwrq->fixed) {
+		data[0] = data[i];
+		data[1] = 0;
+	}
+
+/*
+	i = 0;
+	printk("prism54 rate: ");
+	while(data[i]) {
+		printk("%u ", data[i]);
+		i++;
+	}
+	printk("0\n");
+*/
+	profile = -1;
+	ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
+	ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
+	ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
+
+	kfree(r.ptr);
+
+	return ret;
+}
+
+/* Get the current bit rate */
+static int
+prism54_get_rate(struct net_device *ndev,
+		 struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int rvalue;
+	char *data;
+	union oid_res_t r;
+
+	/* Get the current bit rate */
+	if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
+		return rvalue;
+	vwrq->value = r.u * 500000;
+
+	/* request the device for the enabled rates */
+	if ((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r)))
+		return rvalue;
+	data = r.ptr;
+	vwrq->fixed = (data[0] != 0) && (data[1] == 0);
+	kfree(r.ptr);
+
+	return 0;
+}
+
+static int
+prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
+}
+
+static int
+prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	/* get the rts threshold */
+	rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
+	vwrq->value = r.u;
+
+	return rvalue;
+}
+
+static int
+prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
+}
+
+static int
+prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
+	vwrq->value = r.u;
+
+	return rvalue;
+}
+
+/* Here we have (min,max) = max retries for (small frames, big frames). Where
+ * big frame <=>  bigger than the rts threshold
+ * small frame <=>  smaller than the rts threshold
+ * This is not really the behavior expected by the wireless tool but it seems
+ * to be a common behavior in other drivers.
+ */
+
+static int
+prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 slimit = 0, llimit = 0;	/* short and long limit */
+	u32 lifetime = 0;
+	int rvalue = 0;
+
+	if (vwrq->disabled)
+		/* we cannot disable this feature */
+		return -EINVAL;
+
+	if (vwrq->flags & IW_RETRY_LIMIT) {
+		if (vwrq->flags & IW_RETRY_MIN)
+			slimit = vwrq->value;
+		else if (vwrq->flags & IW_RETRY_MAX)
+			llimit = vwrq->value;
+		else {
+			/* we are asked to set both */
+			slimit = vwrq->value;
+			llimit = vwrq->value;
+		}
+	}
+	if (vwrq->flags & IW_RETRY_LIFETIME)
+		/* Wireless tools use us unit while the device uses 1024 us unit */
+		lifetime = vwrq->value / 1024;
+
+	/* now set what is requested */
+	if (slimit)
+		rvalue =
+		    mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
+	if (llimit)
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
+	if (lifetime)
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
+				    &lifetime);
+	return rvalue;
+}
+
+static int
+prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue = 0;
+	vwrq->disabled = 0;	/* It cannot be disabled */
+
+	if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		/* we are asked for the life time */
+		rvalue =
+		    mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
+		vwrq->value = r.u * 1024;
+		vwrq->flags = IW_RETRY_LIFETIME;
+	} else if ((vwrq->flags & IW_RETRY_MAX)) {
+		/* we are asked for the long retry limit */
+		rvalue |=
+		    mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
+		vwrq->value = r.u;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+	} else {
+		/* default. get the  short retry limit */
+		rvalue |=
+		    mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
+		vwrq->value = r.u;
+		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+	}
+
+	return rvalue;
+}
+
+static int
+prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int rvalue = 0, force = 0;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+	union oid_res_t r;
+
+	/* with the new API, it's impossible to get a NULL pointer.
+	 * New version of iwconfig set the IW_ENCODE_NOKEY flag
+	 * when no key is given, but older versions don't. */
+
+	if (dwrq->length > 0) {
+		/* we have a key to set */
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		int current_index;
+		struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+
+		/* get the current key index */
+		rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		current_index = r.u;
+		/* Verify that the key is not marked as invalid */
+		if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+			key.length = dwrq->length > sizeof (key.key) ?
+			    sizeof (key.key) : dwrq->length;
+			memcpy(key.key, extra, key.length);
+			if (key.length == 32)
+				/* we want WPA-PSK */
+				key.type = DOT11_PRIV_TKIP;
+			if ((index < 0) || (index > 3))
+				/* no index provided use the current one */
+				index = current_index;
+
+			/* now send the key to the card  */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
+					    &key);
+		}
+		/*
+		 * If a valid key is set, encryption should be enabled 
+		 * (user may turn it off later).
+		 * This is also how "iwconfig ethX key on" works
+		 */
+		if ((index == current_index) && (key.length > 0))
+			force = 1;
+	} else {
+		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+		if ((index >= 0) && (index <= 3)) {
+			/* we want to set the key index */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
+					    &index);
+		} else {
+			if (!dwrq->flags & IW_ENCODE_MODE) {
+				/* we cannot do anything. Complain. */
+				return -EINVAL;
+			}
+		}
+	}
+	/* now read the flags */
+	if (dwrq->flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled, 
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (dwrq->flags & IW_ENCODE_OPEN)
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+	/* do the change if requested  */
+	if ((dwrq->flags & IW_ENCODE_MODE) || force) {
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+				    &exunencrypt);
+	}
+	return rvalue;
+}
+
+static int
+prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct obj_key *key;
+	u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+	u32 authen = 0, invoke = 0, exunencrypt = 0;
+	int rvalue;
+	union oid_res_t r;
+
+	/* first get the flags */
+	rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	invoke = r.u;
+	rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+
+	if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
+		dwrq->flags = IW_ENCODE_RESTRICTED;
+	else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
+		if (invoke)
+			dwrq->flags = IW_ENCODE_OPEN;
+		else
+			dwrq->flags = IW_ENCODE_DISABLED;
+	} else
+		/* The card should not work in this state */
+		dwrq->flags = 0;
+
+	/* get the current device key index */
+	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+	devindex = r.u;
+	/* Now get the key, return it */
+	if ((index < 0) || (index > 3))
+		/* no index provided, use the current one */
+		index = devindex;
+	rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
+	key = r.ptr;
+	dwrq->length = key->length;
+	memcpy(extra, key->key, dwrq->length);
+	kfree(key);
+	/* return the used key index */
+	dwrq->flags |= devindex + 1;
+
+	return rvalue;
+}
+
+static int
+prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
+		    struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
+	/* intersil firmware operates in 0.25 dBm (1/4 dBm) */
+	vwrq->value = (s32) r.u / 4;
+	vwrq->fixed = 1;
+	/* radio is not turned of
+	 * btw: how is possible to turn off only the radio 
+	 */
+	vwrq->disabled = 0;
+
+	return rvalue;
+}
+
+static int
+prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
+		    struct iw_param *vwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	s32 u = vwrq->value;
+
+	/* intersil firmware operates in 0.25 dBm (1/4) */
+	u *= 4;
+	if (vwrq->disabled) {
+		/* don't know how to disable radio */
+		printk(KERN_DEBUG
+		       "%s: %s() disabling radio is not yet supported.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -ENOTSUPP;
+	} else if (vwrq->fixed)
+		/* currently only fixed value is supported */
+		return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
+	else {
+		printk(KERN_DEBUG
+		       "%s: %s() auto power will be implemented later.\n",
+		       priv->ndev->name, __FUNCTION__);
+		return -ENOTSUPP;
+	}
+}
+
+static int
+prism54_reset(struct net_device *ndev, struct iw_request_info *info,
+	      __u32 * uwrq, char *extra)
+{
+	islpci_reset(netdev_priv(ndev), 0);
+
+	return 0;
+}
+
+static int
+prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
+{
+	union oid_res_t r;
+	int rvalue;
+	enum oid_num_t n = dwrq->flags;
+
+	rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
+	dwrq->length = mgt_response_to_str(n, &r, extra);
+	if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
+		kfree(r.ptr);
+	return rvalue;
+}
+
+static int
+prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
+{
+	u32 oid = uwrq[0], u = uwrq[1];
+
+	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
+}
+
+static int
+prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
+{
+	u32 oid = dwrq->flags;
+
+	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
+}
+
+void
+prism54_acl_init(struct islpci_acl *acl)
+{
+	sema_init(&acl->sem, 1);
+	INIT_LIST_HEAD(&acl->mac_list);
+	acl->size = 0;
+	acl->policy = MAC_POLICY_OPEN;
+}
+
+static void
+prism54_clear_mac(struct islpci_acl *acl)
+{
+	struct list_head *ptr, *next;
+	struct mac_entry *entry;
+
+	if (down_interruptible(&acl->sem))
+		return;
+
+	if (acl->size == 0) {
+		up(&acl->sem);
+		return;
+	}
+
+	for (ptr = acl->mac_list.next, next = ptr->next;
+	     ptr != &acl->mac_list; ptr = next, next = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+		list_del(ptr);
+		kfree(entry);
+	}
+	acl->size = 0;
+	up(&acl->sem);
+}
+
+void
+prism54_acl_clean(struct islpci_acl *acl)
+{
+	prism54_clear_mac(acl);
+}
+
+static int
+prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
+	if (entry == NULL)
+		return -ENOMEM;
+
+	memcpy(entry->addr, addr->sa_data, ETH_ALEN);
+
+	if (down_interruptible(&acl->sem)) {
+		kfree(entry);
+		return -ERESTARTSYS;
+	}
+	list_add_tail(&entry->_list, &acl->mac_list);
+	acl->size++;
+	up(&acl->sem);
+
+	return 0;
+}
+
+static int
+prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct sockaddr *awrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct list_head *ptr;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+
+		if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
+			list_del(ptr);
+			acl->size--;
+			kfree(entry);
+			up(&acl->sem);
+			return 0;
+		}
+	}
+	up(&acl->sem);
+	return -EINVAL;
+}
+
+static int
+prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
+		struct iw_point *dwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_acl *acl = &priv->acl;
+	struct mac_entry *entry;
+	struct list_head *ptr;
+	struct sockaddr *dst = (struct sockaddr *) extra;
+
+	dwrq->length = 0;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+
+		memcpy(dst->sa_data, entry->addr, ETH_ALEN);
+		dst->sa_family = ARPHRD_ETHER;
+		dwrq->length++;
+		dst++;
+	}
+	up(&acl->sem);
+	return 0;
+}
+
+/* Setting policy also clears the MAC acl, even if we don't change the defaut
+ * policy
+ */
+
+static int
+prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_acl *acl = &priv->acl;
+	u32 mlmeautolevel;
+
+	prism54_clear_mac(acl);
+
+	if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
+		return -EINVAL;
+
+	down_write(&priv->mib_sem);
+
+	acl->policy = *uwrq;
+
+	/* the ACL code needs an intermediate mlmeautolevel */
+	if ((priv->iw_mode == IW_MODE_MASTER) &&
+	    (acl->policy != MAC_POLICY_OPEN))
+		mlmeautolevel = DOT11_MLME_INTERMEDIATE;
+	else
+		mlmeautolevel = CARD_DEFAULT_MLME_MODE;
+	if (priv->wpa)
+		mlmeautolevel = DOT11_MLME_EXTENDED;
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
+	/* restart the card with our new policy */
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+static int
+prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
+		   __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_acl *acl = &priv->acl;
+
+	*uwrq = acl->policy;
+
+	return 0;
+}
+
+/* Return 1 only if client should be accepted. */
+
+static int
+prism54_mac_accept(struct islpci_acl *acl, char *mac)
+{
+	struct list_head *ptr;
+	struct mac_entry *entry;
+	int res = 0;
+
+	if (down_interruptible(&acl->sem))
+		return -ERESTARTSYS;
+
+	if (acl->policy == MAC_POLICY_OPEN) {
+		up(&acl->sem);
+		return 1;
+	}
+
+	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
+		entry = list_entry(ptr, struct mac_entry, _list);
+		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
+			res = 1;
+			break;
+		}
+	}
+	res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
+	up(&acl->sem);
+
+	return res;
+}
+
+static int
+prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
+		 struct iw_point *dwrq, char *extra)
+{
+	struct obj_mlme *mlme;
+	int rvalue;
+
+	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
+	if (mlme == NULL)
+		return -ENOMEM;
+
+	/* Tell the card to kick every client */
+	mlme->id = 0;
+	rvalue =
+	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
+	kfree(mlme);
+
+	return rvalue;
+}
+
+static int
+prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
+		 struct sockaddr *awrq, char *extra)
+{
+	struct obj_mlme *mlme;
+	struct sockaddr *addr = (struct sockaddr *) extra;
+	int rvalue;
+
+	if (addr->sa_family != ARPHRD_ETHER)
+		return -EOPNOTSUPP;
+
+	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
+	if (mlme == NULL)
+		return -ENOMEM;
+
+	/* Tell the card to only kick the corresponding bastard */
+	memcpy(mlme->address, addr->sa_data, ETH_ALEN);
+	mlme->id = -1;
+	rvalue =
+	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
+
+	kfree(mlme);
+
+	return rvalue;
+}
+
+/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
+
+static void
+format_event(islpci_private *priv, char *dest, const char *str,
+	     const struct obj_mlme *mlme, u16 *length, int error)
+{
+	const u8 *a = mlme->address;
+	int n = snprintf(dest, IW_CUSTOM_MAX,
+			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
+			 str,
+			 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
+			 a[0], a[1], a[2], a[3], a[4], a[5],
+			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
+			  : ""), mlme->code);
+	BUG_ON(n > IW_CUSTOM_MAX);
+	*length = n;
+}
+
+static void
+send_formatted_event(islpci_private *priv, const char *str,
+		     const struct obj_mlme *mlme, int error)
+{
+	union iwreq_data wrqu;
+
+	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!wrqu.data.pointer)
+		return;
+	wrqu.data.length = 0;
+	format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,
+		     error);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
+	kfree(wrqu.data.pointer);
+}
+
+static void
+send_simple_event(islpci_private *priv, const char *str)
+{
+	union iwreq_data wrqu;
+	int n = strlen(str);
+
+	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+	if (!wrqu.data.pointer)
+		return;
+	BUG_ON(n > IW_CUSTOM_MAX);
+	wrqu.data.length = n;
+	strcpy(wrqu.data.pointer, str);
+	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);
+	kfree(wrqu.data.pointer);
+}
+
+static void
+link_changed(struct net_device *ndev, u32 bitrate)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	if (bitrate) {
+		if (priv->iw_mode == IW_MODE_INFRA) {
+			union iwreq_data uwrq;
+			prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
+					NULL);
+			wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
+		} else
+			send_simple_event(netdev_priv(ndev),
+					  "Link established");
+	} else
+		send_simple_event(netdev_priv(ndev), "Link lost");
+}
+
+/* Beacon/ProbeResp payload header */
+struct ieee80211_beacon_phdr {
+	u8 timestamp[8];
+	u16 beacon_int;
+	u16 capab_info;
+} __attribute__ ((packed));
+
+#define WLAN_EID_GENERIC 0xdd
+static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+void
+prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+		   u8 *wpa_ie, size_t wpa_ie_len)
+{
+	struct list_head *ptr;
+	struct islpci_bss_wpa_ie *bss = NULL;
+
+	if (wpa_ie_len > MAX_WPA_IE_LEN)
+		wpa_ie_len = MAX_WPA_IE_LEN;
+
+	if (down_interruptible(&priv->wpa_sem))
+		return;
+
+	/* try to use existing entry */
+	list_for_each(ptr, &priv->bss_wpa_list) {
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+			list_move(&bss->list, &priv->bss_wpa_list);
+			break;
+		}
+		bss = NULL;
+	}
+
+	if (bss == NULL) {
+		/* add a new BSS entry; if max number of entries is already
+		 * reached, replace the least recently updated */
+		if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
+			bss = list_entry(priv->bss_wpa_list.prev,
+					 struct islpci_bss_wpa_ie, list);
+			list_del(&bss->list);
+		} else {
+			bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
+			if (bss != NULL) {
+				priv->num_bss_wpa++;
+				memset(bss, 0, sizeof (*bss));
+			}
+		}
+		if (bss != NULL) {
+			memcpy(bss->bssid, bssid, ETH_ALEN);
+			list_add(&bss->list, &priv->bss_wpa_list);
+		}
+	}
+
+	if (bss != NULL) {
+		memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
+		bss->wpa_ie_len = wpa_ie_len;
+		bss->last_update = jiffies;
+	} else {
+		printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
+		       "\n", MAC2STR(bssid));
+	}
+
+	/* expire old entries from WPA list */
+	while (priv->num_bss_wpa > 0) {
+		bss = list_entry(priv->bss_wpa_list.prev,
+				 struct islpci_bss_wpa_ie, list);
+		if (!time_after(jiffies, bss->last_update + 60 * HZ))
+			break;
+
+		list_del(&bss->list);
+		priv->num_bss_wpa--;
+		kfree(bss);
+	}
+
+	up(&priv->wpa_sem);
+}
+
+size_t
+prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+{
+	struct list_head *ptr;
+	struct islpci_bss_wpa_ie *bss = NULL;
+	size_t len = 0;
+
+	if (down_interruptible(&priv->wpa_sem))
+		return 0;
+
+	list_for_each(ptr, &priv->bss_wpa_list) {
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			break;
+		bss = NULL;
+	}
+	if (bss) {
+		len = bss->wpa_ie_len;
+		memcpy(wpa_ie, bss->wpa_ie, len);
+	}
+	up(&priv->wpa_sem);
+
+	return len;
+}
+
+void
+prism54_wpa_ie_init(islpci_private *priv)
+{
+	INIT_LIST_HEAD(&priv->bss_wpa_list);
+	sema_init(&priv->wpa_sem, 1);
+}
+
+void
+prism54_wpa_ie_clean(islpci_private *priv)
+{
+	struct list_head *ptr, *n;
+
+	list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
+		struct islpci_bss_wpa_ie *bss;
+		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+		kfree(bss);
+	}
+}
+
+static void
+prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
+			 u8 *payload, size_t len)
+{
+	struct ieee80211_beacon_phdr *hdr;
+	u8 *pos, *end;
+
+	if (!priv->wpa)
+		return;
+
+	hdr = (struct ieee80211_beacon_phdr *) payload;
+	pos = (u8 *) (hdr + 1);
+	end = payload + len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end) {
+			printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
+			       "for " MACSTR "\n", MAC2STR(addr));
+			return;
+		}
+		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
+		    memcmp(pos + 2, wpa_oid, 4) == 0) {
+			prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+			return;
+		}
+		pos += 2 + pos[1];
+	}
+}
+
+static void
+handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
+{
+	if (((mlme->state == DOT11_STATE_AUTHING) ||
+	     (mlme->state == DOT11_STATE_ASSOCING))
+	    && mgt_mlme_answer(priv)) {
+		/* Someone is requesting auth and we must respond. Just send back
+		 * the trap with error code set accordingly.
+		 */
+		mlme->code = prism54_mac_accept(&priv->acl,
+						mlme->address) ? 0 : 1;
+		mgt_set_request(priv, oid, 0, mlme);
+	}
+}
+
+int
+prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
+			    char *data)
+{
+	struct obj_mlme *mlme = (struct obj_mlme *) data;
+	size_t len;
+	u8 *payload, *pos = (u8 *) (mlme + 1);
+
+	len = pos[0] | (pos[1] << 8);	/* little endian data length */
+	payload = pos + 2;
+
+	/* I think all trapable objects are listed here.
+	 * Some oids have a EX version. The difference is that they are emitted
+	 * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
+	 * with more info.
+	 * The few events already defined by the wireless tools are not really
+	 * suited. We use the more flexible custom event facility.
+	 */
+
+	/* I fear prism54_process_bss_data won't work with big endian data */
+	if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
+		prism54_process_bss_data(priv, oid, mlme->address,
+					 payload, len);
+
+	mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
+
+	switch (oid) {
+
+	case GEN_OID_LINKSTATE:
+		link_changed(priv->ndev, (u32) *data);
+		break;
+
+	case DOT11_OID_MICFAILURE:
+		send_simple_event(priv, "Mic failure");
+		break;
+
+	case DOT11_OID_DEAUTHENTICATE:
+		send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
+		break;
+
+	case DOT11_OID_AUTHENTICATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		break;
+
+	case DOT11_OID_DISASSOCIATE:
+		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		break;
+
+	case DOT11_OID_ASSOCIATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Associate request", mlme, 1);
+		break;
+
+	case DOT11_OID_REASSOCIATE:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "ReAssociate request", mlme, 1);
+		break;
+
+	case DOT11_OID_BEACON:
+		send_formatted_event(priv,
+				     "Received a beacon from an unkown AP",
+				     mlme, 0);
+		break;
+
+	case DOT11_OID_PROBE:
+		/* we received a probe from a client. */
+		send_formatted_event(priv, "Received a probe from client", mlme,
+				     0);
+		break;
+
+		/* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
+		 * is backward compatible layout-wise with "struct obj_mlme".
+		 */
+
+	case DOT11_OID_DEAUTHENTICATEEX:
+		send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
+		break;
+
+	case DOT11_OID_AUTHENTICATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		break;
+
+	case DOT11_OID_DISASSOCIATEEX:
+		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		break;
+
+	case DOT11_OID_ASSOCIATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Associate request", mlme, 1);
+		break;
+
+	case DOT11_OID_REASSOCIATEEX:
+		handle_request(priv, mlme, oid);
+		send_formatted_event(priv, "Reassociate request", mlme, 1);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Process a device trap.  This is called via schedule_work(), outside of
+ * interrupt context, no locks held.
+ */
+void
+prism54_process_trap(void *data)
+{
+	struct islpci_mgmtframe *frame = data;
+	struct net_device *ndev = frame->ndev;
+	enum oid_num_t n = mgt_oidtonum(frame->header->oid);
+
+	if (n != OID_NUM_LAST)
+		prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
+	islpci_mgt_release(frame);
+}
+
+int
+prism54_set_mac_address(struct net_device *ndev, void *addr)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int ret;
+
+	if (ndev->addr_len != 6)
+		return -EINVAL;
+	ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
+			      &((struct sockaddr *) addr)->sa_data);
+	if (!ret)
+		memcpy(priv->ndev->dev_addr,
+		       &((struct sockaddr *) addr)->sa_data, 6);
+
+	return ret;
+}
+
+int
+prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	down_write(&priv->mib_sem);
+
+	priv->wpa = *uwrq;
+	if (priv->wpa) {
+		u32 l = DOT11_MLME_EXTENDED;
+		mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l);
+	}
+	/* restart the card with new level. Needed ? */
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+
+	return 0;
+}
+
+int
+prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
+		__u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	*uwrq = priv->wpa;
+	return 0;
+}
+
+int
+prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+		     __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	priv->monitor_type =
+	    (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
+	if (priv->iw_mode == IW_MODE_MONITOR)
+		priv->ndev->type = priv->monitor_type;
+
+	return 0;
+}
+
+int
+prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
+		     __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	*uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
+	return 0;
+}
+
+int
+prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
+		  __u32 * uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	priv->priv_oid = *uwrq;
+	printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
+
+	return 0;
+}
+
+int
+prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
+		      struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_mgmtframe *response = NULL;
+	int ret = -EIO, response_op = PIMFOR_OP_ERROR;
+
+	printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
+	data->length = 0;
+
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret =
+		    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+					   priv->priv_oid, extra, 256,
+					   &response);
+		response_op = response->header->operation;
+		printk("%s: ret: %i\n", ndev->name, ret);
+		printk("%s: response_op: %i\n", ndev->name, response_op);
+		if (ret || !response
+		    || response->header->operation == PIMFOR_OP_ERROR) {
+			if (response) {
+				islpci_mgt_release(response);
+			}
+			printk("%s: EIO\n", ndev->name);
+			ret = -EIO;
+		}
+		if (!ret) {
+			data->length = response->header->length;
+			memcpy(extra, response->data, data->length);
+			islpci_mgt_release(response);
+			printk("%s: len: %i\n", ndev->name, data->length);
+		}
+	}
+
+	return ret;
+}
+
+int
+prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
+		      struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct islpci_mgmtframe *response = NULL;
+	int ret = 0, response_op = PIMFOR_OP_ERROR;
+
+	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
+	       data->length);
+
+	if (islpci_get_state(priv) >= PRV_STATE_INIT) {
+		ret =
+		    islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+					   priv->priv_oid, extra, data->length,
+					   &response);
+		printk("%s: ret: %i\n", ndev->name, ret);
+		if (!ret) {
+			response_op = response->header->operation;
+			printk("%s: response_op: %i\n", ndev->name,
+			       response_op);
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR) {
+			printk("%s: EIO\n", ndev->name);
+			ret = -EIO;
+		}
+	}
+
+	return (ret ? ret : -EINPROGRESS);
+}
+
+static int
+prism54_set_spy(struct net_device *ndev,
+		struct iw_request_info *info,
+		union iwreq_data *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 u, oid = OID_INL_CONFIG;
+
+	down_write(&priv->mib_sem);
+	mgt_get(priv, OID_INL_CONFIG, &u);
+
+	if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
+		/* disable spy */
+		u &= ~INL_CONFIG_RXANNEX;
+	else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
+		/* enable spy */
+		u |= INL_CONFIG_RXANNEX;
+
+	mgt_set(priv, OID_INL_CONFIG, &u);
+	mgt_commit_list(priv, &oid, 1);
+	up_write(&priv->mib_sem);
+
+	return iw_handler_set_spy(ndev, info, uwrq, extra);
+}
+
+static const iw_handler prism54_handler[] = {
+	(iw_handler) prism54_commit,	/* SIOCSIWCOMMIT */
+	(iw_handler) prism54_get_name,	/* SIOCGIWNAME */
+	(iw_handler) NULL,	/* SIOCSIWNWID */
+	(iw_handler) NULL,	/* SIOCGIWNWID */
+	(iw_handler) prism54_set_freq,	/* SIOCSIWFREQ */
+	(iw_handler) prism54_get_freq,	/* SIOCGIWFREQ */
+	(iw_handler) prism54_set_mode,	/* SIOCSIWMODE */
+	(iw_handler) prism54_get_mode,	/* SIOCGIWMODE */
+	(iw_handler) prism54_set_sens,	/* SIOCSIWSENS */
+	(iw_handler) prism54_get_sens,	/* SIOCGIWSENS */
+	(iw_handler) NULL,	/* SIOCSIWRANGE */
+	(iw_handler) prism54_get_range,	/* SIOCGIWRANGE */
+	(iw_handler) NULL,	/* SIOCSIWPRIV */
+	(iw_handler) NULL,	/* SIOCGIWPRIV */
+	(iw_handler) NULL,	/* SIOCSIWSTATS */
+	(iw_handler) NULL,	/* SIOCGIWSTATS */
+	prism54_set_spy,	/* SIOCSIWSPY */
+	iw_handler_get_spy,	/* SIOCGIWSPY */
+	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
+	(iw_handler) prism54_set_wap,	/* SIOCSIWAP */
+	(iw_handler) prism54_get_wap,	/* SIOCGIWAP */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* SIOCGIWAPLIST depreciated */
+	(iw_handler) prism54_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) prism54_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) prism54_set_essid,	/* SIOCSIWESSID */
+	(iw_handler) prism54_get_essid,	/* SIOCGIWESSID */
+	(iw_handler) prism54_set_nick,	/* SIOCSIWNICKN */
+	(iw_handler) prism54_get_nick,	/* SIOCGIWNICKN */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) prism54_set_rate,	/* SIOCSIWRATE */
+	(iw_handler) prism54_get_rate,	/* SIOCGIWRATE */
+	(iw_handler) prism54_set_rts,	/* SIOCSIWRTS */
+	(iw_handler) prism54_get_rts,	/* SIOCGIWRTS */
+	(iw_handler) prism54_set_frag,	/* SIOCSIWFRAG */
+	(iw_handler) prism54_get_frag,	/* SIOCGIWFRAG */
+	(iw_handler) prism54_set_txpower,	/* SIOCSIWTXPOW */
+	(iw_handler) prism54_get_txpower,	/* SIOCGIWTXPOW */
+	(iw_handler) prism54_set_retry,	/* SIOCSIWRETRY */
+	(iw_handler) prism54_get_retry,	/* SIOCGIWRETRY */
+	(iw_handler) prism54_set_encode,	/* SIOCSIWENCODE */
+	(iw_handler) prism54_get_encode,	/* SIOCGIWENCODE */
+	(iw_handler) NULL,	/* SIOCSIWPOWER */
+	(iw_handler) NULL,	/* SIOCGIWPOWER */
+};
+
+/* The low order bit identify a SET (0) or a GET (1) ioctl.  */
+
+#define PRISM54_RESET		SIOCIWFIRSTPRIV
+#define PRISM54_GET_POLICY	SIOCIWFIRSTPRIV+1
+#define PRISM54_SET_POLICY	SIOCIWFIRSTPRIV+2
+#define PRISM54_GET_MAC		SIOCIWFIRSTPRIV+3
+#define PRISM54_ADD_MAC		SIOCIWFIRSTPRIV+4
+
+#define PRISM54_DEL_MAC		SIOCIWFIRSTPRIV+6
+
+#define PRISM54_KICK_MAC	SIOCIWFIRSTPRIV+8
+
+#define PRISM54_KICK_ALL	SIOCIWFIRSTPRIV+10
+
+#define PRISM54_GET_WPA		SIOCIWFIRSTPRIV+11
+#define PRISM54_SET_WPA		SIOCIWFIRSTPRIV+12
+
+#define PRISM54_DBG_OID		SIOCIWFIRSTPRIV+14
+#define PRISM54_DBG_GET_OID	SIOCIWFIRSTPRIV+15
+#define PRISM54_DBG_SET_OID	SIOCIWFIRSTPRIV+16
+
+#define PRISM54_GET_OID		SIOCIWFIRSTPRIV+17
+#define PRISM54_SET_OID_U32	SIOCIWFIRSTPRIV+18
+#define	PRISM54_SET_OID_STR	SIOCIWFIRSTPRIV+20
+#define	PRISM54_SET_OID_ADDR	SIOCIWFIRSTPRIV+22
+
+#define PRISM54_GET_PRISMHDR	SIOCIWFIRSTPRIV+23
+#define PRISM54_SET_PRISMHDR	SIOCIWFIRSTPRIV+24
+
+#define IWPRIV_SET_U32(n,x)	{ n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_SSID(n,x)	{ n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_SET_ADDR(n,x)	{ n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
+#define IWPRIV_GET(n,x)	{ n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
+
+#define IWPRIV_U32(n,x)		IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
+#define IWPRIV_SSID(n,x)	IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
+#define IWPRIV_ADDR(n,x)	IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
+
+/* Note : limited to 128 private ioctls (wireless tools 26) */
+
+static const struct iw_priv_args prism54_private_args[] = {
+/*{ cmd, set_args, get_args, name } */
+	{PRISM54_RESET, 0, 0, "reset"},
+	{PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_prismhdr"},
+	{PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "set_prismhdr"},
+	{PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getPolicy"},
+	{PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "setPolicy"},
+	{PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
+	{PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "addMac"},
+	{PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "delMac"},
+	{PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "kickMac"},
+	{PRISM54_KICK_ALL, 0, 0, "kickAll"},
+	{PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_wpa"},
+	{PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "set_wpa"},
+	{PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+	 "dbg_oid"},
+	{PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
+	{PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
+	/* --- sub-ioctls handlers --- */
+	{PRISM54_GET_OID,
+	 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
+	{PRISM54_SET_OID_U32,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	{PRISM54_SET_OID_STR,
+	 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	{PRISM54_SET_OID_ADDR,
+	 IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
+	/* --- sub-ioctls definitions --- */
+	IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
+	IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
+	IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
+	IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
+	IWPRIV_U32(DOT11_OID_STATE, "state"),
+	IWPRIV_U32(DOT11_OID_AID, "aid"),
+
+	IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
+
+	IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
+	IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
+	IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
+
+	IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
+	IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
+	IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
+
+	IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
+
+	IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
+	IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
+	IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
+	IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
+	IWPRIV_U32(DOT11_OID_PSM, "psm"),
+
+	IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
+	IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
+	IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
+	IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
+	IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
+	IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
+	IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
+	IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
+	IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
+	IWPRIV_GET(DOT11_OID_RATES, "rates"),
+	IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
+	IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
+	IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
+
+	IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
+	IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
+	IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
+	IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
+	IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
+	IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
+
+	IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
+	IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
+	IWPRIV_U32(OID_INL_MODE, "mode"),
+	IWPRIV_U32(OID_INL_CONFIG, "config"),
+	IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
+	IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
+	IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
+};
+
+static const iw_handler prism54_private_handler[] = {
+	(iw_handler) prism54_reset,
+	(iw_handler) prism54_get_policy,
+	(iw_handler) prism54_set_policy,
+	(iw_handler) prism54_get_mac,
+	(iw_handler) prism54_add_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_del_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_kick_mac,
+	(iw_handler) NULL,
+	(iw_handler) prism54_kick_all,
+	(iw_handler) prism54_get_wpa,
+	(iw_handler) prism54_set_wpa,
+	(iw_handler) NULL,
+	(iw_handler) prism54_debug_oid,
+	(iw_handler) prism54_debug_get_oid,
+	(iw_handler) prism54_debug_set_oid,
+	(iw_handler) prism54_get_oid,
+	(iw_handler) prism54_set_u32,
+	(iw_handler) NULL,
+	(iw_handler) prism54_set_raw,
+	(iw_handler) NULL,
+	(iw_handler) prism54_set_raw,
+	(iw_handler) prism54_get_prismhdr,
+	(iw_handler) prism54_set_prismhdr,
+};
+
+const struct iw_handler_def prism54_handler_def = {
+	.num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
+	.num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
+	.num_private_args =
+	    sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
+	.standard = (iw_handler *) prism54_handler,
+	.private = (iw_handler *) prism54_private_handler,
+	.private_args = (struct iw_priv_args *) prism54_private_args,
+	.spy_offset = offsetof(islpci_private, spy_data),
+};
+
+/* For ioctls that don't work with the new API */
+
+int
+prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+
+	return -EOPNOTSUPP;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.h linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_ioctl.h
--- linux-2.4.27/drivers/net/wireless/prism54/isl_ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_ioctl.h	2004-08-15 19:51:02.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *            (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _ISL_IOCTL_H
+#define _ISL_IOCTL_H
+
+#include "islpci_mgt.h"
+#include "islpci_dev.h"
+
+#include <net/iw_handler.h>	/* New driver API */
+
+#define SUPPORTED_WIRELESS_EXT                  16
+
+void prism54_mib_init(islpci_private *);
+
+struct iw_statistics *prism54_get_wireless_stats(struct net_device *);
+void prism54_update_stats(islpci_private *);
+
+void prism54_acl_init(struct islpci_acl *);
+void prism54_acl_clean(struct islpci_acl *);
+
+void prism54_process_trap(void *);
+
+void prism54_wpa_ie_init(islpci_private *priv);
+void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+			u8 *wpa_ie, size_t wpa_ie_len);
+size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+
+int prism54_set_mac_address(struct net_device *, void *);
+
+int prism54_ioctl(struct net_device *, struct ifreq *, int);
+
+extern const struct iw_handler_def prism54_handler_def;
+
+#endif				/* _ISL_IOCTL_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/isl_oid.h linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_oid.h
--- linux-2.4.27/drivers/net/wireless/prism54/isl_oid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/isl_oid.h	2004-08-15 19:50:34.000000000 +0000
@@ -0,0 +1,498 @@
+/*
+ *
+ *  
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#if !defined(_ISL_OID_H)
+#define _ISL_OID_H
+
+/* 
+ * MIB related constant and structure definitions for communicating
+ * with the device firmware
+ */
+
+struct obj_ssid {
+	u8 length;
+	char octets[33];
+} __attribute__ ((packed));
+
+struct obj_key {
+	u8 type;		/* dot11_priv_t */
+	u8 length;
+	char key[32];
+} __attribute__ ((packed));
+
+struct obj_mlme {
+	u8 address[6];
+	u16 id;
+	u16 state;
+	u16 code;
+} __attribute__ ((packed));
+
+struct obj_mlmeex {
+	u8 address[6];
+	u16 id;
+	u16 state;
+	u16 code;
+	u16 size;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct obj_buffer {
+	u32 size;
+	u32 addr;		/* 32bit bus address */
+} __attribute__ ((packed));
+
+struct obj_bss {
+	u8 address[6];
+	int:16;			/* padding */
+
+	char state;
+	char reserved;
+	short age;
+
+	char quality;
+	char rssi;
+
+	struct obj_ssid ssid;
+	short channel;
+	char beacon_period;
+	char dtim_period;
+	short capinfo;
+	short rates;
+	short basic_rates;
+	int:16;			/* padding */
+} __attribute__ ((packed));
+
+struct obj_bsslist {
+	u32 nr;
+	struct obj_bss bsslist[0];
+} __attribute__ ((packed));
+
+struct obj_frequencies {
+	u16 nr;
+	u16 mhz[0];
+} __attribute__ ((packed));
+
+/* 
+ * in case everything's ok, the inlined function below will be
+ * optimized away by the compiler...
+ */
+static inline void
+__bug_on_wrong_struct_sizes(void)
+{
+	BUG_ON(sizeof (struct obj_ssid) != 34);
+	BUG_ON(sizeof (struct obj_key) != 34);
+	BUG_ON(sizeof (struct obj_mlme) != 12);
+	BUG_ON(sizeof (struct obj_mlmeex) != 14);
+	BUG_ON(sizeof (struct obj_buffer) != 8);
+	BUG_ON(sizeof (struct obj_bss) != 60);
+	BUG_ON(sizeof (struct obj_bsslist) != 4);
+	BUG_ON(sizeof (struct obj_frequencies) != 2);
+}
+
+enum dot11_state_t {
+	DOT11_STATE_NONE = 0,
+	DOT11_STATE_AUTHING = 1,
+	DOT11_STATE_AUTH = 2,
+	DOT11_STATE_ASSOCING = 3,
+
+	DOT11_STATE_ASSOC = 5,
+	DOT11_STATE_IBSS = 6,
+	DOT11_STATE_WDS = 7
+};
+
+enum dot11_bsstype_t {
+	DOT11_BSSTYPE_NONE = 0,
+	DOT11_BSSTYPE_INFRA = 1,
+	DOT11_BSSTYPE_IBSS = 2,
+	DOT11_BSSTYPE_ANY = 3
+};
+
+enum dot11_auth_t {
+	DOT11_AUTH_NONE = 0,
+	DOT11_AUTH_OS = 1,
+	DOT11_AUTH_SK = 2,
+	DOT11_AUTH_BOTH = 3
+};
+
+enum dot11_mlme_t {
+	DOT11_MLME_AUTO = 0,
+	DOT11_MLME_INTERMEDIATE = 1,
+	DOT11_MLME_EXTENDED = 2
+};
+
+enum dot11_priv_t {
+	DOT11_PRIV_WEP = 0,
+	DOT11_PRIV_TKIP = 1
+};
+
+/* Prism "Nitro" / Frameburst / "Packet Frame Grouping"
+ * Value is in microseconds. Represents the # microseconds
+ * the firmware will take to group frames before sending out then out 
+ * together with a CSMA contention. Without this all frames are
+ * sent with a CSMA contention. 
+ * Bibliography: 
+ * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html
+ */
+enum dot11_maxframeburst_t { 
+	/* Values for DOT11_OID_MAXFRAMEBURST */
+	DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */
+	DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */
+	DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */
+	DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max,
+		* Note: firmware allows for greater values. This is a
+		* recommended max. I'll update this as I find
+		* out what the real MAX is. Also note that you don't necessarily
+		* get better results with a greater value here.
+		*/
+};
+
+/* Support for 802.11 long and short frame preambles.
+ * Long	 preamble uses 128-bit sync field, 8-bit  CRC
+ * Short preamble uses 56-bit  sync field, 16-bit CRC
+ * 
+ * 802.11a -- not sure, both optionally ?
+ * 802.11b supports long and optionally short 
+ * 802.11g supports both */
+enum dot11_preamblesettings_t {
+	DOT11_PREAMBLESETTING_LONG = 0,
+		/* Allows *only* long 802.11 preambles */
+	DOT11_PREAMBLESETTING_SHORT = 1,
+		/* Allows *only* short 802.11 preambles */
+	DOT11_PREAMBLESETTING_DYNAMIC = 2
+		/* AutomatiGically set */
+};
+
+/* Support for 802.11 slot timing (time between packets).
+ *
+ * Long uses 802.11a slot timing  (9 usec ?)
+ * Short uses 802.11b slot timing (20 use ?) */
+enum dot11_slotsettings_t {
+	DOT11_SLOTSETTINGS_LONG = 0, 
+		/* Allows *only* long 802.11b slot timing */
+	DOT11_SLOTSETTINGS_SHORT = 1,
+		/* Allows *only* long 802.11a slot timing */
+	DOT11_SLOTSETTINGS_DYNAMIC = 2
+		/* AutomatiGically set */
+};
+
+/* All you need to know, ERP is "Extended Rate PHY".
+ * An Extended Rate PHY (ERP) STA or AP shall support three different 
+ * preamble and header formats:
+ * Long  preamble (refer to above)
+ * Short preamble (refer to above)
+ * OFDM  preamble ( ? )
+ *
+ * I'm assuming here Protection tells the AP
+ * to be careful, a STA which cannot handle the long pre-amble
+ * has joined.
+ */
+enum do11_nonerpstatus_t {
+	DOT11_ERPSTAT_NONEPRESENT = 0,
+	DOT11_ERPSTAT_USEPROTECTION = 1
+};
+
+/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-*
+ * The key here is DOT11 NON ERP NEVER protects against
+ * NON ERP STA's. You *don't* want this unless
+ * you know what you are doing. It means you will only 
+ * get Extended Rate capabilities */
+enum dot11_nonerpprotection_t {
+	DOT11_NONERP_NEVER = 0,
+	DOT11_NONERP_ALWAYS = 1,
+	DOT11_NONERP_DYNAMIC = 2
+};
+
+/* Preset OID configuration for 802.11 modes 
+ * Note: DOT11_OID_CW[MIN|MAX] hold the values of the 
+ * DCS MIN|MAX backoff used */
+enum dot11_profile_t { /* And set/allowed values */
+	/* Allowed values for DOT11_OID_PROFILES */
+	DOT11_PROFILE_B_ONLY = 0,
+		/* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps 
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
+		 * DOT11_OID_CWMIN: 31
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG
+		 */
+	DOT11_PROFILE_MIXED_G_WIFI = 1,
+		/* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
+		 * DOT11_OID_CWMIN: 15
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC
+		 */
+	DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */
+		/* Same as Profile MIXED_G_WIFI */
+	DOT11_PROFILE_G_ONLY = 3,
+		/* Same as Profile MIXED_G_WIFI */
+	DOT11_PROFILE_TEST = 4,
+		/* Same as Profile MIXED_G_WIFI except:
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT
+		 */
+	DOT11_PROFILE_B_WIFI = 5,
+		/* Same as Profile B_ONLY */
+	DOT11_PROFILE_A_ONLY = 6,
+		/* Same as Profile MIXED_G_WIFI except:
+		 * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs
+		 */
+	DOT11_PROFILE_MIXED_SHORT = 7
+		/* Same as MIXED_G_WIFI */
+};
+
+
+/* The dot11d conformance level configures the 802.11d conformance levels.
+ * The following conformance levels exist:*/
+enum oid_inl_conformance_t {
+	OID_INL_CONFORMANCE_NONE = 0,	/* Perform active scanning */
+	OID_INL_CONFORMANCE_STRICT = 1,	/* Strictly adhere to 802.11d */
+	OID_INL_CONFORMANCE_FLEXIBLE = 2,	/* Use passed 802.11d info to
+		* determine channel AND/OR just make assumption that active 
+		* channels are valid  channels */
+};
+
+enum oid_inl_mode_t {
+	INL_MODE_NONE = -1,
+	INL_MODE_PROMISCUOUS = 0,
+	INL_MODE_CLIENT = 1,
+	INL_MODE_AP = 2,
+	INL_MODE_SNIFFER = 3
+};
+
+enum oid_inl_config_t {
+	INL_CONFIG_NOTHING = 0x00,
+	INL_CONFIG_MANUALRUN = 0x01,
+	INL_CONFIG_FRAMETRAP = 0x02,
+	INL_CONFIG_RXANNEX = 0x04,
+	INL_CONFIG_TXANNEX = 0x08,
+	INL_CONFIG_WDS = 0x10
+};
+
+enum oid_inl_phycap_t {
+	INL_PHYCAP_2400MHZ = 1,
+	INL_PHYCAP_5000MHZ = 2,
+	INL_PHYCAP_FAA = 0x80000000,	/* Means card supports the FAA switch */
+};
+
+
+enum oid_num_t {
+	GEN_OID_MACADDRESS = 0,
+	GEN_OID_LINKSTATE,
+	GEN_OID_WATCHDOG,
+	GEN_OID_MIBOP,
+	GEN_OID_OPTIONS,
+	GEN_OID_LEDCONFIG,
+
+	/* 802.11 */
+	DOT11_OID_BSSTYPE,
+	DOT11_OID_BSSID,
+	DOT11_OID_SSID,
+	DOT11_OID_STATE,
+	DOT11_OID_AID,
+	DOT11_OID_COUNTRYSTRING,
+	DOT11_OID_SSIDOVERRIDE,
+
+	DOT11_OID_MEDIUMLIMIT,
+	DOT11_OID_BEACONPERIOD,
+	DOT11_OID_DTIMPERIOD,
+	DOT11_OID_ATIMWINDOW,
+	DOT11_OID_LISTENINTERVAL,
+	DOT11_OID_CFPPERIOD,
+	DOT11_OID_CFPDURATION,
+
+	DOT11_OID_AUTHENABLE,
+	DOT11_OID_PRIVACYINVOKED,
+	DOT11_OID_EXUNENCRYPTED,
+	DOT11_OID_DEFKEYID,
+	DOT11_OID_DEFKEYX,	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
+	DOT11_OID_STAKEY,
+	DOT11_OID_REKEYTHRESHOLD,
+	DOT11_OID_STASC,
+
+	DOT11_OID_PRIVTXREJECTED,
+	DOT11_OID_PRIVRXPLAIN,
+	DOT11_OID_PRIVRXFAILED,
+	DOT11_OID_PRIVRXNOKEY,
+
+	DOT11_OID_RTSTHRESH,
+	DOT11_OID_FRAGTHRESH,
+	DOT11_OID_SHORTRETRIES,
+	DOT11_OID_LONGRETRIES,
+	DOT11_OID_MAXTXLIFETIME,
+	DOT11_OID_MAXRXLIFETIME,
+	DOT11_OID_AUTHRESPTIMEOUT,
+	DOT11_OID_ASSOCRESPTIMEOUT,
+
+	DOT11_OID_ALOFT_TABLE,
+	DOT11_OID_ALOFT_CTRL_TABLE,
+	DOT11_OID_ALOFT_RETREAT,
+	DOT11_OID_ALOFT_PROGRESS,
+	DOT11_OID_ALOFT_FIXEDRATE,
+	DOT11_OID_ALOFT_RSSIGRAPH,
+	DOT11_OID_ALOFT_CONFIG,
+
+	DOT11_OID_VDCFX,
+	DOT11_OID_MAXFRAMEBURST,
+
+	DOT11_OID_PSM,
+	DOT11_OID_CAMTIMEOUT,
+	DOT11_OID_RECEIVEDTIMS,
+	DOT11_OID_ROAMPREFERENCE,
+
+	DOT11_OID_BRIDGELOCAL,
+	DOT11_OID_CLIENTS,
+	DOT11_OID_CLIENTSASSOCIATED,
+	DOT11_OID_CLIENTX,	/* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
+
+	DOT11_OID_CLIENTFIND,
+	DOT11_OID_WDSLINKADD,
+	DOT11_OID_WDSLINKREMOVE,
+	DOT11_OID_EAPAUTHSTA,
+	DOT11_OID_EAPUNAUTHSTA,
+	DOT11_OID_DOT1XENABLE,
+	DOT11_OID_MICFAILURE,
+	DOT11_OID_REKEYINDICATE,
+
+	DOT11_OID_MPDUTXSUCCESSFUL,
+	DOT11_OID_MPDUTXONERETRY,
+	DOT11_OID_MPDUTXMULTIPLERETRIES,
+	DOT11_OID_MPDUTXFAILED,
+	DOT11_OID_MPDURXSUCCESSFUL,
+	DOT11_OID_MPDURXDUPS,
+	DOT11_OID_RTSSUCCESSFUL,
+	DOT11_OID_RTSFAILED,
+	DOT11_OID_ACKFAILED,
+	DOT11_OID_FRAMERECEIVES,
+	DOT11_OID_FRAMEERRORS,
+	DOT11_OID_FRAMEABORTS,
+	DOT11_OID_FRAMEABORTSPHY,
+
+	DOT11_OID_SLOTTIME,
+	DOT11_OID_CWMIN, /* MIN DCS backoff */
+	DOT11_OID_CWMAX, /* MAX DCS backoff */
+	DOT11_OID_ACKWINDOW,
+	DOT11_OID_ANTENNARX,
+	DOT11_OID_ANTENNATX,
+	DOT11_OID_ANTENNADIVERSITY,
+	DOT11_OID_CHANNEL,
+	DOT11_OID_EDTHRESHOLD,
+	DOT11_OID_PREAMBLESETTINGS,
+	DOT11_OID_RATES,
+	DOT11_OID_CCAMODESUPPORTED,
+	DOT11_OID_CCAMODE,
+	DOT11_OID_RSSIVECTOR,
+	DOT11_OID_OUTPUTPOWERTABLE,
+	DOT11_OID_OUTPUTPOWER,
+	DOT11_OID_SUPPORTEDRATES,
+	DOT11_OID_FREQUENCY,
+	DOT11_OID_SUPPORTEDFREQUENCIES,
+	DOT11_OID_NOISEFLOOR,
+	DOT11_OID_FREQUENCYACTIVITY,
+	DOT11_OID_IQCALIBRATIONTABLE,
+	DOT11_OID_NONERPPROTECTION,
+	DOT11_OID_SLOTSETTINGS,
+	DOT11_OID_NONERPTIMEOUT,
+	DOT11_OID_PROFILES,
+	DOT11_OID_EXTENDEDRATES,
+
+	DOT11_OID_DEAUTHENTICATE,
+	DOT11_OID_AUTHENTICATE,
+	DOT11_OID_DISASSOCIATE,
+	DOT11_OID_ASSOCIATE,
+	DOT11_OID_SCAN,
+	DOT11_OID_BEACON,
+	DOT11_OID_PROBE,
+	DOT11_OID_DEAUTHENTICATEEX,
+	DOT11_OID_AUTHENTICATEEX,
+	DOT11_OID_DISASSOCIATEEX,
+	DOT11_OID_ASSOCIATEEX,
+	DOT11_OID_REASSOCIATE,
+	DOT11_OID_REASSOCIATEEX,
+
+	DOT11_OID_NONERPSTATUS,
+
+	DOT11_OID_STATIMEOUT,
+	DOT11_OID_MLMEAUTOLEVEL,
+	DOT11_OID_BSSTIMEOUT,
+	DOT11_OID_ATTACHMENT,
+	DOT11_OID_PSMBUFFER,
+
+	DOT11_OID_BSSS,
+	DOT11_OID_BSSX,		/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
+	DOT11_OID_BSSFIND,
+	DOT11_OID_BSSLIST,
+
+	OID_INL_TUNNEL,
+	OID_INL_MEMADDR,
+	OID_INL_MEMORY,
+	OID_INL_MODE,
+	OID_INL_COMPONENT_NR,
+	OID_INL_VERSION,
+	OID_INL_INTERFACE_ID,
+	OID_INL_COMPONENT_ID,
+	OID_INL_CONFIG,
+	OID_INL_DOT11D_CONFORMANCE,
+	OID_INL_PHYCAPABILITIES,
+	OID_INL_OUTPUTPOWER,
+
+	OID_NUM_LAST
+};
+
+#define OID_FLAG_CACHED		0x80
+#define OID_FLAG_TYPE		0x7f
+
+#define OID_TYPE_U32		0x01
+#define OID_TYPE_SSID		0x02
+#define OID_TYPE_KEY		0x03
+#define OID_TYPE_BUFFER		0x04
+#define OID_TYPE_BSS		0x05
+#define OID_TYPE_BSSLIST	0x06
+#define OID_TYPE_FREQUENCIES	0x07
+#define OID_TYPE_MLME		0x08
+#define OID_TYPE_MLMEEX		0x09
+#define OID_TYPE_ADDR		0x0A
+#define OID_TYPE_RAW		0x0B
+
+/* OID_TYPE_MLMEEX is special because of a variable size field when sending.
+ * Not yet implemented (not used in driver anyway).
+ */
+
+struct oid_t {
+	enum oid_num_t oid;
+	short range;		/* to define a range of oid */
+	short size;		/* max size of the associated data */
+	char flags;
+};
+
+union oid_res_t {
+	void *ptr;
+	u32 u;
+};
+
+#define	IWMAX_BITRATES	20
+#define	IWMAX_BSS	24
+#define IWMAX_FREQ	30
+#define PRIV_STR_SIZE	1024
+
+#endif				/* !defined(_ISL_OID_H) */
+/* EOF */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.c linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_dev.c
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_dev.c	2004-08-15 19:51:55.000000000 +0000
@@ -0,0 +1,931 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+
+#include <asm/io.h>
+
+#include "prismcompat.h"
+#include "isl_38xx.h"
+#include "isl_ioctl.h"
+#include "islpci_dev.h"
+#include "islpci_mgt.h"
+#include "islpci_eth.h"
+#include "oid_mgt.h"
+
+#define ISL3877_IMAGE_FILE	"isl3877"
+#define ISL3890_IMAGE_FILE	"isl3890"
+
+static int prism54_bring_down(islpci_private *);
+static int islpci_alloc_memory(islpci_private *);
+
+/* Temporary dummy MAC address to use until firmware is loaded.
+ * The idea there is that some tools (such as nameif) may query
+ * the MAC address before the netdev is 'open'. By using a valid
+ * OUI prefix, they can process the netdev properly.
+ * Of course, this is not the final/real MAC address. It doesn't
+ * matter, as you are suppose to be able to change it anytime via
+ * ndev->set_mac_address. Jean II */
+const unsigned char	dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };
+
+static int
+isl_upload_firmware(islpci_private *priv)
+{
+	u32 reg, rc;
+	void *device_base = priv->device_base;
+
+	/* clear the RAMBoot and the Reset bit */
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	reg &= ~ISL38XX_CTRL_STAT_RAMBOOT;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the Reset bit without reading the register ! */
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the Reset bit */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+
+	/* wait a while for the device to reboot */
+	mdelay(50);
+
+	{
+		const struct firmware *fw_entry = 0;
+		long fw_len;
+		const u32 *fw_ptr;
+
+		rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV);
+		if (rc) {
+			printk(KERN_ERR
+			       "%s: request_firmware() failed for '%s'\n",
+			       "prism54", priv->firmware);
+			return rc;
+		}
+		/* prepare the Direct Memory Base register */
+		reg = ISL38XX_DEV_FIRMWARE_ADDRES;
+
+		fw_ptr = (u32 *) fw_entry->data;
+		fw_len = fw_entry->size;
+
+		if (fw_len % 4) {
+			printk(KERN_ERR
+			       "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
+			       "prism54", priv->firmware);
+			release_firmware(fw_entry);
+			return EILSEQ; /* Illegal byte sequence  */;
+		}
+
+		while (fw_len > 0) {
+			long _fw_len =
+			    (fw_len >
+			     ISL38XX_MEMORY_WINDOW_SIZE) ?
+			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
+			u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
+
+			/* set the cards base address for writting the data */
+			isl38xx_w32_flush(device_base, reg,
+					  ISL38XX_DIR_MEM_BASE_REG);
+			wmb();	/* be paranoid */
+
+			/* increment the write address for next iteration */
+			reg += _fw_len;
+			fw_len -= _fw_len;
+
+			/* write the data to the Direct Memory Window 32bit-wise */
+			/* memcpy_toio() doesn't guarantee 32bit writes :-| */
+			while (_fw_len > 0) {
+				/* use non-swapping writel() */
+				__raw_writel(*fw_ptr, dev_fw_ptr);
+				fw_ptr++, dev_fw_ptr++;
+				_fw_len -= 4;
+			}
+
+			/* flush PCI posting */
+			(void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH);
+			wmb();	/* be paranoid again */
+
+			BUG_ON(_fw_len != 0);
+		}
+
+		BUG_ON(fw_len != 0);
+
+		release_firmware(fw_entry);
+	}
+
+	/* now reset the device
+	 * clear the Reset & ClkRun bit, set the RAMBoot bit */
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~ISL38XX_CTRL_STAT_CLKRUN;
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	reg |= ISL38XX_CTRL_STAT_RAMBOOT;
+	isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* set the reset bit latches the host override and RAMBoot bits
+	 * into the device for operation when the reset bit is reset */
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	/* don't do flush PCI posting here! */
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the reset bit should start the whole circus */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	/* don't do flush PCI posting here! */
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	return 0;
+}
+
+/******************************************************************************
+    Device Interrupt Handler
+******************************************************************************/
+
+irqreturn_t
+islpci_interrupt(int irq, void *config, struct pt_regs *regs)
+{
+	u32 reg;
+	islpci_private *priv = config;
+	struct net_device *ndev = priv->ndev;
+	void *device = priv->device_base;
+	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;
+
+	/* received an interrupt request on a shared IRQ line
+	 * first check whether the device is in sleep mode */
+	reg = readl(device + ISL38XX_CTRL_STAT_REG);
+	if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)
+		/* device is in sleep mode, IRQ was generated by someone else */
+	{
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");
+#endif
+		return IRQ_NONE;
+	}
+
+	if (islpci_get_state(priv) != PRV_STATE_SLEEP)
+		powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+	/* lock the interrupt handler */
+	spin_lock(&priv->slock);
+
+	/* check whether there is any source of interrupt on the device */
+	reg = readl(device + ISL38XX_INT_IDENT_REG);
+
+	/* also check the contents of the Interrupt Enable Register, because this
+	 * will filter out interrupt sources from other devices on the same irq ! */
+	reg &= readl(device + ISL38XX_INT_EN_REG);
+	reg &= ISL38XX_INT_SOURCES;
+
+	if (reg != 0) {
+		/* reset the request bits in the Identification register */
+		isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_FUNCTION_CALLS,
+		      "IRQ: Identification register 0x%p 0x%x \n", device, reg);
+#endif
+
+		/* check for each bit in the register separately */
+		if (reg & ISL38XX_INT_IDENT_UPDATE) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			/* Queue has been updated */
+			DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
+
+			DEBUG(SHOW_QUEUE_INDEXES,
+			      "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[0]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[1]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[2]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[3]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[4]),
+			      le32_to_cpu(priv->control_block->
+					  driver_curr_frag[5])
+			    );
+
+			DEBUG(SHOW_QUEUE_INDEXES,
+			      "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n",
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[0]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[1]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[2]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[3]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[4]),
+			      le32_to_cpu(priv->control_block->
+					  device_curr_frag[5])
+			    );
+#endif
+
+			/* cleanup the data low transmit queue */
+			islpci_eth_cleanup_transmit(priv, priv->control_block);
+
+			/* device is in active state, update the
+			 * powerstate flag if necessary */
+			powerstate = ISL38XX_PSM_ACTIVE_STATE;
+
+			/* check all three queues in priority order
+			 * call the PIMFOR receive function until the
+			 * queue is empty */
+			if (isl38xx_in_queue(priv->control_block,
+						ISL38XX_CB_RX_MGMTQ) != 0) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+				DEBUG(SHOW_TRACING,
+				      "Received frame in Management Queue\n");
+#endif
+				islpci_mgt_receive(ndev);
+
+				islpci_mgt_cleanup_transmit(ndev);
+
+				/* Refill slots in receive queue */
+				islpci_mgmt_rx_fill(ndev);
+
+				/* no need to trigger the device, next
+                                   islpci_mgt_transaction does it */
+			}
+
+			while (isl38xx_in_queue(priv->control_block,
+						ISL38XX_CB_RX_DATA_LQ) != 0) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+				DEBUG(SHOW_TRACING,
+				      "Received frame in Data Low Queue \n");
+#endif
+				islpci_eth_receive(priv);
+			}
+
+			/* check whether the data transmit queues were full */
+			if (priv->data_low_tx_full) {
+				/* check whether the transmit is not full anymore */
+				if (ISL38XX_CB_TX_QSIZE -
+				    isl38xx_in_queue(priv->control_block,
+						     ISL38XX_CB_TX_DATA_LQ) >=
+				    ISL38XX_MIN_QTHRESHOLD) {
+					/* nope, the driver is ready for more network frames */
+					netif_wake_queue(priv->ndev);
+
+					/* reset the full flag */
+					priv->data_low_tx_full = 0;
+				}
+			}
+		}
+
+		if (reg & ISL38XX_INT_IDENT_INIT) {
+			/* Device has been initialized */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING,
+			      "IRQ: Init flag, device initialized \n");
+#endif
+			wake_up(&priv->reset_done);
+		}
+
+		if (reg & ISL38XX_INT_IDENT_SLEEP) {
+			/* Device intends to move to powersave state */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
+#endif
+			isl38xx_handle_sleep_request(priv->control_block,
+						     &powerstate,
+						     priv->device_base);
+		}
+
+		if (reg & ISL38XX_INT_IDENT_WAKEUP) {
+			/* Device has been woken up to active state */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
+#endif
+
+			isl38xx_handle_wakeup(priv->control_block,
+					      &powerstate, priv->device_base);
+		}
+	}
+
+	/* sleep -> ready */
+	if (islpci_get_state(priv) == PRV_STATE_SLEEP
+	    && powerstate == ISL38XX_PSM_ACTIVE_STATE)
+		islpci_set_state(priv, PRV_STATE_READY);
+
+	/* !sleep -> sleep */
+	if (islpci_get_state(priv) != PRV_STATE_SLEEP
+	    && powerstate == ISL38XX_PSM_POWERSAVE_STATE)
+		islpci_set_state(priv, PRV_STATE_SLEEP);
+
+	/* unlock the interrupt handler */
+	spin_unlock(&priv->slock);
+
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************
+    Network Interface Control & Statistical functions
+******************************************************************************/
+static int
+islpci_open(struct net_device *ndev)
+{
+	u32 rc;
+	islpci_private *priv = netdev_priv(ndev);
+
+	printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
+
+	/* reset data structures, upload firmware and reset device */
+	rc = islpci_reset(priv,1);
+	if (rc) {
+		prism54_bring_down(priv);
+		return rc; /* Returns informative message */
+	}
+
+	netif_start_queue(ndev);
+/*      netif_mark_up( ndev ); */
+
+	return 0;
+}
+
+static int
+islpci_close(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+	printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name);
+
+	netif_stop_queue(ndev);
+
+	return prism54_bring_down(priv);
+}
+
+static int
+prism54_bring_down(islpci_private *priv)
+{
+	void *device_base = priv->device_base;
+	u32 reg;
+	/* we are going to shutdown the device */
+	islpci_set_state(priv, PRV_STATE_PREBOOT);
+
+	/* disable all device interrupts in case they weren't */
+	isl38xx_disable_interrupts(priv->device_base);  
+
+	/* For safety reasons, we may want to ensure that no DMA transfer is
+	 * currently in progress by emptying the TX and RX queues. */
+
+	/* wait until interrupts have finished executing on other CPUs */
+	prism54_synchronize_irq(priv->pdev->irq);
+
+	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
+	reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT);
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	reg |= ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+	udelay(ISL38XX_WRITEIO_DELAY);
+
+	/* clear the Reset bit */
+	reg &= ~ISL38XX_CTRL_STAT_RESET;
+	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);
+	wmb();
+
+	/* wait a while for the device to reset */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(50*HZ/1000);
+
+	return 0;
+}
+
+static int
+islpci_upload_fw(islpci_private *priv)
+{
+	islpci_state_t old_state;
+	u32 rc;
+
+	old_state = islpci_set_state(priv, PRV_STATE_BOOT);
+
+	printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name);
+
+	rc = isl_upload_firmware(priv);
+	if (rc) {
+		/* error uploading the firmware */
+		printk(KERN_ERR "%s: could not upload firmware ('%s')\n",
+		       priv->ndev->name, priv->firmware);
+
+		islpci_set_state(priv, old_state);
+		return rc;
+	}
+
+	printk(KERN_DEBUG
+	       "%s: firmware uploaded done, now triggering reset...\n",
+	       priv->ndev->name);
+
+	islpci_set_state(priv, PRV_STATE_POSTBOOT);
+
+	return 0;
+}
+
+static int
+islpci_reset_if(islpci_private *priv)
+{
+	long remaining;
+	int result = -ETIME;
+	int count;
+
+	DEFINE_WAIT(wait);
+	prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
+	
+	/* now the last step is to reset the interface */
+	isl38xx_interface_reset(priv->device_base, priv->device_host_address);
+	islpci_set_state(priv, PRV_STATE_PREINIT);
+
+        for(count = 0; count < 2 && result; count++) {
+		/* The software reset acknowledge needs about 220 msec here.
+		 * Be conservative and wait for up to one second. */
+	
+		remaining = schedule_timeout(HZ);
+
+		if(remaining > 0) {
+			result = 0;
+			break;
+		}
+
+		/* If we're here it's because our IRQ hasn't yet gone through. 
+		 * Retry a bit more...
+		 */
+		 printk(KERN_ERR "%s: device soft reset timed out\n",
+		       priv->ndev->name);
+
+	}
+
+	finish_wait(&priv->reset_done, &wait);
+
+	if(result)
+		return result;
+
+	islpci_set_state(priv, PRV_STATE_INIT);
+
+	/* Now that the device is 100% up, let's allow
+	 * for the other interrupts --
+	 * NOTE: this is not *yet* true since we've only allowed the 
+	 * INIT interrupt on the IRQ line. We can perhaps poll
+	 * the IRQ line until we know for sure the reset went through */
+	isl38xx_enable_common_interrupts(priv->device_base);
+
+	down_write(&priv->mib_sem);
+	mgt_commit(priv);
+	up_write(&priv->mib_sem);
+
+	islpci_set_state(priv, PRV_STATE_READY);
+
+	return 0;
+}
+
+int
+islpci_reset(islpci_private *priv, int reload_firmware)
+{
+	isl38xx_control_block *cb =    /* volatile not needed */
+		(isl38xx_control_block *) priv->control_block;
+	unsigned counter;
+	int rc;
+
+	if (reload_firmware)
+		islpci_set_state(priv, PRV_STATE_PREBOOT);
+	else
+		islpci_set_state(priv, PRV_STATE_POSTBOOT);
+
+	printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name);
+
+	/* disable all device interrupts in case they weren't */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* flush all management queues */
+	priv->index_mgmt_tx = 0;
+	priv->index_mgmt_rx = 0;
+
+	/* clear the indexes in the frame pointer */
+	for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
+		cb->driver_curr_frag[counter] = cpu_to_le32(0);
+		cb->device_curr_frag[counter] = cpu_to_le32(0);
+	}
+
+	/* reset the mgmt receive queue */
+	for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
+		isl38xx_fragment *frag = &cb->rx_data_mgmt[counter];
+		frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
+		frag->flags = 0;
+		frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr);
+	}
+
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		cb->rx_data_low[counter].address =
+		    cpu_to_le32((u32) priv->pci_map_rx_address[counter]);
+	}
+
+	/* since the receive queues are filled with empty fragments, now we can
+	 * set the corresponding indexes in the Control Block */
+	priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] =
+	    cpu_to_le32(ISL38XX_CB_RX_QSIZE);
+	priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] =
+	    cpu_to_le32(ISL38XX_CB_MGMT_QSIZE);
+
+	/* reset the remaining real index registers and full flags */
+	priv->free_data_rx = 0;
+	priv->free_data_tx = 0;
+	priv->data_low_tx_full = 0;
+
+	if (reload_firmware) { /* Should we load the firmware ? */
+	/* now that the data structures are cleaned up, upload
+	 * firmware and reset interface */
+		rc = islpci_upload_fw(priv);
+		if (rc) 
+			return rc;
+	}
+
+	/* finally reset interface */
+	rc = islpci_reset_if(priv);
+	if (!rc) /* If successful */
+		return rc;
+	
+	printk(KERN_DEBUG  "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
+	return rc;
+
+}
+
+struct net_device_stats *
+islpci_statistics(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
+#endif
+
+	return &priv->statistics;
+}
+
+/******************************************************************************
+    Network device configuration functions
+******************************************************************************/
+static int
+islpci_alloc_memory(islpci_private *priv)
+{
+	int counter;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	printk(KERN_DEBUG "islpci_alloc_memory\n");
+#endif
+
+	/* remap the PCI device base address to accessable */
+	if (!(priv->device_base =
+	      ioremap(pci_resource_start(priv->pdev, 0),
+		      ISL38XX_PCI_MEM_SIZE))) {
+		/* error in remapping the PCI device memory address range */
+		printk(KERN_ERR "PCI memory remapping failed \n");
+		return -1;
+	}
+
+	/* memory layout for consistent DMA region:
+	 *
+	 * Area 1: Control Block for the device interface
+	 * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that
+	 *         the number of supported stations in the AP determines the minimal
+	 *         size of the buffer !
+	 */
+
+	/* perform the allocation */
+	priv->driver_mem_address = pci_alloc_consistent(priv->pdev,
+							HOST_MEM_BLOCK,
+							&priv->
+							device_host_address);
+
+	if (!priv->driver_mem_address) {
+		/* error allocating the block of PCI memory */
+		printk(KERN_ERR "%s: could not allocate DMA memory, aborting!",
+		       "prism54");
+		return -1;
+	}
+
+	/* assign the Control Block to the first address of the allocated area */
+	priv->control_block =
+	    (isl38xx_control_block *) priv->driver_mem_address;
+
+	/* set the Power Save Buffer pointer directly behind the CB */
+	priv->device_psm_buffer =
+		priv->device_host_address + CONTROL_BLOCK_SIZE;
+
+	/* make sure all buffer pointers are initialized */
+	for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) {
+		priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0);
+		priv->control_block->device_curr_frag[counter] = cpu_to_le32(0);
+	}
+
+	priv->index_mgmt_rx = 0;
+	memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx));
+	memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx));
+
+	/* allocate rx queue for management frames */
+	if (islpci_mgmt_rx_fill(priv->ndev) < 0)
+		goto out_free;
+
+	/* now get the data rx skb's */
+	memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx));
+	memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address));
+
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		struct sk_buff *skb;
+
+		/* allocate an sk_buff for received data frames storage
+		 * each frame on receive size consists of 1 fragment
+		 * include any required allignment operations */
+		if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) {
+			/* error allocating an sk_buff structure elements */
+			printk(KERN_ERR "Error allocating skb.\n");
+			skb = NULL;
+			goto out_free;
+		}
+		skb_reserve(skb, (4 - (long) skb->data) & 0x03);
+		/* add the new allocated sk_buff to the buffer array */
+		priv->data_low_rx[counter] = skb;
+
+		/* map the allocated skb data area to pci */
+		priv->pci_map_rx_address[counter] =
+		    pci_map_single(priv->pdev, (void *) skb->data,
+				   MAX_FRAGMENT_SIZE_RX + 2,
+				   PCI_DMA_FROMDEVICE);
+		if (!priv->pci_map_rx_address[counter]) {
+			/* error mapping the buffer to device
+			   accessable memory address */
+			printk(KERN_ERR "failed to map skb DMA'able\n");
+			goto out_free;
+		}
+	}
+
+	prism54_acl_init(&priv->acl);
+	prism54_wpa_ie_init(priv);
+	if (mgt_init(priv)) 
+		goto out_free;
+
+	return 0;
+ out_free:
+	islpci_free_memory(priv);
+	return -1;
+}
+
+int
+islpci_free_memory(islpci_private *priv)
+{
+	int counter;
+
+	if (priv->device_base)
+		iounmap(priv->device_base);
+	priv->device_base = 0;
+
+	/* free consistent DMA area... */
+	if (priv->driver_mem_address)
+		pci_free_consistent(priv->pdev, HOST_MEM_BLOCK,
+				    priv->driver_mem_address,
+				    priv->device_host_address);
+
+	/* clear some dangling pointers */
+	priv->driver_mem_address = 0;
+	priv->device_host_address = 0;
+	priv->device_psm_buffer = 0;
+	priv->control_block = 0;
+
+        /* clean up mgmt rx buffers */
+        for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) {
+		struct islpci_membuf *buf = &priv->mgmt_rx[counter];
+		if (buf->pci_addr)
+			pci_unmap_single(priv->pdev, buf->pci_addr,
+					 buf->size, PCI_DMA_FROMDEVICE);
+		buf->pci_addr = 0;
+		if (buf->mem)
+			kfree(buf->mem);
+		buf->size = 0;
+		buf->mem = NULL;
+        }
+
+	/* clean up data rx buffers */
+	for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) {
+		if (priv->pci_map_rx_address[counter])
+			pci_unmap_single(priv->pdev,
+					 priv->pci_map_rx_address[counter],
+					 MAX_FRAGMENT_SIZE_RX + 2,
+					 PCI_DMA_FROMDEVICE);
+		priv->pci_map_rx_address[counter] = 0;
+
+		if (priv->data_low_rx[counter])
+			dev_kfree_skb(priv->data_low_rx[counter]);
+		priv->data_low_rx[counter] = 0;
+	}
+
+	/* Free the acces control list and the WPA list */
+	prism54_acl_clean(&priv->acl);
+	prism54_wpa_ie_clean(priv);
+	mgt_clean(priv);
+
+	return 0;
+}
+
+#if 0
+static void
+islpci_set_multicast_list(struct net_device *dev)
+{
+	/* put device into promisc mode and let network layer handle it */
+}
+#endif
+
+struct net_device *
+islpci_setup(struct pci_dev *pdev)
+{
+	islpci_private *priv;
+	struct net_device *ndev = alloc_etherdev(sizeof (islpci_private));
+
+	if (!ndev)
+		return ndev;
+
+	SET_MODULE_OWNER(ndev);
+	pci_set_drvdata(pdev, ndev);
+#if defined(SET_NETDEV_DEV)
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+#endif
+
+	/* setup the structure members */
+	ndev->base_addr = pci_resource_start(pdev, 0);
+	ndev->irq = pdev->irq;
+
+	/* initialize the function pointers */
+	ndev->open = &islpci_open;
+	ndev->stop = &islpci_close;
+	ndev->get_stats = &islpci_statistics;
+	ndev->get_wireless_stats = &prism54_get_wireless_stats;
+	ndev->do_ioctl = &prism54_ioctl;
+	ndev->wireless_handlers =
+	    (struct iw_handler_def *) &prism54_handler_def;
+
+	ndev->hard_start_xmit = &islpci_eth_transmit;
+	/* ndev->set_multicast_list = &islpci_set_multicast_list; */
+	ndev->addr_len = ETH_ALEN;
+	ndev->set_mac_address = &prism54_set_mac_address;
+	/* Get a non-zero dummy MAC address for nameif. Jean II */
+	memcpy(ndev->dev_addr, dummy_mac, 6);
+
+#ifdef HAVE_TX_TIMEOUT
+	ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT;
+	ndev->tx_timeout = &islpci_eth_tx_timeout;
+#endif
+
+	/* allocate a private device structure to the network device  */
+	priv = netdev_priv(ndev);
+	priv->ndev = ndev;
+	priv->pdev = pdev;
+	priv->monitor_type = ARPHRD_IEEE80211;
+	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
+		priv->monitor_type : ARPHRD_ETHER;
+
+	/* save the start and end address of the PCI memory area */
+	ndev->mem_start = (unsigned long) priv->device_base;
+	ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base);
+#endif
+
+	init_waitqueue_head(&priv->reset_done);
+
+	/* init the queue read locks, process wait counter */
+	sema_init(&priv->mgmt_sem, 1);
+	priv->mgmt_received = NULL;
+	init_waitqueue_head(&priv->mgmt_wqueue);
+	sema_init(&priv->stats_sem, 1);
+	spin_lock_init(&priv->slock);
+
+	/* init state machine with off#1 state */
+	priv->state = PRV_STATE_OFF;
+	priv->state_off = 1;
+
+	/* initialize workqueue's */
+	INIT_WORK(&priv->stats_work,
+		  (void (*)(void *)) prism54_update_stats, priv);
+	priv->stats_timestamp = 0;
+
+	INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv);
+	priv->reset_task_pending = 0;
+
+	/* allocate various memory areas */
+	if (islpci_alloc_memory(priv))
+		goto do_free_netdev;
+
+	/* select the firmware file depending on the device id */
+	switch (pdev->device) {
+	case PCIDEVICE_ISL3890:
+	case PCIDEVICE_3COM6001:
+		strcpy(priv->firmware, ISL3890_IMAGE_FILE);
+		break;
+	case PCIDEVICE_ISL3877:
+		strcpy(priv->firmware, ISL3877_IMAGE_FILE);
+		break;
+
+	default:
+		strcpy(priv->firmware, ISL3890_IMAGE_FILE);
+		break;
+	}
+
+	if (register_netdev(ndev)) {
+		DEBUG(SHOW_ERROR_MESSAGES,
+		      "ERROR: register_netdev() failed \n");
+		goto do_islpci_free_memory;
+	}
+
+	return ndev;
+
+      do_islpci_free_memory:
+	islpci_free_memory(priv);
+      do_free_netdev:
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+	return NULL;
+}
+
+islpci_state_t
+islpci_set_state(islpci_private *priv, islpci_state_t new_state)
+{
+	islpci_state_t old_state;
+
+	/* lock */
+	old_state = priv->state;
+
+	/* this means either a race condition or some serious error in
+	 * the driver code */
+	switch (new_state) {
+	case PRV_STATE_OFF:
+		priv->state_off++;
+	default:
+		priv->state = new_state;
+		break;
+
+	case PRV_STATE_PREBOOT:
+		/* there are actually many off-states, enumerated by
+		 * state_off */
+		if (old_state == PRV_STATE_OFF)
+			priv->state_off--;
+
+		/* only if hw_unavailable is zero now it means we either
+		 * were in off#1 state, or came here from
+		 * somewhere else */
+		if (!priv->state_off)
+			priv->state = new_state;
+		break;
+	};
+#if 0
+	printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n",
+	       priv->ndev->name, old_state, new_state, priv->state_off);
+#endif
+
+	/* invariants */
+	BUG_ON(priv->state_off < 0);
+	BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF));
+	BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF));
+
+	/* unlock */
+	return old_state;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.h linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_dev.h
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_dev.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_dev.h	2004-08-15 19:49:18.000000000 +0000
@@ -0,0 +1,215 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc. 
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _ISLPCI_DEV_H
+#define _ISLPCI_DEV_H
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/list.h>
+
+#include "isl_38xx.h"
+#include "isl_oid.h"
+#include "islpci_mgt.h"
+
+/* some states might not be superflous and may be removed when
+   design is finalized (hvr) */
+typedef enum {
+	PRV_STATE_OFF = 0,	/* this means hw_unavailable is != 0 */
+	PRV_STATE_PREBOOT,	/* we are in a pre-boot state (empty RAM) */
+	PRV_STATE_BOOT,		/* boot state (fw upload, run fw) */
+	PRV_STATE_POSTBOOT,	/* after boot state, need reset now */
+	PRV_STATE_PREINIT,	/* pre-init state */
+	PRV_STATE_INIT,		/* init state (restore MIB backup to device) */
+	PRV_STATE_READY,	/* driver&device are in operational state */
+	PRV_STATE_SLEEP		/* device in sleep mode */
+} islpci_state_t;
+
+/* ACL using MAC address */
+struct mac_entry {
+   struct list_head _list;
+   char addr[ETH_ALEN];
+};
+
+struct islpci_acl {
+   enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy;
+   struct list_head mac_list;  /* a list of mac_entry */
+   int size;   /* size of queue */
+   struct semaphore sem;   /* accessed in ioctls and trap_work */
+};
+
+struct islpci_membuf {
+	int size;                   /* size of memory */
+	void *mem;                  /* address of memory as seen by CPU */
+	dma_addr_t pci_addr;        /* address of memory as seen by device */
+};
+
+#define MAX_BSS_WPA_IE_COUNT 64
+#define MAX_WPA_IE_LEN 64
+struct islpci_bss_wpa_ie {
+	struct list_head list;
+	unsigned long last_update;
+	u8 bssid[ETH_ALEN];
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
+	
+};
+
+typedef struct {
+	spinlock_t slock;	/* generic spinlock; */
+	
+	u32 priv_oid;
+
+	/* our mib cache */
+	u32 iw_mode;
+        struct rw_semaphore mib_sem;
+	void **mib;
+	char nickname[IW_ESSID_MAX_SIZE+1];
+	
+	/* Take care of the wireless stats */
+	struct work_struct stats_work;
+	struct semaphore stats_sem;
+	/* remember when we last updated the stats */
+	unsigned long stats_timestamp;
+	/* The first is accessed under semaphore locking.
+	 * The second is the clean one we return to iwconfig.
+	 */
+	struct iw_statistics local_iwstatistics;
+	struct iw_statistics iwstatistics;
+
+	struct iw_spy_data spy_data; /* iwspy support */
+
+	int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
+
+	struct islpci_acl acl;
+
+	/* PCI bus allocation & configuration members */
+	struct pci_dev *pdev;	/* PCI structure information */
+	u32 pci_state[16];	/* used for suspend/resume */
+	char firmware[33];
+
+	void *device_base;	/* ioremapped device base address */
+
+	/* consistent DMA region */
+	void *driver_mem_address;	/* base DMA address */
+	dma_addr_t device_host_address;	/* base DMA address (bus address) */
+	dma_addr_t device_psm_buffer;	/* host memory for PSM buffering (bus address) */
+
+	/* our network_device structure  */
+	struct net_device *ndev;
+
+	/* device queue interface members */
+	struct isl38xx_cb *control_block;	/* device control block 
+							   (== driver_mem_address!) */
+
+	/* Each queue has three indexes:
+	 *   free/index_mgmt/data_rx/tx (called index, see below),
+	 *   driver_curr_frag, and device_curr_frag (in the control block)
+	 * All indexes are ever-increasing, but interpreted modulo the
+	 * device queue size when used.
+	 *   index <= device_curr_frag <= driver_curr_frag  at all times
+	 * For rx queues, [index, device_curr_frag) contains fragments
+	 * that the interrupt processing needs to handle (owned by driver).
+	 * [device_curr_frag, driver_curr_frag) is the free space in the
+	 * rx queue, waiting for data (owned by device).  The driver
+	 * increments driver_curr_frag to indicate to the device that more
+	 * buffers are available.
+	 * If device_curr_frag == driver_curr_frag, no more rx buffers are
+	 * available, and the rx DMA engine of the device is halted.
+	 * For tx queues, [index, device_curr_frag) contains fragments
+	 * where tx is done; they need to be freed (owned by driver).
+	 * [device_curr_frag, driver_curr_frag) contains the frames
+	 * that are being transferred (owned by device).  The driver
+	 * increments driver_curr_frag to indicate that more tx work
+	 * needs to be done.
+	 */
+	u32 index_mgmt_rx;              /* real index mgmt rx queue */
+	u32 index_mgmt_tx;              /* read index mgmt tx queue */
+	u32 free_data_rx;	/* free pointer data rx queue */
+	u32 free_data_tx;	/* free pointer data tx queue */
+	u32 data_low_tx_full;	/* full detected flag */
+
+	/* frame memory buffers for the device queues */
+	struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE];
+	struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE];
+	struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE];
+	struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE];
+	dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE];
+	dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE];
+
+	/* driver network interface members */
+	struct net_device_stats statistics;
+
+	/* wait for a reset interrupt */
+	wait_queue_head_t reset_done;
+
+	/* used by islpci_mgt_transaction */
+	struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */
+	struct islpci_mgmtframe *mgmt_received;	  /* mbox for incoming frame */
+	wait_queue_head_t mgmt_wqueue;            /* waitqueue for mbox */
+
+	/* state machine */
+	islpci_state_t state;
+	int state_off;		/* enumeration of off-state, if 0 then
+				 * we're not in any off-state */
+
+	/* WPA stuff */
+	int wpa; /* WPA mode enabled */
+	struct list_head bss_wpa_list;
+	int num_bss_wpa;
+	struct semaphore wpa_sem;
+
+	struct work_struct reset_task;
+	int reset_task_pending;
+} islpci_private;
+
+static inline islpci_state_t
+islpci_get_state(islpci_private *priv)
+{
+	/* lock */
+	return priv->state;
+	/* unlock */
+}
+
+islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state);
+
+#define ISLPCI_TX_TIMEOUT               (2*HZ)
+
+irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
+
+int prism54_post_setup(islpci_private *, int);
+int islpci_reset(islpci_private *, int);
+
+static inline void
+islpci_trigger(islpci_private *priv)
+{
+	isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP,
+			       priv->device_base);
+}
+
+struct net_device_stats *islpci_statistics(struct net_device *);
+
+int islpci_free_memory(islpci_private *);
+struct net_device *islpci_setup(struct pci_dev *);
+#endif				/* _ISLPCI_DEV_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.c linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_eth.c
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_eth.c	2004-08-15 19:48:29.000000000 +0000
@@ -0,0 +1,518 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include "prismcompat.h"
+#include "isl_38xx.h"
+#include "islpci_eth.h"
+#include "islpci_mgt.h"
+#include "oid_mgt.h"
+
+/******************************************************************************
+    Network Interface functions
+******************************************************************************/
+void
+islpci_eth_cleanup_transmit(islpci_private *priv,
+			    isl38xx_control_block *control_block)
+{
+	struct sk_buff *skb;
+	u32 index;
+
+	/* compare the control block read pointer with the free pointer */
+	while (priv->free_data_tx !=
+	       le32_to_cpu(control_block->
+			   device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) {
+		/* read the index of the first fragment to be freed */
+		index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;
+
+		/* check for holes in the arrays caused by multi fragment frames 
+		 * searching for the last fragment of a frame */
+		if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
+			/* entry is the last fragment of a frame
+			 * free the skb structure and unmap pci memory */
+			skb = priv->data_low_tx[index];
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING,
+			      "cleanup skb %p skb->data %p skb->len %u truesize %u\n ",
+			      skb, skb->data, skb->len, skb->truesize);
+#endif
+
+			pci_unmap_single(priv->pdev,
+					 priv->pci_map_tx_address[index],
+					 skb->len, PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(skb);
+			skb = NULL;
+		}
+		/* increment the free data low queue pointer */
+		priv->free_data_tx++;
+	}
+}
+
+int
+islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	isl38xx_control_block *cb = priv->control_block;
+	u32 index;
+	dma_addr_t pci_map_address;
+	int frame_size;
+	isl38xx_fragment *fragment;
+	int offset;
+	struct sk_buff *newskb;
+	int newskb_offset;
+	unsigned long flags;
+	unsigned char wds_mac[6];
+	u32 curr_frag;
+	int err = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
+#endif
+
+	/* lock the driver code */
+	spin_lock_irqsave(&priv->slock, flags);
+
+	/* determine the amount of fragments needed to store the frame */
+
+	frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+	if (init_wds)
+		frame_size += 6;
+
+	/* check whether the destination queue has enough fragments for the frame */
+	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);
+	if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {
+		printk(KERN_ERR "%s: transmit device queue full when awake\n",
+		       ndev->name);
+		netif_stop_queue(ndev);
+
+		/* trigger the device */
+		isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,
+				  ISL38XX_DEV_INT_REG);
+		udelay(ISL38XX_WRITEIO_DELAY);
+
+		err = -EBUSY;
+		goto drop_free;
+	}
+	/* Check alignment and WDS frame formatting. The start of the packet should
+	 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes
+	 * and add WDS address information */
+	if (likely(((long) skb->data & 0x03) | init_wds)) {
+		/* get the number of bytes to add and re-allign */
+		offset = (4 - (long) skb->data) & 0x03;
+		offset += init_wds ? 6 : 0;
+
+		/* check whether the current skb can be used  */
+		if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
+			unsigned char *src = skb->data;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,
+			      init_wds);
+#endif
+
+			/* align the buffer on 4-byte boundary */
+			skb_reserve(skb, (4 - (long) skb->data) & 0x03);
+			if (init_wds) {
+				/* wds requires an additional address field of 6 bytes */
+				skb_put(skb, 6);
+#ifdef ISLPCI_ETH_DEBUG
+				printk("islpci_eth_transmit:wds_mac\n");
+#endif
+				memmove(skb->data + 6, src, skb->len);
+				memcpy(skb->data, wds_mac, 6);
+			} else {
+				memmove(skb->data, src, skb->len);
+			}
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
+			      src, skb->len);
+#endif
+		} else {
+			newskb =
+			    dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);
+			if (unlikely(newskb == NULL)) {
+				printk(KERN_ERR "%s: Cannot allocate skb\n",
+				       ndev->name);
+				err = -ENOMEM;
+				goto drop_free;
+			}
+			newskb_offset = (4 - (long) newskb->data) & 0x03;
+
+			/* Check if newskb->data is aligned */
+			if (newskb_offset)
+				skb_reserve(newskb, newskb_offset);
+
+			skb_put(newskb, init_wds ? skb->len + 6 : skb->len);
+			if (init_wds) {
+				memcpy(newskb->data + 6, skb->data, skb->len);
+				memcpy(newskb->data, wds_mac, 6);
+#ifdef ISLPCI_ETH_DEBUG
+				printk("islpci_eth_transmit:wds_mac\n");
+#endif
+			} else
+				memcpy(newskb->data, skb->data, skb->len);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",
+			      newskb->data, skb->data, skb->len, init_wds);
+#endif
+
+			newskb->dev = skb->dev;
+			dev_kfree_skb(skb);
+			skb = newskb;
+		}
+	}
+	/* display the buffer contents for debugging */
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* map the skb buffer to pci memory for DMA operation */
+	pci_map_address = pci_map_single(priv->pdev,
+					 (void *) skb->data, skb->len,
+					 PCI_DMA_TODEVICE);
+	if (unlikely(pci_map_address == 0)) {
+		printk(KERN_WARNING "%s: cannot map buffer to PCI\n",
+		       ndev->name);
+
+		err = -EIO;
+		goto drop_free;
+	}
+	/* Place the fragment in the control block structure. */
+	index = curr_frag % ISL38XX_CB_TX_QSIZE;
+	fragment = &cb->tx_data_low[index];
+
+	priv->pci_map_tx_address[index] = pci_map_address;
+	/* store the skb address for future freeing  */
+	priv->data_low_tx[index] = skb;
+	/* set the proper fragment start address and size information */
+	fragment->size = cpu_to_le16(frame_size);
+	fragment->flags = cpu_to_le16(0);	/* set to 1 if more fragments */
+	fragment->address = cpu_to_le32(pci_map_address);
+	curr_frag++;
+
+	/* The fragment address in the control block must have been
+	 * written before announcing the frame buffer to device. */
+	wmb();
+	cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);
+
+	if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD
+	    > ISL38XX_CB_TX_QSIZE) {
+		/* stop sends from upper layers */
+		netif_stop_queue(ndev);
+
+		/* set the full flag for the transmission queue */
+		priv->data_low_tx_full = 1;
+	}
+
+	/* trigger the device */
+	islpci_trigger(priv);
+
+	/* unlock the driver code */
+	spin_unlock_irqrestore(&priv->slock, flags);
+
+	/* set the transmission time */
+	ndev->trans_start = jiffies;
+	priv->statistics.tx_packets++;
+	priv->statistics.tx_bytes += skb->len;
+
+	return 0;
+
+      drop_free:
+	/* free the skbuf structure before aborting */
+	dev_kfree_skb(skb);
+	skb = NULL;
+
+	priv->statistics.tx_dropped++;
+	spin_unlock_irqrestore(&priv->slock, flags);
+	return err;
+}
+
+static inline int
+islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
+{
+	/* The card reports full 802.11 packets but with a 20 bytes
+	 * header and without the FCS. But there a is a bit that
+	 * indicates if the packet is corrupted :-) */
+	struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;
+	if (hdr->flags & 0x01)
+		/* This one is bad. Drop it ! */
+		return -1;
+	if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) {
+		struct avs_80211_1_header *avs;
+		/* extract the relevant data from the header */
+		u32 clock = le32_to_cpu(hdr->clock);
+		u8 rate = hdr->rate;
+		u16 freq = le16_to_cpu(hdr->freq);
+		u8 rssi = hdr->rssi;
+
+		skb_pull(*skb, sizeof (struct rfmon_header));
+
+		if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) {
+			struct sk_buff *newskb = skb_copy_expand(*skb,
+								 sizeof (struct
+									 avs_80211_1_header),
+								 0, GFP_ATOMIC);
+			if (newskb) {
+				dev_kfree_skb_irq(*skb);
+				*skb = newskb;
+			} else
+				return -1;
+			/* This behavior is not very subtile... */
+		}
+
+		/* make room for the new header and fill it. */
+		avs =
+		    (struct avs_80211_1_header *) skb_push(*skb,
+							   sizeof (struct
+								   avs_80211_1_header));
+		
+		avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
+		avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
+		avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+		avs->hosttime = cpu_to_be64(jiffies);
+		avs->phytype = cpu_to_be32(6);	/*OFDM: 6 for (g), 8 for (a) */
+		avs->channel = cpu_to_be32(channel_of_freq(freq));
+		avs->datarate = cpu_to_be32(rate * 5);
+		avs->antenna = cpu_to_be32(0);	/*unknown */
+		avs->priority = cpu_to_be32(0);	/*unknown */
+		avs->ssi_type = cpu_to_be32(3);	/*2: dBm, 3: raw RSSI */
+		avs->ssi_signal = cpu_to_be32(rssi & 0x7f);
+		avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise);	/*better than 'undefined', I assume */
+		avs->preamble = cpu_to_be32(0);	/*unknown */
+		avs->encoding = cpu_to_be32(0);	/*unknown */
+	} else
+		skb_pull(*skb, sizeof (struct rfmon_header));
+
+	(*skb)->protocol = htons(ETH_P_802_2);
+	(*skb)->mac.raw = (*skb)->data;
+	(*skb)->pkt_type = PACKET_OTHERHOST;
+
+	return 0;
+}
+
+int
+islpci_eth_receive(islpci_private *priv)
+{
+	struct net_device *ndev = priv->ndev;
+	isl38xx_control_block *control_block = priv->control_block;
+	struct sk_buff *skb;
+	u16 size;
+	u32 index, offset;
+	unsigned char *src;
+	int discard = 0;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
+#endif
+
+	/* the device has written an Ethernet frame in the data area
+	 * of the sk_buff without updating the structure, do it now */
+	index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE;
+	size = le16_to_cpu(control_block->rx_data_low[index].size);
+	skb = priv->data_low_rx[index];
+	offset = ((unsigned long)
+		  le32_to_cpu(control_block->rx_data_low[index].address) -
+		  (unsigned long) skb->data) & 3;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING,
+	      "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ",
+	      control_block->rx_data_low[priv->free_data_rx].address, skb->data,
+	      skb->len, offset, skb->truesize);
+#endif
+
+	/* delete the streaming DMA mapping before processing the skb */
+	pci_unmap_single(priv->pdev,
+			 priv->pci_map_rx_address[index],
+			 MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE);
+
+	/* update the skb structure and allign the buffer */
+	skb_put(skb, size);
+	if (offset) {
+		/* shift the buffer allocation offset bytes to get the right frame */
+		skb_pull(skb, 2);
+		skb_put(skb, 2);
+	}
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	/* display the buffer contents for debugging */
+	DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* check whether WDS is enabled and whether the data frame is a WDS frame */
+
+	if (init_wds) {
+		/* WDS enabled, check for the wds address on the first 6 bytes of the buffer */
+		src = skb->data + 6;
+		memmove(skb->data, src, skb->len - 6);
+		skb_trim(skb, skb->len - 6);
+	}
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb);
+	DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len);
+
+	/* display the buffer contents for debugging */
+	DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
+	display_buffer((char *) skb->data, skb->len);
+#endif
+
+	/* do some additional sk_buff and network layer parameters */
+	skb->dev = ndev;
+
+	/* take care of monitor mode and spy monitoring. */
+	if (unlikely(priv->iw_mode == IW_MODE_MONITOR))
+		discard = islpci_monitor_rx(priv, &skb);
+	else {
+		if (unlikely(skb->data[2 * ETH_ALEN] == 0)) {
+			/* The packet has a rx_annex. Read it for spy monitoring, Then
+			 * remove it, while keeping the 2 leading MAC addr.
+			 */
+			struct iw_quality wstats;
+			struct rx_annex_header *annex =
+			    (struct rx_annex_header *) skb->data;
+			wstats.level = annex->rfmon.rssi;
+			/* The noise value can be a bit outdated if nobody's 
+			 * reading wireless stats... */
+			wstats.noise = priv->local_iwstatistics.qual.noise;
+			wstats.qual = wstats.level - wstats.noise;
+			wstats.updated = 0x07;
+			/* Update spy records */
+			wireless_spy_update(ndev, annex->addr2, &wstats);
+
+			memcpy(skb->data + sizeof (struct rfmon_header),
+			       skb->data, 2 * ETH_ALEN);
+			skb_pull(skb, sizeof (struct rfmon_header));
+		}
+		skb->protocol = eth_type_trans(skb, ndev);
+	}
+	skb->ip_summed = CHECKSUM_NONE;
+	priv->statistics.rx_packets++;
+	priv->statistics.rx_bytes += size;
+
+	/* deliver the skb to the network layer */
+#ifdef ISLPCI_ETH_DEBUG
+	printk
+	    ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+	     skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+	     skb->data[4], skb->data[5]);
+#endif
+	if (unlikely(discard)) {
+		dev_kfree_skb_irq(skb);
+		skb = NULL;
+	} else
+		netif_rx(skb);
+
+	/* increment the read index for the rx data low queue */
+	priv->free_data_rx++;
+
+	/* add one or more sk_buff structures */
+	while (index =
+	       le32_to_cpu(control_block->
+			   driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]),
+	       index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) {
+		/* allocate an sk_buff for received data frames storage
+		 * include any required allignment operations */
+		skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2);
+		if (unlikely(skb == NULL)) {
+			/* error allocating an sk_buff structure elements */
+			DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
+			break;
+		}
+		skb_reserve(skb, (4 - (long) skb->data) & 0x03);
+		/* store the new skb structure pointer */
+		index = index % ISL38XX_CB_RX_QSIZE;
+		priv->data_low_rx[index] = skb;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_TRACING,
+		      "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ",
+		      skb, skb->data, skb->len, index, skb->truesize);
+#endif
+
+		/* set the streaming DMA mapping for proper PCI bus operation */
+		priv->pci_map_rx_address[index] =
+		    pci_map_single(priv->pdev, (void *) skb->data,
+				   MAX_FRAGMENT_SIZE_RX + 2,
+				   PCI_DMA_FROMDEVICE);
+		if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) {
+			/* error mapping the buffer to device accessable memory address */
+			DEBUG(SHOW_ERROR_MESSAGES,
+			      "Error mapping DMA address\n");
+
+			/* free the skbuf structure before aborting */
+			dev_kfree_skb_irq((struct sk_buff *) skb);
+			skb = NULL;
+			break;
+		}
+		/* update the fragment address */
+		control_block->rx_data_low[index].address = cpu_to_le32((u32)
+									priv->
+									pci_map_rx_address
+									[index]);
+		wmb();
+
+		/* increment the driver read pointer */
+		add_le32p((u32 *) &control_block->
+			  driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
+	}
+
+	/* trigger the device */
+	islpci_trigger(priv);
+
+	return 0;
+}
+
+void
+islpci_do_reset_and_wake(void *data)
+{
+	islpci_private *priv = (islpci_private *) data;
+	islpci_reset(priv, 1);
+	netif_wake_queue(priv->ndev);
+	priv->reset_task_pending = 0;
+}
+
+void
+islpci_eth_tx_timeout(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct net_device_stats *statistics = &priv->statistics;
+
+	/* increment the transmit error counter */
+	statistics->tx_errors++;
+
+	if (!priv->reset_task_pending) {
+		priv->reset_task_pending = 1;
+		netif_stop_queue(ndev);
+		schedule_work(&priv->reset_task);
+	}
+
+	return;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.h linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_eth.h
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_eth.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_eth.h	2004-08-15 19:50:32.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _ISLPCI_ETH_H
+#define _ISLPCI_ETH_H
+
+#include "isl_38xx.h"
+#include "islpci_dev.h"
+
+struct rfmon_header {
+	u16 unk0;		/* = 0x0000 */
+	u16 length;		/* = 0x1400 */
+	u32 clock;		/* 1MHz clock */
+	u8 flags;
+	u8 unk1;
+	u8 rate;
+	u8 unk2;
+	u16 freq;
+	u16 unk3;
+	u8 rssi;
+	u8 padding[3];
+} __attribute__ ((packed));
+
+struct rx_annex_header {
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	struct rfmon_header rfmon;
+} __attribute__ ((packed));
+
+/* wlan-ng (and hopefully others) AVS header, version one.  Fields in
+ * network byte order. */
+#define P80211CAPTURE_VERSION 0x80211001
+
+struct avs_80211_1_header {
+	uint32_t version;
+	uint32_t length;
+	uint64_t mactime;
+	uint64_t hosttime;
+	uint32_t phytype;
+	uint32_t channel;
+	uint32_t datarate;
+	uint32_t antenna;
+	uint32_t priority;
+	uint32_t ssi_type;
+	int32_t ssi_signal;
+	int32_t ssi_noise;
+	uint32_t preamble;
+	uint32_t encoding;
+};
+
+void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
+int islpci_eth_transmit(struct sk_buff *, struct net_device *);
+int islpci_eth_receive(islpci_private *);
+void islpci_eth_tx_timeout(struct net_device *);
+void islpci_do_reset_and_wake(void *data);
+
+#endif				/* _ISL_GEN_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_hotplug.c linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_hotplug.c
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_hotplug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_hotplug.c	2004-08-15 19:48:42.000000000 +0000
@@ -0,0 +1,494 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h> /* For __init, __exit */
+
+#include "prismcompat.h"
+#include "islpci_dev.h"
+#include "islpci_mgt.h"		/* for pc_debug */
+#include "isl_oid.h"
+
+#define DRV_NAME	"prism54"
+#define DRV_VERSION	"1.2"
+
+MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
+MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
+MODULE_LICENSE("GPL");
+
+static int	init_pcitm = 0;
+module_param(init_pcitm, int, 0);
+
+/* In this order: vendor, device, subvendor, subdevice, class, class_mask,
+ * driver_data 
+ * If you have an update for this please contact prism54-devel@prism54.org 
+ * The latest list can be found at http://prism54.org/supported_cards.php */
+static const struct pci_device_id prism54_id_tbl[] = {
+	/* 3COM 3CRWE154G72 Wireless LAN adapter */
+	{
+	 PCIVENDOR_3COM, PCIDEVICE_3COM6001,
+	 PCIVENDOR_3COM, PCIDEVICE_3COM6001,
+	 0, 0, 0
+	},
+
+	/* D-Link Air Plus Xtreme G A1 - DWL-g650 A1 */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_DLINK, 0x3202UL, 
+	 0, 0, 0
+	},
+
+	/* I-O Data WN-G54/CB - WN-G54/CB */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_IODATA, 0xd019UL, 
+	 0, 0, 0
+	},
+
+	/* Netgear WG511 */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_NETGEAR, 0x4800UL,
+	 0, 0, 0
+	},
+
+	/* Tekram Technology clones, Allnet, Netcomm, Zyxel */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_TTL, 0x1605UL,
+	 0, 0, 0
+	},
+
+	/* SMC2802W */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_SMC, 0x2802UL,
+	 0, 0, 0
+	},
+
+	/* SMC2835W */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_SMC, 0x2835UL,
+	 0, 0, 0
+	},
+
+	/* Corega CG-WLCB54GT */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_ATI, 0xc104UL,
+	 0, 0, 0
+	},
+
+	/* I4 Z-Com XG-600 */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_I4, 0x0014UL,
+	 0, 0, 0
+	},
+
+	/* I4 Z-Com XG-900  and clones Macer, Ovislink, Planex, Peabird, */
+	/* Sitecom, Xterasys */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_I4, 0x0020UL,
+	 0, 0, 0
+	},
+
+	/* SMC 2802W V2 */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_ACCTON, 0xee03UL,
+	 0, 0, 0
+	},
+
+	/* SMC 2835W V2 */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCIVENDOR_SMC, 0xa835UL,
+	 0, 0, 0
+	},
+
+	/* Intersil PRISM Indigo Wireless LAN adapter */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877,
+	 PCI_ANY_ID, PCI_ANY_ID,
+	 0, 0, 0
+	},
+
+	/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
+	/* Default */
+	{
+	 PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
+	 PCI_ANY_ID, PCI_ANY_ID,
+	 0, 0, 0
+	},
+
+	/* End of list */
+	{0,0,0,0,0,0,0}
+};
+
+/* register the device with the Hotplug facilities of the kernel */
+MODULE_DEVICE_TABLE(pci, prism54_id_tbl);
+
+static int prism54_probe(struct pci_dev *, const struct pci_device_id *);
+static void prism54_remove(struct pci_dev *);
+static int prism54_suspend(struct pci_dev *, u32 state);
+static int prism54_resume(struct pci_dev *);
+
+static struct pci_driver prism54_driver = {
+	.name = DRV_NAME,
+	.id_table = prism54_id_tbl,
+	.probe = prism54_probe,
+	.remove = prism54_remove,
+	.suspend = prism54_suspend,
+	.resume = prism54_resume,
+	/* .enable_wake ; we don't support this yet */
+};
+
+static void
+prism54_get_card_model(struct net_device *ndev)
+{
+	islpci_private	*priv;
+	char		*modelp;
+	int		notwork = 0;
+
+	priv = netdev_priv(ndev);
+	switch (priv->pdev->subsystem_device) {
+	case PCIDEVICE_ISL3877:
+		modelp = "PRISM Indigo";
+		break;
+	case PCIDEVICE_ISL3886:
+		modelp = "PRISM Javelin / Xbow";
+		break;
+	case PCIDEVICE_3COM6001:
+		modelp = "3COM 3CRWE154G72";
+		break;
+	case 0x3202UL:
+		modelp = "D-Link DWL-g650 A1";
+		break;
+	case 0xd019UL:
+		modelp = "WN-G54/CB";
+		break;
+	case 0x4800UL:
+		modelp = "Netgear WG511";
+		break;
+	case 0x2802UL:
+		modelp = "SMC2802W";
+		break;
+	case 0xee03UL:
+		modelp = "SMC2802W V2";
+		notwork = 1;
+		break;
+	case 0x2835UL:
+		modelp = "SMC2835W";
+		break;
+	case 0xa835UL:
+		modelp = "SMC2835W V2";
+		notwork = 1;
+		break;
+	case 0xc104UL:
+		modelp = "CG-WLCB54GT";
+		break;
+	case 0x1605UL:
+		modelp = "Tekram Technology clone";
+		break;
+	/* Let's leave this one out for now since it seems bogus/wrong 
+	 * Even if the manufacturer did use 0x0000UL it may not be correct
+	 * by their part, therefore deserving no name ;) */
+	/*      case 0x0000UL: 
+	 *              modelp = "SparkLAN WL-850F";
+	 *              break;*/
+
+	/* We have two reported for the one below :( */
+	case 0x0014UL:
+		modelp = "I4 Z-Com XG-600 and clones";
+		break;
+	case 0x0020UL:
+		modelp = "I4 Z-Com XG-900 and clones";
+		break;
+/* Default it */
+/*
+	case PCIDEVICE_ISL3890:
+		modelp = "PRISM Duette/GT";
+		break;
+*/
+	default:
+		modelp = "PRISM Duette/GT";
+	}
+	printk(KERN_DEBUG "%s: %s driver detected card model: %s\n",
+			ndev->name, DRV_NAME, modelp);
+	if ( notwork ) {
+		printk(KERN_DEBUG "%s: %s Warning - This may not work\n",
+			ndev->name, DRV_NAME);
+	}
+	return;
+}
+
+/******************************************************************************
+    Module initialization functions
+******************************************************************************/
+
+int
+prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net_device *ndev;
+	u8 latency_tmr;
+	u32 mem_addr;
+	islpci_private *priv;
+	int rvalue;
+
+	/* TRACE(DRV_NAME); */
+	
+	
+	/* Enable the pci device */
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME);
+		return -ENODEV;
+	}
+
+	/* check whether the latency timer is set correctly */
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr);
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr);
+#endif
+	if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) {
+		/* set the latency timer */
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+				      PCIDEVICE_LATENCY_TIMER_VAL);
+	}
+
+	/* enable PCI DMA */
+	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+		printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
+		goto do_pci_disable_device;
+        }
+
+	/* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT)
+	 * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT)
+	 * 	The RETRY_TIMEOUT is used to set the number of retries that the core, as a
+	 * 	Master, will perform before abandoning a cycle. The default value for
+	 * 	RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
+	 * 	devices. A write of zero to the RETRY_TIMEOUT register disables this
+	 * 	function to allow use with any non-compliant legacy devices that may
+	 * 	execute more retries.
+	 *
+	 * 	Writing zero to both these two registers will disable both timeouts and
+	 * 	*can* solve problems caused by devices that are slow to respond.
+	 *	Make this configurable - MSW
+	 */
+	if ( init_pcitm >= 0 ) {
+		pci_write_config_byte(pdev, 0x40, (u8)init_pcitm);
+		pci_write_config_byte(pdev, 0x41, (u8)init_pcitm);
+	} else {
+		printk(KERN_INFO "PCI TRDY/RETRY unchanged\n");
+	}
+
+	/* request the pci device I/O regions */
+	rvalue = pci_request_regions(pdev, DRV_NAME);
+	if (rvalue) {
+		printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n",
+		       DRV_NAME, rvalue);
+		goto do_pci_disable_device;
+	}
+
+	/* check if the memory window is indeed set */
+	rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr);
+	if (rvalue || !mem_addr) {
+		printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n",
+		       DRV_NAME);
+		goto do_pci_disable_device;
+	}
+
+	/* enable PCI bus-mastering */
+	DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME);
+	pci_set_master(pdev);
+
+	/* enable MWI */
+	pci_set_mwi(pdev);
+
+	/* setup the network device interface and its structure */
+	if (!(ndev = islpci_setup(pdev))) {
+		/* error configuring the driver as a network device */
+		printk(KERN_ERR "%s: could not configure network device\n",
+		       DRV_NAME);
+		goto do_pci_release_regions;
+	}
+
+	priv = netdev_priv(ndev);
+	islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */
+
+	/* card is in unknown state yet, might have some interrupts pending */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* request for the interrupt before uploading the firmware */
+	rvalue = request_irq(pdev->irq, &islpci_interrupt,
+			     SA_SHIRQ, ndev->name, priv);
+
+	if (rvalue) {
+		/* error, could not hook the handler to the irq */
+		printk(KERN_ERR "%s: could not install IRQ handler\n",
+		       ndev->name);
+		goto do_unregister_netdev;
+	}
+
+	/* firmware upload is triggered in islpci_open */
+
+	/* Pretty card model discovery output */
+	prism54_get_card_model(ndev);
+
+	return 0;
+
+      do_unregister_netdev:
+	unregister_netdev(ndev);
+	islpci_free_memory(priv);
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+      do_pci_release_regions:
+	pci_release_regions(pdev);
+      do_pci_disable_device:
+	pci_disable_device(pdev);
+	return -EIO;
+}
+
+/* set by cleanup_module */
+static volatile int __in_cleanup_module = 0;
+
+/* this one removes one(!!) instance only */
+void
+prism54_remove(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
+	BUG_ON(!priv);
+
+	if (!__in_cleanup_module) {
+		printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name);
+		islpci_set_state(priv, PRV_STATE_OFF);
+	}
+
+	printk(KERN_DEBUG "%s: removing device\n", ndev->name);
+
+	unregister_netdev(ndev);
+
+	/* free the interrupt request */
+
+	if (islpci_get_state(priv) != PRV_STATE_OFF) {
+		isl38xx_disable_interrupts(priv->device_base);
+		islpci_set_state(priv, PRV_STATE_OFF);
+		/* This bellow causes a lockup at rmmod time. It might be
+		 * because some interrupts still linger after rmmod time, 
+		 * see bug #17 */
+		/* pci_set_power_state(pdev, 3);*/	/* try to power-off */
+	}
+
+	free_irq(pdev->irq, priv);
+
+	/* free the PCI memory and unmap the remapped page */
+	islpci_free_memory(priv);
+
+	pci_set_drvdata(pdev, 0);
+	free_netdev(ndev);
+	priv = 0;
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+}
+
+int
+prism54_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
+	BUG_ON(!priv);
+
+	printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
+	       ndev->name, state);
+
+	pci_save_state(pdev, priv->pci_state);
+
+	/* tell the device not to trigger interrupts for now... */
+	isl38xx_disable_interrupts(priv->device_base);
+
+	/* from now on assume the hardware was already powered down
+	   and don't touch it anymore */
+	islpci_set_state(priv, PRV_STATE_OFF);
+
+	netif_stop_queue(ndev);
+	netif_device_detach(ndev);
+
+	return 0;
+}
+
+int
+prism54_resume(struct pci_dev *pdev)
+{
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
+	BUG_ON(!priv);
+
+	printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
+
+	pci_restore_state(pdev, priv->pci_state);
+
+	/* alright let's go into the PREBOOT state */
+	islpci_reset(priv, 1);
+
+	netif_device_attach(ndev);
+	netif_start_queue(ndev);
+
+	return 0;
+}
+
+static int __init
+prism54_module_init(void)
+{
+	printk(KERN_INFO "Loaded %s driver, version %s\n",
+	       DRV_NAME, DRV_VERSION);
+
+	__bug_on_wrong_struct_sizes ();
+
+	return pci_module_init(&prism54_driver);
+}
+
+/* by the time prism54_module_exit() terminates, as a postcondition
+ * all instances will have been destroyed by calls to
+ * prism54_remove() */
+static void __exit
+prism54_module_exit(void)
+{
+	__in_cleanup_module = 1;
+
+	pci_unregister_driver(&prism54_driver);
+
+	printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME);
+
+	__in_cleanup_module = 0;
+}
+
+/* register entry points */
+module_init(prism54_module_init);
+module_exit(prism54_module_exit);
+/* EOF */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.c linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_mgt.c
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_mgt.c	2004-08-15 19:47:53.000000000 +0000
@@ -0,0 +1,510 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/if_arp.h>
+
+#include "prismcompat.h"
+#include "isl_38xx.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"		/* additional types and defs for isl38xx fw */
+#include "isl_ioctl.h"
+
+#include <net/iw_handler.h>
+
+/******************************************************************************
+        Global variable definition section
+******************************************************************************/
+int pc_debug = VERBOSE;
+module_param(pc_debug, int, 0);
+
+/******************************************************************************
+    Driver general functions
+******************************************************************************/
+void
+display_buffer(char *buffer, int length)
+{
+	if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0)
+		return;
+
+	while (length > 0) {
+		printk("[%02x]", *buffer & 255);
+		length--;
+		buffer++;
+	}
+
+	printk("\n");
+}
+
+/*****************************************************************************
+    Queue handling for management frames
+******************************************************************************/
+
+/*
+ * Helper function to create a PIMFOR management frame header.
+ */
+static void
+pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h)
+{
+	h->version = PIMFOR_VERSION;
+	h->operation = operation;
+	h->device_id = PIMFOR_DEV_ID_MHLI_MIB;
+	h->flags = 0;
+	h->oid = cpu_to_be32(oid);
+	h->length = cpu_to_be32(length);
+}
+
+/*
+ * Helper function to analyze a PIMFOR management frame header.
+ */
+static pimfor_header_t *
+pimfor_decode_header(void *data, int len)
+{
+	pimfor_header_t *h = data;
+
+	while ((void *) h < data + len) {
+		if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) {
+			le32_to_cpus(&h->oid);
+			le32_to_cpus(&h->length);
+		} else {
+			be32_to_cpus(&h->oid);
+			be32_to_cpus(&h->length);
+		}
+		if (h->oid != OID_INL_TUNNEL)
+			return h;
+		h++;
+	}
+	return NULL;
+}
+
+/*
+ * Fill the receive queue for management frames with fresh buffers.
+ */
+int
+islpci_mgmt_rx_fill(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	isl38xx_control_block *cb =	/* volatile not needed */
+	    (isl38xx_control_block *) priv->control_block;
+	u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n");
+#endif
+
+	while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
+		u32 index = curr % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_rx[index];
+		isl38xx_fragment *frag = &cb->rx_data_mgmt[index];
+
+		if (buf->mem == NULL) {
+			buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC);
+			if (!buf->mem) {
+				printk(KERN_WARNING
+				       "Error allocating management frame.\n");
+				return -ENOMEM;
+			}
+			buf->size = MGMT_FRAME_SIZE;
+		}
+		if (buf->pci_addr == 0) {
+			buf->pci_addr = pci_map_single(priv->pdev, buf->mem,
+						       MGMT_FRAME_SIZE,
+						       PCI_DMA_FROMDEVICE);
+			if (!buf->pci_addr) {
+				printk(KERN_WARNING
+				       "Failed to make memory DMA'able\n.");
+				return -ENOMEM;
+			}
+		}
+
+		/* be safe: always reset control block information */
+		frag->size = cpu_to_le16(MGMT_FRAME_SIZE);
+		frag->flags = 0;
+		frag->address = cpu_to_le32(buf->pci_addr);
+		curr++;
+
+		/* The fragment address in the control block must have
+		 * been written before announcing the frame buffer to
+		 * device */
+		wmb();
+		cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr);
+	}
+	return 0;
+}
+
+/*
+ * Create and transmit a management frame using "operation" and "oid",
+ * with arguments data/length.
+ * We either return an error and free the frame, or we return 0 and
+ * islpci_mgt_cleanup_transmit() frees the frame in the tx-done
+ * interrupt.
+ */
+static int
+islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
+		    void *data, int length)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	isl38xx_control_block *cb =
+	    (isl38xx_control_block *) priv->control_block;
+	void *p;
+	int err = -EINVAL;
+	unsigned long flags;
+	isl38xx_fragment *frag;
+	struct islpci_membuf buf;
+	u32 curr_frag;
+	int index;
+	int frag_len = length + PIMFOR_HEADER_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n");
+#endif
+
+	if (frag_len > MGMT_FRAME_SIZE) {
+		printk(KERN_DEBUG "%s: mgmt frame too large %d\n",
+		       ndev->name, frag_len);
+		goto error;
+	}
+
+	err = -ENOMEM;
+	p = buf.mem = kmalloc(frag_len, GFP_KERNEL);
+	if (!buf.mem) {
+		printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n",
+		       ndev->name);
+		goto error;
+	}
+	buf.size = frag_len;
+
+	/* create the header directly in the fragment data area */
+	pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p);
+	p += PIMFOR_HEADER_SIZE;
+
+	if (data)
+		memcpy(p, data, length);
+	else
+		memset(p, 0, length);
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	{
+		pimfor_header_t *h = buf.mem;
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n",
+		      h->operation, oid, h->device_id, h->flags, length);
+
+		/* display the buffer contents for debugging */
+		display_buffer((char *) h, sizeof (pimfor_header_t));
+		display_buffer(p, length);
+	}
+#endif
+
+	err = -ENOMEM;
+	buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len,
+				      PCI_DMA_TODEVICE);
+	if (!buf.pci_addr) {
+		printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n",
+		       ndev->name);
+		goto error_free;
+	}
+
+	/* Protect the control block modifications against interrupts. */
+	spin_lock_irqsave(&priv->slock, flags);
+	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]);
+	if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) {
+		printk(KERN_WARNING "%s: mgmt tx queue is still full\n",
+		       ndev->name);
+		goto error_unlock;
+	}
+
+	/* commit the frame to the tx device queue */
+	index = curr_frag % ISL38XX_CB_MGMT_QSIZE;
+	priv->mgmt_tx[index] = buf;
+	frag = &cb->tx_data_mgmt[index];
+	frag->size = cpu_to_le16(frag_len);
+	frag->flags = 0;	/* for any other than the last fragment, set to 1 */
+	frag->address = cpu_to_le32(buf.pci_addr);
+
+	/* The fragment address in the control block must have
+	 * been written before announcing the frame buffer to
+	 * device */
+	wmb();
+	cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1);
+	spin_unlock_irqrestore(&priv->slock, flags);
+
+	/* trigger the device */
+	islpci_trigger(priv);
+	return 0;
+
+      error_unlock:
+	spin_unlock_irqrestore(&priv->slock, flags);
+      error_free:
+	kfree(buf.mem);
+      error:
+	return err;
+}
+
+/*
+ * Receive a management frame from the device.
+ * This can be an arbitrary number of traps, and at most one response
+ * frame for a previous request sent via islpci_mgt_transmit().
+ */
+int
+islpci_mgt_receive(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	isl38xx_control_block *cb =
+	    (isl38xx_control_block *) priv->control_block;
+	u32 curr_frag;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
+#endif
+
+	/* Only once per interrupt, determine fragment range to
+	 * process.  This avoids an endless loop (i.e. lockup) if
+	 * frames come in faster than we can process them. */
+	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]);
+	barrier();
+
+	for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) {
+		pimfor_header_t *header;
+		u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_rx[index];
+		u16 frag_len;
+		int size;
+		struct islpci_mgmtframe *frame;
+
+		/* I have no idea (and no documentation) if flags != 0
+		 * is possible.  Drop the frame, reuse the buffer. */
+		if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) {
+			printk(KERN_WARNING "%s: unknown flags 0x%04x\n",
+			       ndev->name,
+			       le16_to_cpu(cb->rx_data_mgmt[index].flags));
+			continue;
+		}
+
+		/* The device only returns the size of the header(s) here. */
+		frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size);
+
+		/*
+		 * We appear to have no way to tell the device the
+		 * size of a receive buffer.  Thus, if this check
+		 * triggers, we likely have kernel heap corruption. */
+		if (frag_len > MGMT_FRAME_SIZE) {
+			printk(KERN_WARNING
+				"%s: Bogus packet size of %d (%#x).\n",
+				ndev->name, frag_len, frag_len);
+			frag_len = MGMT_FRAME_SIZE;
+		}
+
+		/* Ensure the results of device DMA are visible to the CPU. */
+		pci_dma_sync_single(priv->pdev, buf->pci_addr,
+				    buf->size, PCI_DMA_FROMDEVICE);
+
+		/* Perform endianess conversion for PIMFOR header in-place. */
+		header = pimfor_decode_header(buf->mem, frag_len);
+		if (!header) {
+			printk(KERN_WARNING "%s: no PIMFOR header found\n",
+			       ndev->name);
+			continue;
+		}
+
+		/* The device ID from the PIMFOR packet received from
+		 * the MVC is always 0.  We forward a sensible device_id.
+		 * Not that anyone upstream would care... */
+		header->device_id = priv->ndev->ifindex;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
+		      header->operation, header->oid, header->device_id,
+		      header->flags, header->length);
+
+		/* display the buffer contents for debugging */
+		display_buffer((char *) header, PIMFOR_HEADER_SIZE);
+		display_buffer((char *) header + PIMFOR_HEADER_SIZE,
+			       header->length);
+#endif
+
+		/* nobody sends these */
+		if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) {
+			printk(KERN_DEBUG
+			       "%s: errant PIMFOR application frame\n",
+			       ndev->name);
+			continue;
+		}
+
+		/* Determine frame size, skipping OID_INL_TUNNEL headers. */
+		size = PIMFOR_HEADER_SIZE + header->length;
+		frame = kmalloc(sizeof (struct islpci_mgmtframe) + size,
+				GFP_ATOMIC);
+		if (!frame) {
+			printk(KERN_WARNING
+			       "%s: Out of memory, cannot handle oid 0x%08x\n",
+			       ndev->name, header->oid);
+			continue;
+		}
+		frame->ndev = ndev;
+		memcpy(&frame->buf, header, size);
+		frame->header = (pimfor_header_t *) frame->buf;
+		frame->data = frame->buf + PIMFOR_HEADER_SIZE;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+		DEBUG(SHOW_PIMFOR_FRAMES,
+		      "frame: header: %p, data: %p, size: %d\n",
+		      frame->header, frame->data, size);
+#endif
+
+		if (header->operation == PIMFOR_OP_TRAP) {
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			printk(KERN_DEBUG
+			       "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n",
+			       header->oid, header->device_id, header->flags,
+			       header->length);
+#endif
+
+			/* Create work to handle trap out of interrupt
+			 * context. */
+			INIT_WORK(&frame->ws, prism54_process_trap, frame);
+			schedule_work(&frame->ws);
+
+		} else {
+			/* Signal the one waiting process that a response
+			 * has been received. */
+			if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) {
+				printk(KERN_WARNING
+				       "%s: mgmt response not collected\n",
+				       ndev->name);
+				kfree(frame);
+			}
+#if VERBOSE > SHOW_ERROR_MESSAGES
+			DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n");
+#endif
+			wake_up(&priv->mgmt_wqueue);
+		}
+
+	}
+
+	return 0;
+}
+
+/*
+ * Cleanup the transmit queue by freeing all frames handled by the device.
+ */
+void
+islpci_mgt_cleanup_transmit(struct net_device *ndev)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	isl38xx_control_block *cb =	/* volatile not needed */
+	    (isl38xx_control_block *) priv->control_block;
+	u32 curr_frag;
+
+#if VERBOSE > SHOW_ERROR_MESSAGES
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n");
+#endif
+
+	/* Only once per cleanup, determine fragment range to
+	 * process.  This avoids an endless loop (i.e. lockup) if
+	 * the device became confused, incrementing device_curr_frag
+	 * rapidly. */
+	curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]);
+	barrier();
+
+	for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) {
+		int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE;
+		struct islpci_membuf *buf = &priv->mgmt_tx[index];
+		pci_unmap_single(priv->pdev, buf->pci_addr, buf->size,
+				 PCI_DMA_TODEVICE);
+		buf->pci_addr = 0;
+		kfree(buf->mem);
+		buf->mem = NULL;
+		buf->size = 0;
+	}
+}
+
+/*
+ * Perform one request-response transaction to the device.
+ */
+int
+islpci_mgt_transaction(struct net_device *ndev,
+		       int operation, unsigned long oid,
+		       void *senddata, int sendlen,
+		       struct islpci_mgmtframe **recvframe)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
+	long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
+	int err;
+	DEFINE_WAIT(wait);
+
+	*recvframe = NULL;
+
+	if (down_interruptible(&priv->mgmt_sem))
+		return -ERESTARTSYS;
+
+	prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
+	err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen);
+	if (err)
+		goto out;
+
+	err = -ETIMEDOUT;
+	while (timeout_left > 0) {
+		int timeleft;
+		struct islpci_mgmtframe *frame;
+
+		timeleft = schedule_timeout(wait_cycle_jiffies);
+		frame = xchg(&priv->mgmt_received, NULL);
+		if (frame) {
+			if (frame->header->oid == oid) {
+				*recvframe = frame;
+				err = 0;
+				goto out;
+			} else {
+				printk(KERN_DEBUG
+				       "%s: expecting oid 0x%x, received 0x%x.\n",
+				       ndev->name, (unsigned int) oid,
+				       frame->header->oid);
+				kfree(frame);
+				frame = NULL;
+			}
+		}
+		if (timeleft == 0) {
+			printk(KERN_DEBUG
+				"%s: timeout waiting for mgmt response %lu, "
+				"triggering device\n",
+				ndev->name, timeout_left);
+			islpci_trigger(priv);
+		}
+		timeout_left += timeleft - wait_cycle_jiffies;
+	}
+	printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
+	       ndev->name);
+
+	/* TODO: we should reset the device here */     
+ out:
+	finish_wait(&priv->mgmt_wqueue, &wait);
+	up(&priv->mgmt_sem);
+	return err;
+}
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.h linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_mgt.h
--- linux-2.4.27/drivers/net/wireless/prism54/islpci_mgt.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/islpci_mgt.h	2004-08-15 19:51:46.000000000 +0000
@@ -0,0 +1,162 @@
+/*
+ *  
+ *  Copyright (C) 2002 Intersil Americas Inc.
+ *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _ISLPCI_MGT_H
+#define _ISLPCI_MGT_H
+
+#include <linux/wireless.h>
+#include <linux/skbuff.h>
+
+/*
+ *  Function definitions
+ */
+
+#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0)
+#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args)
+
+#define TRACE(devname)   K_DEBUG(SHOW_TRACING, VERBOSE, "%s:  -> " __FUNCTION__ "()\n", devname)
+
+extern int pc_debug;
+#define init_wds 0	/* help compiler optimize away dead code */
+
+
+/* General driver definitions */
+#define PCIVENDOR_INTERSIL                      0x1260UL
+#define PCIVENDOR_3COM				0x10b7UL
+#define PCIVENDOR_DLINK				0x1186UL
+#define PCIVENDOR_I4				0x17cfUL
+#define PCIVENDOR_IODATA			0x10fcUL
+#define PCIVENDOR_NETGEAR			0x1385UL
+#define PCIVENDOR_SMC				0x10b8UL
+#define PCIVENDOR_ACCTON			0x1113UL
+#define PCIVENDOR_ATI				0x1259UL
+#define PCIVENDOR_TTL				0x16a5UL
+
+#define PCIDEVICE_ISL3877                       0x3877UL
+#define PCIDEVICE_ISL3886                       0x3886UL
+#define PCIDEVICE_ISL3890                       0x3890UL
+#define	PCIDEVICE_3COM6001			0x6001UL
+#define PCIDEVICE_LATENCY_TIMER_MIN 		0x40
+#define PCIDEVICE_LATENCY_TIMER_VAL 		0x50
+
+/* Debugging verbose definitions */
+#define SHOW_NOTHING                            0x00	/* overrules everything */
+#define SHOW_ANYTHING                           0xFF
+#define SHOW_ERROR_MESSAGES                     0x01
+#define SHOW_TRAPS                              0x02
+#define SHOW_FUNCTION_CALLS                     0x04
+#define SHOW_TRACING                            0x08
+#define SHOW_QUEUE_INDEXES                      0x10
+#define SHOW_PIMFOR_FRAMES                      0x20
+#define SHOW_BUFFER_CONTENTS                    0x40
+#define VERBOSE                                 0x01
+
+/* Default card definitions */
+#define CARD_DEFAULT_CHANNEL                    6
+#define CARD_DEFAULT_MODE                       INL_MODE_CLIENT
+#define CARD_DEFAULT_IW_MODE			IW_MODE_INFRA
+#define CARD_DEFAULT_BSSTYPE                    DOT11_BSSTYPE_INFRA
+#define CARD_DEFAULT_CLIENT_SSID		""
+#define CARD_DEFAULT_AP_SSID			"default"
+#define CARD_DEFAULT_KEY1                       "default_key_1"
+#define CARD_DEFAULT_KEY2                       "default_key_2"
+#define CARD_DEFAULT_KEY3                       "default_key_3"
+#define CARD_DEFAULT_KEY4                       "default_key_4"
+#define CARD_DEFAULT_WEP                        0
+#define CARD_DEFAULT_FILTER                     0
+#define CARD_DEFAULT_WDS                        0
+#define	CARD_DEFAULT_AUTHEN                     DOT11_AUTH_OS
+#define	CARD_DEFAULT_DOT1X			0
+#define CARD_DEFAULT_MLME_MODE			DOT11_MLME_AUTO
+#define CARD_DEFAULT_CONFORMANCE                OID_INL_CONFORMANCE_NONE
+#define CARD_DEFAULT_PROFILE			DOT11_PROFILE_MIXED_G_WIFI
+#define CARD_DEFAULT_MAXFRAMEBURST		DOT11_MAXFRAMEBURST_MIXED_SAFE
+
+/* PIMFOR package definitions */
+#define PIMFOR_ETHERTYPE                        0x8828
+#define PIMFOR_HEADER_SIZE                      12
+#define PIMFOR_VERSION                          1
+#define PIMFOR_OP_GET                           0
+#define PIMFOR_OP_SET                           1
+#define PIMFOR_OP_RESPONSE                      2
+#define PIMFOR_OP_ERROR                         3
+#define PIMFOR_OP_TRAP                          4
+#define PIMFOR_OP_RESERVED                      5	/* till 255 */
+#define PIMFOR_DEV_ID_MHLI_MIB                  0
+#define PIMFOR_FLAG_APPLIC_ORIGIN               0x01
+#define PIMFOR_FLAG_LITTLE_ENDIAN               0x02
+
+static inline void
+add_le32p(u32 * le_number, u32 add)
+{
+	*le_number = cpu_to_le32(le32_to_cpup(le_number) + add);
+}
+
+void display_buffer(char *, int);
+
+/*
+ *  Type definition section
+ *
+ *  the structure defines only the header allowing copyless
+ *  frame handling
+ */
+typedef struct {
+	u8 version;
+	u8 operation;
+	u32 oid;
+	u8 device_id;
+	u8 flags;
+	u32 length;
+} __attribute__ ((packed))
+pimfor_header_t;
+
+/* A received and interrupt-processed management frame, either for
+ * schedule_work(prism54_process_trap) or for priv->mgmt_received,
+ * processed by islpci_mgt_transaction(). */
+struct islpci_mgmtframe {
+	struct net_device *ndev;      /* pointer to network device */
+	pimfor_header_t *header;      /* payload header, points into buf */
+	void *data;		      /* payload ex header, points into buf */
+        struct work_struct ws;	      /* argument for schedule_work() */
+	char buf[0];		      /* fragment buffer */
+};
+
+int
+islpci_mgt_receive(struct net_device *ndev);
+
+int
+islpci_mgmt_rx_fill(struct net_device *ndev);
+
+void
+islpci_mgt_cleanup_transmit(struct net_device *ndev);
+
+int
+islpci_mgt_transaction(struct net_device *ndev,
+                       int operation, unsigned long oid,
+		       void *senddata, int sendlen,
+		       struct islpci_mgmtframe **recvframe);
+
+static inline void
+islpci_mgt_release(struct islpci_mgmtframe *frame)
+{
+        kfree(frame);
+}
+
+#endif				/* _ISLPCI_MGT_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.c linux-2.4.28-pre1/drivers/net/wireless/prism54/oid_mgt.c
--- linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/oid_mgt.c	2004-08-15 19:49:27.000000000 +0000
@@ -0,0 +1,807 @@
+/*   
+ *  Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "prismcompat.h"
+#include "islpci_dev.h"
+#include "islpci_mgt.h"
+#include "isl_oid.h"
+#include "oid_mgt.h"
+#include "isl_ioctl.h"
+
+/* to convert between channel and freq */
+const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+	2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+int
+channel_of_freq(int f)
+{
+	int c = 0;
+
+	if ((f >= 2412) && (f <= 2484)) {
+		while ((c < 14) && (f != frequency_list_bg[c]))
+			c++;
+		return (c >= 14) ? 0 : ++c;
+	} else if ((f >= (int) 5000) && (f <= (int) 6000)) {
+		return ( (f - 5000) / 5 );
+	} else
+		return 0;
+}
+
+#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t}
+#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED)
+#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32)
+#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32)
+#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME)
+#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX)
+
+#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0)
+
+struct oid_t isl_oid[] = {
+	OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR),
+	OID_U32(GEN_OID_LINKSTATE, 0x00000001),
+	OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002),
+	OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003),
+	OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004),
+	OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005),
+
+	/* 802.11 */
+	OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000),
+	OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW),
+	OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid,
+		     OID_TYPE_SSID),
+	OID_U32(DOT11_OID_STATE, 0x10000003),
+	OID_U32(DOT11_OID_AID, 0x10000004),
+	OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW),
+	OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid,
+		     OID_TYPE_SSID),
+
+	OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000),
+	OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001),
+	OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002),
+	OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003),
+	OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004),
+	OID_U32(DOT11_OID_CFPPERIOD, 0x11000005),
+	OID_U32(DOT11_OID_CFPDURATION, 0x11000006),
+
+	OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000),
+	OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001),
+	OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002),
+	OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003),
+	[DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key),
+			       OID_FLAG_CACHED | OID_TYPE_KEY},	/* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */
+	OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008),
+	OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009),
+	OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a),
+
+	OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000),
+	OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001),
+	OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002),
+	OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003),
+
+	OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000),
+	OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001),
+	OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002),
+	OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003),
+	OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004),
+	OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005),
+	OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006),
+	OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007),
+
+	OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000),
+	OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001),
+	OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002),
+	OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003),
+	OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004),
+	OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005),
+	OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006),
+
+	[DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0},
+	OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008),
+
+	OID_U32(DOT11_OID_PSM, 0x14000000),
+	OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001),
+	OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002),
+	OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003),
+
+	OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000),
+	OID_U32(DOT11_OID_CLIENTS, 0x15000001),
+	OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002),
+	[DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0},	/* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */
+
+	OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR),
+	OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR),
+	OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0),
+	OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1),
+	OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2),
+
+	OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000),
+	OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001),
+	OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002),
+	OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003),
+	OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004),
+	OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005),
+	OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006),
+	OID_U32(DOT11_OID_RTSFAILED, 0x16000007),
+	OID_U32(DOT11_OID_ACKFAILED, 0x16000008),
+	OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009),
+	OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A),
+	OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B),
+	OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C),
+
+	OID_U32(DOT11_OID_SLOTTIME, 0x17000000),
+	OID_U32(DOT11_OID_CWMIN, 0x17000001),
+	OID_U32(DOT11_OID_CWMAX, 0x17000002),
+	OID_U32(DOT11_OID_ACKWINDOW, 0x17000003),
+	OID_U32(DOT11_OID_ANTENNARX, 0x17000004),
+	OID_U32(DOT11_OID_ANTENNATX, 0x17000005),
+	OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006),
+	OID_U32_C(DOT11_OID_CHANNEL, 0x17000007),
+	OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008),
+	OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009),
+	OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1],
+		   OID_TYPE_RAW),
+	OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B),
+	OID_U32(DOT11_OID_CCAMODE, 0x1700000C),
+	OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D),
+	OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E),
+	OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F),
+	OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010,
+		   u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
+	OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011),
+	[DOT11_OID_SUPPORTEDFREQUENCIES] =
+	    {0x17000012, 0, sizeof (struct obj_frequencies)
+	     + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES},
+
+	OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013),
+	OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1],
+		   OID_TYPE_RAW),
+	OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015),
+	OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016),
+	OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017),
+	OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018),
+	OID_U32(DOT11_OID_PROFILES, 0x17000019),
+	OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020,
+		   u8[IWMAX_BITRATES + 1], OID_TYPE_RAW),
+
+	OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000),
+	OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001),
+	OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002),
+	OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003),
+	OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004),
+	OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005),
+	OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006),
+	OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007),
+	OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008),
+	OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009),
+	OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A),
+	OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B),
+	OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C),
+
+	OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000),
+
+	OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
+	OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
+	OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
+	OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003),
+	OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
+		     OID_TYPE_BUFFER),
+
+	OID_U32(DOT11_OID_BSSS, 0x1C000000),
+	[DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss),
+			    OID_TYPE_BSS},	/*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */
+	OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS),
+	[DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct
+						      obj_bsslist) +
+			       sizeof (struct obj_bss[IWMAX_BSS]),
+			       OID_TYPE_BSSLIST},
+
+	OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000),
+	OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001),
+	OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002),
+	OID_U32_C(OID_INL_MODE, 0xFF020003),
+	OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004),
+	OID_UNKNOWN(OID_INL_VERSION, 0xFF020005),
+	OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006),
+	OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007),
+	OID_U32_C(OID_INL_CONFIG, 0xFF020008),
+	OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C),
+	OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D),
+	OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F),
+
+};
+
+int
+mgt_init(islpci_private *priv)
+{
+	int i;
+
+	priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL);
+	if (!priv->mib)
+		return -ENOMEM;
+
+	memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *));
+
+	/* Alloc the cache */
+	for (i = 0; i < OID_NUM_LAST; i++) {
+		if (isl_oid[i].flags & OID_FLAG_CACHED) {
+			priv->mib[i] = kmalloc(isl_oid[i].size *
+					       (isl_oid[i].range + 1),
+					       GFP_KERNEL);
+			if (!priv->mib[i])
+				return -ENOMEM;
+			memset(priv->mib[i], 0,
+			       isl_oid[i].size * (isl_oid[i].range + 1));
+		} else
+			priv->mib[i] = NULL;
+	}
+
+	init_rwsem(&priv->mib_sem);
+	prism54_mib_init(priv);
+
+	return 0;
+}
+
+void
+mgt_clean(islpci_private *priv)
+{
+	int i;
+
+	if (!priv->mib)
+		return;
+	for (i = 0; i < OID_NUM_LAST; i++)
+		if (priv->mib[i]) {
+			kfree(priv->mib[i]);
+			priv->mib[i] = NULL;
+		}
+	kfree(priv->mib);
+	priv->mib = NULL;
+}
+
+void
+mgt_le_to_cpu(int type, void *data)
+{
+	switch (type) {
+	case OID_TYPE_U32:
+		*(u32 *) data = le32_to_cpu(*(u32 *) data);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = data;
+			buff->size = le32_to_cpu(buff->size);
+			buff->addr = le32_to_cpu(buff->addr);
+			break;
+		}
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = data;
+			bss->age = le16_to_cpu(bss->age);
+			bss->channel = le16_to_cpu(bss->channel);
+			bss->capinfo = le16_to_cpu(bss->capinfo);
+			bss->rates = le16_to_cpu(bss->rates);
+			bss->basic_rates = le16_to_cpu(bss->basic_rates);
+			break;
+		}
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = data;
+			int i;
+			list->nr = le32_to_cpu(list->nr);
+			for (i = 0; i < list->nr; i++)
+				mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]);
+			break;
+		}
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = data;
+			int i;
+			freq->nr = le16_to_cpu(freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				freq->mhz[i] = le16_to_cpu(freq->mhz[i]);
+			break;
+		}
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = data;
+			mlme->id = le16_to_cpu(mlme->id);
+			mlme->state = le16_to_cpu(mlme->state);
+			mlme->code = le16_to_cpu(mlme->code);
+			break;
+		}
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = data;
+			mlme->id = le16_to_cpu(mlme->id);
+			mlme->state = le16_to_cpu(mlme->state);
+			mlme->code = le16_to_cpu(mlme->code);
+			mlme->size = le16_to_cpu(mlme->size);
+			break;
+		}
+	case OID_TYPE_SSID:
+	case OID_TYPE_KEY:
+	case OID_TYPE_ADDR:
+	case OID_TYPE_RAW:
+		break;
+	default:
+		BUG();
+	}
+}
+
+static void
+mgt_cpu_to_le(int type, void *data)
+{
+	switch (type) {
+	case OID_TYPE_U32:
+		*(u32 *) data = cpu_to_le32(*(u32 *) data);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = data;
+			buff->size = cpu_to_le32(buff->size);
+			buff->addr = cpu_to_le32(buff->addr);
+			break;
+		}
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = data;
+			bss->age = cpu_to_le16(bss->age);
+			bss->channel = cpu_to_le16(bss->channel);
+			bss->capinfo = cpu_to_le16(bss->capinfo);
+			bss->rates = cpu_to_le16(bss->rates);
+			bss->basic_rates = cpu_to_le16(bss->basic_rates);
+			break;
+		}
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = data;
+			int i;
+			list->nr = cpu_to_le32(list->nr);
+			for (i = 0; i < list->nr; i++)
+				mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]);
+			break;
+		}
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = data;
+			int i;
+			freq->nr = cpu_to_le16(freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				freq->mhz[i] = cpu_to_le16(freq->mhz[i]);
+			break;
+		}
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = data;
+			mlme->id = cpu_to_le16(mlme->id);
+			mlme->state = cpu_to_le16(mlme->state);
+			mlme->code = cpu_to_le16(mlme->code);
+			break;
+		}
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = data;
+			mlme->id = cpu_to_le16(mlme->id);
+			mlme->state = cpu_to_le16(mlme->state);
+			mlme->code = cpu_to_le16(mlme->code);
+			mlme->size = cpu_to_le16(mlme->size);
+			break;
+		}
+	case OID_TYPE_SSID:
+	case OID_TYPE_KEY:
+	case OID_TYPE_ADDR:
+	case OID_TYPE_RAW:
+		break;
+	default:
+		BUG();
+	}
+}
+
+/* Note : data is modified during this function */
+
+int
+mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data)
+{
+	int ret = 0;
+	struct islpci_mgmtframe *response = NULL;
+	int response_op = PIMFOR_OP_ERROR;
+	int dlen;
+	void *cache, *_data = data;
+	u32 oid;
+
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(extra > isl_oid[n].range);
+
+	if (!priv->mib)
+		/* memory has been freed */
+		return -1;
+
+	dlen = isl_oid[n].size;
+	cache = priv->mib[n];
+	cache += (cache ? extra * dlen : 0);
+	oid = isl_oid[n].oid + extra;
+
+	if (_data == NULL)
+		/* we are requested to re-set a cached value */
+		_data = cache;
+	else
+		mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data);
+	/* If we are going to write to the cache, we don't want anyone to read
+	 * it -> acquire write lock.
+	 * Else we could acquire a read lock to be sure we don't bother the
+	 * commit process (which takes a write lock). But I'm not sure if it's
+	 * needed.
+	 */
+	if (cache)
+		down_write(&priv->mib_sem);
+
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
+					     _data, dlen, &response);
+		if (!ret) {
+			response_op = response->header->operation;
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR)
+			ret = -EIO;
+	} else if (!cache)
+		ret = -EIO;
+
+	if (cache) {
+		if (!ret && data)
+			memcpy(cache, _data, dlen);
+		up_write(&priv->mib_sem);
+	}
+
+	/* re-set given data to what it was */
+	if (data)
+		mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+	return ret;
+}
+
+int
+mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
+		union oid_res_t *res)
+{
+
+	int ret = -EIO;
+	int reslen = 0;
+	struct islpci_mgmtframe *response = NULL;
+
+	int dlen;
+	void *cache, *_res = NULL;
+	u32 oid;
+
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(extra > isl_oid[n].range);
+
+	if (!priv->mib)
+		/* memory has been freed */
+		return -1;
+
+	dlen = isl_oid[n].size;
+	cache = priv->mib[n];
+	cache += cache ? extra * dlen : 0;
+	oid = isl_oid[n].oid + extra;
+	reslen = dlen;
+
+	if (cache)
+		down_read(&priv->mib_sem);
+
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+					     oid, data, dlen, &response);
+		if (ret || !response ||
+		    response->header->operation == PIMFOR_OP_ERROR) {
+			if (response)
+				islpci_mgt_release(response);
+			ret = -EIO;
+		}
+		if (!ret) {
+			_res = response->data;
+			reslen = response->header->length;
+		}
+	} else if (cache) {
+		_res = cache;
+		ret = 0;
+	}
+	if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32)
+		res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res);
+	else {
+		res->ptr = kmalloc(reslen, GFP_KERNEL);
+		BUG_ON(res->ptr == NULL);
+		if (ret)
+			memset(res->ptr, 0, reslen);
+		else {
+			memcpy(res->ptr, _res, reslen);
+			mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE,
+				      res->ptr);
+		}
+	}
+	if (cache)
+		up_read(&priv->mib_sem);
+
+	if (response && !ret)
+		islpci_mgt_release(response);
+
+	if (reslen > isl_oid[n].size)
+		printk(KERN_DEBUG
+		       "mgt_get_request(0x%x): received data length was bigger "
+		       "than expected (%d > %d). Memory is probably corrupted...",
+		       oid, reslen, isl_oid[n].size);
+
+	return ret;
+}
+
+/* lock outside */
+int
+mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n)
+{
+	int i, ret = 0;
+	struct islpci_mgmtframe *response;
+
+	for (i = 0; i < n; i++) {
+		struct oid_t *t = &(isl_oid[l[i]]);
+		void *data = priv->mib[l[i]];
+		int j = 0;
+		u32 oid = t->oid;
+		BUG_ON(data == NULL);
+		while (j <= t->range) {
+			response = NULL;
+			ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+						      oid, data, t->size,
+						      &response);
+			if (response) {
+				ret |= (response->header->operation ==
+					PIMFOR_OP_ERROR);
+				islpci_mgt_release(response);
+			}
+			j++;
+			oid++;
+			data += t->size;
+		}
+	}
+	return ret;
+}
+
+/* Lock outside */
+
+void
+mgt_set(islpci_private *priv, enum oid_num_t n, void *data)
+{
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(priv->mib[n] == NULL);
+
+	memcpy(priv->mib[n], data, isl_oid[n].size);
+	mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]);
+}
+
+void
+mgt_get(islpci_private *priv, enum oid_num_t n, void *res)
+{
+	BUG_ON(OID_NUM_LAST <= n);
+	BUG_ON(priv->mib[n] == NULL);
+	BUG_ON(res == NULL);
+
+	memcpy(res, priv->mib[n], isl_oid[n].size);
+	mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res);
+}
+
+/* Commits the cache. Lock outside. */
+
+static enum oid_num_t commit_part1[] = {
+	OID_INL_CONFIG,
+	OID_INL_MODE,
+	DOT11_OID_BSSTYPE,
+	DOT11_OID_CHANNEL,
+	DOT11_OID_MLMEAUTOLEVEL
+};
+
+static enum oid_num_t commit_part2[] = {
+	DOT11_OID_SSID,
+	DOT11_OID_PSMBUFFER,
+	DOT11_OID_AUTHENABLE,
+	DOT11_OID_PRIVACYINVOKED,
+	DOT11_OID_EXUNENCRYPTED,
+	DOT11_OID_DEFKEYX,	/* MULTIPLE */
+	DOT11_OID_DEFKEYID,
+	DOT11_OID_DOT1XENABLE,
+	OID_INL_DOT11D_CONFORMANCE,
+	OID_INL_OUTPUTPOWER,
+};
+
+/* update the MAC addr. */
+static int
+mgt_update_addr(islpci_private *priv)
+{
+	struct islpci_mgmtframe *res = NULL;
+	int ret;
+
+	ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
+				     isl_oid[GEN_OID_MACADDRESS].oid, NULL,
+				     isl_oid[GEN_OID_MACADDRESS].size, &res);
+
+	if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR))
+		memcpy(priv->ndev->dev_addr, res->data, 6);
+	else
+		ret = -EIO;
+	if (res)
+		islpci_mgt_release(res);
+
+	return ret;
+}
+
+void
+mgt_commit(islpci_private *priv)
+{
+	int rvalue;
+	u32 u;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return;
+
+	rvalue = mgt_commit_list(priv, commit_part1,
+				 sizeof (commit_part1) /
+				 sizeof (commit_part1[0]));
+
+	if (priv->iw_mode != IW_MODE_MONITOR)
+		rvalue |= mgt_commit_list(priv, commit_part2,
+					  sizeof (commit_part2) /
+					  sizeof (commit_part2[0]));
+
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+	rvalue |= mgt_update_addr(priv);
+
+	if (rvalue) {
+		/* some request have failed. The device might be in an
+		   incoherent state. We should reset it ! */
+		printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
+		       "device \n", priv->ndev->name);
+	}
+}
+
+/* This will tell you if you are allowed to answer a mlme(ex) request .*/
+
+int
+mgt_mlme_answer(islpci_private *priv)
+{
+	u32 mlmeautolevel;
+	/* Acquire a read lock because if we are in a mode change, it's
+	 * possible to answer true, while the card is leaving master to managed
+	 * mode. Answering to a mlme in this situation could hang the card.
+	 */
+	down_read(&priv->mib_sem);
+	mlmeautolevel =
+	    le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]);
+	up_read(&priv->mib_sem);
+
+	return ((priv->iw_mode == IW_MODE_MASTER) &&
+		(mlmeautolevel >= DOT11_MLME_INTERMEDIATE));
+}
+
+enum oid_num_t
+mgt_oidtonum(u32 oid)
+{
+	int i;
+
+	for (i = 0; i < OID_NUM_LAST; i++)
+		if (isl_oid[i].oid == oid)
+			return i;
+
+	printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid);
+
+	return OID_NUM_LAST;
+}
+
+int
+mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
+{
+	switch (isl_oid[n].flags & OID_FLAG_TYPE) {
+	case OID_TYPE_U32:
+		return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u);
+		break;
+	case OID_TYPE_BUFFER:{
+			struct obj_buffer *buff = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"size=%u\naddr=0x%X\n", buff->size,
+					buff->addr);
+		}
+		break;
+	case OID_TYPE_BSS:{
+			struct obj_bss *bss = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"age=%u\nchannel=%u\n"
+					"capinfo=0x%X\nrates=0x%X\n"
+					"basic_rates=0x%X\n", bss->age,
+					bss->channel, bss->capinfo,
+					bss->rates, bss->basic_rates);
+		}
+		break;
+	case OID_TYPE_BSSLIST:{
+			struct obj_bsslist *list = r->ptr;
+			int i, k;
+			k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
+			for (i = 0; i < list->nr; i++)
+				k += snprintf(str + k, PRIV_STR_SIZE - k,
+					      "bss[%u] : \nage=%u\nchannel=%u\n"
+					      "capinfo=0x%X\nrates=0x%X\n"
+					      "basic_rates=0x%X\n",
+					      i, list->bsslist[i].age,
+					      list->bsslist[i].channel,
+					      list->bsslist[i].capinfo,
+					      list->bsslist[i].rates,
+					      list->bsslist[i].basic_rates);
+			return k;
+		}
+		break;
+	case OID_TYPE_FREQUENCIES:{
+			struct obj_frequencies *freq = r->ptr;
+			int i, t;
+			printk("nr : %u\n", freq->nr);
+			t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr);
+			for (i = 0; i < freq->nr; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "mhz[%u]=%u\n", i, freq->mhz[i]);
+			return t;
+		}
+		break;
+	case OID_TYPE_MLME:{
+			struct obj_mlme *mlme = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=0x%X\nstate=0x%X\ncode=0x%X\n",
+					mlme->id, mlme->state, mlme->code);
+		}
+		break;
+	case OID_TYPE_MLMEEX:{
+			struct obj_mlmeex *mlme = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=0x%X\nstate=0x%X\n"
+					"code=0x%X\nsize=0x%X\n", mlme->id,
+					mlme->state, mlme->code, mlme->size);
+		}
+		break;
+	case OID_TYPE_SSID:{
+			struct obj_ssid *ssid = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"length=%u\noctets=%.*s\n",
+					ssid->length, ssid->length,
+					ssid->octets);
+		}
+		break;
+	case OID_TYPE_KEY:{
+			struct obj_key *key = r->ptr;
+			int t, i;
+			t = snprintf(str, PRIV_STR_SIZE,
+				     "type=0x%X\nlength=0x%X\nkey=0x",
+				     key->type, key->length);
+			for (i = 0; i < key->length; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "%02X:", key->key[i]);
+			t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
+			return t;
+		}
+		break;
+	case OID_TYPE_RAW:
+	case OID_TYPE_ADDR:{
+			unsigned char *buff = r->ptr;
+			int t, i;
+			t = snprintf(str, PRIV_STR_SIZE, "hex data=");
+			for (i = 0; i < isl_oid[n].size; i++)
+				t += snprintf(str + t, PRIV_STR_SIZE - t,
+					      "%02X:", buff[i]);
+			t += snprintf(str + t, PRIV_STR_SIZE - t, "\n");
+			return t;
+		}
+		break;
+	default:
+		BUG();
+	}
+	return 0;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.h linux-2.4.28-pre1/drivers/net/wireless/prism54/oid_mgt.h
--- linux-2.4.27/drivers/net/wireless/prism54/oid_mgt.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/oid_mgt.h	2004-08-15 19:49:20.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#if !defined(_OID_MGT_H)
+#define _OID_MGT_H
+
+#include "isl_oid.h"
+#include "islpci_dev.h"
+
+extern struct oid_t isl_oid[];
+
+int mgt_init(islpci_private *);
+
+void mgt_clean(islpci_private *);
+
+/* I don't know where to put these 3 */
+extern const int frequency_list_bg[];
+extern const int frequency_list_a[];
+int channel_of_freq(int);
+
+void mgt_le_to_cpu(int, void *);
+
+int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
+
+int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
+		    union oid_res_t *);
+
+int mgt_commit_list(islpci_private *, enum oid_num_t *, int);
+
+void mgt_set(islpci_private *, enum oid_num_t, void *);
+
+void mgt_get(islpci_private *, enum oid_num_t, void *);
+
+void mgt_commit(islpci_private *);
+
+int mgt_mlme_answer(islpci_private *);
+
+enum oid_num_t mgt_oidtonum(u32 oid);
+
+int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *);
+
+#endif				/* !defined(_OID_MGT_H) */
+/* EOF */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/prismcompat.h linux-2.4.28-pre1/drivers/net/wireless/prism54/prismcompat.h
--- linux-2.4.27/drivers/net/wireless/prism54/prismcompat.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/prismcompat.h	2004-08-15 19:47:43.000000000 +0000
@@ -0,0 +1,46 @@
+/*  
+ *  (C) 2004 Margit Schubert-While <margitsw@t-online.de>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*  
+ *	Compatibility header file to aid support of different kernel versions
+ */
+
+#ifdef PRISM54_COMPAT24
+#include "prismcompat24.h"
+#else	/* PRISM54_COMPAT24 */
+
+#ifndef _PRISM_COMPAT_H
+#define _PRISM_COMPAT_H
+
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/config.h>
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+#include <linux/compiler.h>
+
+#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
+#error Firmware Loading is not configured in the kernel !
+#endif
+
+#define prism54_synchronize_irq(irq) synchronize_irq(irq)
+
+#define PRISM_FW_PDEV		&priv->pdev->dev
+
+#endif				/* _PRISM_COMPAT_H */
+#endif				/* PRISM54_COMPAT24 */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/net/wireless/prism54/prismcompat24.h linux-2.4.28-pre1/drivers/net/wireless/prism54/prismcompat24.h
--- linux-2.4.27/drivers/net/wireless/prism54/prismcompat24.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/net/wireless/prism54/prismcompat24.h	2004-08-15 19:48:34.000000000 +0000
@@ -0,0 +1,72 @@
+/*  
+ *  (C) 2004 Margit Schubert-While <margitsw@t-online.de>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*  
+ *	Compatibility header file to aid support of different kernel versions
+ */
+
+#ifndef _PRISM_COMPAT_H
+#define _PRISM_COMPAT_H
+
+#include <linux/firmware.h>
+#include <linux/config.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/compiler.h>
+#include <linux/netdevice.h>
+#include <asm/uaccess.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25)
+#define module_param(x, y, z)	MODULE_PARM(x, "i")
+#else
+#include <linux/moduleparam.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+#define free_netdev(x)		kfree(x)
+#define pci_name(x)		x->slot_name
+#define irqreturn_t		void
+#define IRQ_HANDLED
+#define IRQ_NONE
+#else
+#include <linux/interrupt.h>
+#endif
+
+#define work_struct		tq_struct
+#define INIT_WORK		INIT_TQUEUE
+#define schedule_work		schedule_task
+
+#if !defined(HAVE_NETDEV_PRIV)
+#define netdev_priv(x)		x->priv
+#endif
+
+#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)
+#error Firmware Loading is not configured in the kernel !
+#endif
+
+#define prism54_synchronize_irq(irq) synchronize_irq()
+
+#define DEFINE_WAIT(y)			DECLARE_WAITQUEUE(y, current)
+#define prepare_to_wait(x, y, z)	set_current_state(z); \
+					add_wait_queue(x, y)
+#define finish_wait(x, y)		remove_wait_queue(x, y); \
+					set_current_state(TASK_RUNNING)
+
+#define PRISM_FW_PDEV		pci_name(priv->pdev)
+
+#endif				/* _PRISM_COMPAT_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/parport/parport_pc.c linux-2.4.28-pre1/drivers/parport/parport_pc.c
--- linux-2.4.27/drivers/parport/parport_pc.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/parport/parport_pc.c	2004-08-15 19:49:41.000000000 +0000
@@ -414,7 +414,8 @@ static size_t parport_pc_epp_read_data (
 				left -= 16;
 			} else {
 				/* grab single byte from the warp fifo */
-				*((char *)buf)++ = inb (EPPDATA (port));
+				*((char *)buf) = inb (EPPDATA (port));
+				buf++;
 				got++;
 				left--;
 			}
@@ -441,7 +442,8 @@ static size_t parport_pc_epp_read_data (
 		return length;
 	}
 	for (; got < length; got++) {
-		*((char*)buf)++ = inb (EPPDATA(port));
+		*((char*)buf) = inb (EPPDATA(port));
+		buf++;
 		if (inb (STATUS (port)) & 0x01) {
 			/* EPP timeout */
 			clear_epp_timeout (port);
@@ -470,7 +472,8 @@ static size_t parport_pc_epp_write_data 
 		return length;
 	}
 	for (; written < length; written++) {
-		outb (*((char*)buf)++, EPPDATA(port));
+		outb (*((char*)buf), EPPDATA(port));
+		buf++;
 		if (inb (STATUS(port)) & 0x01) {
 			clear_epp_timeout (port);
 			break;
@@ -494,7 +497,8 @@ static size_t parport_pc_epp_read_addr (
 		return length;
 	}
 	for (; got < length; got++) {
-		*((char*)buf)++ = inb (EPPADDR (port));
+		*((char*)buf) = inb (EPPADDR (port));
+		buf++;
 		if (inb (STATUS (port)) & 0x01) {
 			clear_epp_timeout (port);
 			break;
@@ -519,7 +523,8 @@ static size_t parport_pc_epp_write_addr 
 		return length;
 	}
 	for (; written < length; written++) {
-		outb (*((char*)buf)++, EPPADDR (port));
+		outb (*((char*)buf), EPPADDR (port));
+		buf++;
 		if (inb (STATUS (port)) & 0x01) {
 			clear_epp_timeout (port);
 			break;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/pcmcia/bulkmem.c linux-2.4.28-pre1/drivers/pcmcia/bulkmem.c
--- linux-2.4.27/drivers/pcmcia/bulkmem.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.28-pre1/drivers/pcmcia/bulkmem.c	2004-08-15 19:52:10.000000000 +0000
@@ -301,7 +301,7 @@ int MTDHelperEntry(int func, void *a1, v
     {
 	window_handle_t w;
         int ret = pcmcia_request_window(a1, a2, &w);
-        (window_handle_t *)a1 = w;
+        a1 = w;
 	return  ret;
     }
         break;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/s390/net/c7000.c linux-2.4.28-pre1/drivers/s390/net/c7000.c
--- linux-2.4.27/drivers/s390/net/c7000.c	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.28-pre1/drivers/s390/net/c7000.c	2004-08-15 19:49:12.000000000 +0000
@@ -3,6 +3,20 @@
 	Author: Bob Scardapane (UTS Global LLC).
 	Version: 3.
 
+	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, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
 	To use this driver, run the LINUX command:
 
 	insmod c7000 base0=0xYYYY lhost0=s1 uhost0=s2 lappl0=s3 uappl0=s4 dbg=x
@@ -409,16 +423,7 @@ static char	ifnames[MAX_C7000][8] = {"ci
 	One device structure per controller.
 */
 
-/* RBH Try out the new code for 2.4.0 */
-#define NEWSTUFF
-
-#ifdef NEWSTUFF
-#define STRUCT_NET_DEVICE struct net_device
-#else
-#define STRUCT_NET_DEVICE struct device
-#endif
-
-STRUCT_NET_DEVICE	c7000_devices[MAX_C7000];
+struct net_device	c7000_devices[MAX_C7000];
 
 /*
 	Scratch variable filled in with controller name.
@@ -432,6 +437,7 @@ static char	*controller;
 
 MODULE_AUTHOR("Robert Scardapane (UTS Global)");
 MODULE_DESCRIPTION("Network module for Cisco 7000 box.");
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(base0, "1i");
 MODULE_PARM_DESC(base0, "Base unit address for 1st C7000 box.");
@@ -521,16 +527,12 @@ struct	c7000_unit {
 	ccw1_t				ccws[5];	/* control ccws */
 	int				devno;		/* device number */
 	int				irq;		/* subchannel number */
-	int				IO_active;	/* IO activity flag */
+	unsigned long			IO_active;	/* IO activity flag */
 	int				state;		/* fsm state */
 	int				retries;	/* retry counter */
 	unsigned long			flag_a;		/* bh activity flag */
 	devstat_t			devstat;	/* device status */
-#ifdef NEWSTUFF
 	wait_queue_head_t		wait;		/* sleep q head */
-#else
-	struct wait_queue		*wait;		/* sleep q pointer */
-#endif
 	struct c7000_controller		*cntlp;		/* controller pointer */
 	struct c7000_buffer		*free;		/* free buffer anchor */
 	struct c7000_buffer		*proc_head;	/* proc head */
@@ -551,7 +553,7 @@ struct	c7000_unit {
 
 struct c7000_controller {
 	struct	net_device_stats	stats;		/* statistics */
-	STRUCT_NET_DEVICE		*dev;		/* -> device struct */
+	struct net_device		*dev;		/* -> device struct */
 	unsigned int			base_addr;	/* base address */
 	char				lappl[NAMLEN];	/* local appl */
 	char				lhost[NAMLEN];	/* local host */
@@ -560,9 +562,7 @@ struct c7000_controller {
 	unsigned char			version;	/* version = 2 */
 	unsigned char			linkid;		/* link id */
 	struct	c7000_unit		cunits[NUNITS];	/* embedded units */
-#ifdef NEWSTUFF
-	int				tbusy;
-#endif
+	unsigned long			tbusy;
 };
 
 /*
@@ -579,62 +579,29 @@ struct	c7000_rd_header {
 	Set the device structure transmission busy flag.
 */
 
-#ifdef NEWSTUFF
 #define c7000_set_busy(dev) netif_stop_queue(dev)
-#else
-static __inline__ void
-c7000_set_busy(STRUCT_NET_DEVICE *dev)
-{
-	dev->tbusy = 1;
-	eieio();
-	return;
-}
-#endif
 	
 /*
 	Clear the device structure transmission busy flag.
 */
 
-#ifdef NEWSTUFF
 #define c7000_clear_busy(dev) netif_wake_queue(dev)
-#else
-static __inline__ void
-c7000_clear_busy(STRUCT_NET_DEVICE *dev)
-{
-	dev->tbusy = 0;
-	eieio();
-	return;
-}
-#endif
 
 /*
 	Extract the device structure transmission busy flag.
 */
 
-#ifdef NEWSTUFF
 #define c7000_check_busy(dev) netif_queue_stopped(dev)
-#else
-static __inline__ int
-c7000_check_busy(STRUCT_NET_DEVICE *dev)
-{
-	eieio();
-	return(dev->tbusy);
-}
-#endif
 
 /*
 	Set a bit in the device structure transmission busy flag.
 */
 
 static __inline__ void
-c7000_setbit_busy(int nr, STRUCT_NET_DEVICE *dev)
+c7000_setbit_busy(int nr, struct net_device *dev)
 {
-#ifdef NEWSTUFF
 	netif_stop_queue(dev);
 	test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
-#else
-	set_bit(nr, (void *)&dev->tbusy);
-#endif
 	return;
 }
 
@@ -643,14 +610,10 @@ c7000_setbit_busy(int nr, STRUCT_NET_DEV
 */
 
 static __inline__ void
-c7000_clearbit_busy(int nr, STRUCT_NET_DEVICE *dev)
+c7000_clearbit_busy(int nr, struct net_device *dev)
 {
-#ifdef NEWSTUFF
 	clear_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
 	netif_wake_queue(dev);
-#else
-	clear_bit(nr, (void *)&dev->tbusy);
-#endif
 	return;
 }
 
@@ -659,14 +622,10 @@ c7000_clearbit_busy(int nr, STRUCT_NET_D
 */
 
 static __inline__ int
-c7000_ts_busy(int nr, STRUCT_NET_DEVICE *dev)
+c7000_ts_busy(int nr, struct net_device *dev)
 {
-#ifdef NEWSTUFF
 	netif_stop_queue(dev);
 	return test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy);
-#else
-	return(test_and_set_bit(nr, (void *)&dev->tbusy));
-#endif
 }
 
 /*
@@ -678,7 +637,7 @@ c7000_error(struct c7000_controller *ccp
 {
 	int			i;
 	struct	c7000_unit	*cup;
-	STRUCT_NET_DEVICE	*dev = ccp->dev;
+	struct net_device	*dev = ccp->dev;
 
 	for (i = 0; i < NUNITS; i++) {
 		cup = &ccp->cunits[i];
@@ -686,12 +645,8 @@ c7000_error(struct c7000_controller *ccp
 	}
 
 	if (dev != NULL)
-#ifdef NEWSTUFF
 		/* RBH XXX Should we be doing this? */
 		dev->state &= ~__LINK_STATE_START;
-#else
-		dev->flags &= ~IFF_RUNNING;
-#endif
 
 	CPrintk(0, "c7000: c7000_error: base unit 0x%x is down\n", ccp->base_addr);
 	return;
@@ -759,9 +714,9 @@ c7000_check_devices(int devno)
 static int
 c7000_haltio(struct c7000_unit *cup)
 {
-	__u32			parm;
+	unsigned long		parm;
 	__u8			flags = 0x00;
-	__u32			saveflags;
+	unsigned long		saveflags;
 	DECLARE_WAITQUEUE(wait, current);
 	int			rc;
 
@@ -792,9 +747,9 @@ c7000_haltio(struct c7000_unit *cup)
 static int
 c7000_doio(struct c7000_unit *cup)
 {
-	__u32			parm;
+	unsigned long		parm;
 	__u8			flags = 0x00;
-	__u32			saveflags;
+	unsigned long		saveflags;
 	DECLARE_WAITQUEUE(wait, current);
 	int			rc;
 
@@ -1013,7 +968,7 @@ c7000_bld_read_chpgm(struct c7000_unit *
 */
 
 static int
-c7000_alloc_buffers(STRUCT_NET_DEVICE *dev)
+c7000_alloc_buffers(struct net_device *dev)
 {
 	int				i;
 	int				j;
@@ -1030,9 +985,10 @@ c7000_alloc_buffers(STRUCT_NET_DEVICE *d
 			bufptr = kmalloc(sizeof(struct c7000_buffer), GFP_KERNEL);
 			data = kmalloc(C7000_BUFSIZE, GFP_KERNEL);
 
-			if (bufptr == NULL)
-			{
-				if(data)
+			if (bufptr == NULL || data == NULL) {
+				if (bufptr)
+					kfree(bufptr);
+				if (data)
 					kfree(data);
 				return(-1);
 			}
@@ -1088,7 +1044,7 @@ c7000_free_chain(struct c7000_buffer *bu
 */
 
 static void
-c7000_free_buffers(STRUCT_NET_DEVICE *dev)
+c7000_free_buffers(struct net_device *dev)
 {
 	int				i;
 	struct	c7000_controller	*ccp = (struct c7000_controller *) dev->priv;
@@ -1328,12 +1284,12 @@ c7000_irq_bh(struct c7000_unit *cup)
 	struct	c7000_rd_header		*head;	
 	struct	sk_buff			*skb;
 	struct	c7000_controller	*ccp;
-	STRUCT_NET_DEVICE		*dev;
+	struct	net_device		*dev;
 	int				rc;
 	__u16				data_length;
-	__u32				parm;
+	unsigned long			parm;
 	__u8				flags = 0x00;
-	__u32				saveflags;
+	unsigned long			saveflags;
 
 	ccp = cup->cntlp;
 	dev = ccp->dev;
@@ -1385,6 +1341,7 @@ c7000_irq_bh(struct c7000_unit *cup)
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			netif_rx(skb);
 			ccp->stats.rx_packets++;
+			ccp->stats.rx_bytes += skb->len;
 		} else {
 			CPrintk(0, "c7000: c7000_irq_bh: can not allocate a skb for unit 0x%x\n", cup->devno);
 			ccp->stats.rx_dropped++;
@@ -1403,6 +1360,7 @@ c7000_irq_bh(struct c7000_unit *cup)
 			Rechain the buffer on the running channel program.
 		*/
 
+		buf->ccws[3].cda = buf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[6]);
 		if (pbuf != NULL)
 			pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]);
 
@@ -1422,7 +1380,7 @@ c7000_irq_bh(struct c7000_unit *cup)
 			return;
 		}
 
-		parm = (__u32)cup;
+		parm = (unsigned long)cup;
 		cup->state = C7000_READ;
 
 		if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
@@ -1979,7 +1937,7 @@ c7000_get_conn(struct c7000_unit *cup)
 */
 
 struct net_device_stats *
-c7000_stats(STRUCT_NET_DEVICE *dev)
+c7000_stats(struct net_device *dev)
 {
 	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
 
@@ -1991,13 +1949,13 @@ c7000_stats(STRUCT_NET_DEVICE *dev)
 */
 
 static int
-c7000_open(STRUCT_NET_DEVICE *dev)
+c7000_open(struct net_device *dev)
 {
 	int				i;
 	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
 	struct	c7000_unit		*cup;
 	int				rc;
-	__u32				parm;
+	unsigned long			parm;
 	__u8				flags = 0x00;
 
 	c7000_set_busy(dev);
@@ -2025,16 +1983,11 @@ c7000_open(STRUCT_NET_DEVICE *dev)
 			half routine.
 		*/
 
-#ifndef NEWSTUFF
-		cup->tq.next = NULL;
-#endif
 		cup->tq.sync = 0;
 		cup->tq.routine = (void *)(void *)c7000_irq_bh;
 		cup->tq.data = cup;
 		cup->state = C7000_HALT;
-#ifdef NEWSTUFF
 		init_waitqueue_head(&cup->wait);
-#endif
 		CPrintk(1, "c7000: c7000_open: issuing halt to unit 0x%x\n", cup->devno);
 
 		/*
@@ -2154,7 +2107,7 @@ c7000_open(STRUCT_NET_DEVICE *dev)
 	*/
 
 	cup->state = C7000_READ;
-	parm = (__u32) cup;
+	parm = (unsigned long)cup;
 	set_bit(0, (void *)&cup->IO_active);
 
 	if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
@@ -2165,11 +2118,7 @@ c7000_open(STRUCT_NET_DEVICE *dev)
 		return(-EIO);
 	}
 
-#ifdef NEWSTUFF
 	netif_start_queue(dev);
-#else
-	dev->start = 1;
-#endif
 	CPrintk(0, "c7000: c7000_open: base unit 0x%lx is opened\n", dev->base_addr);
 	c7000_clear_busy(dev);
 	MOD_INC_USE_COUNT;	/* increment module usage count */
@@ -2181,18 +2130,13 @@ c7000_open(STRUCT_NET_DEVICE *dev)
 */
 
 static int
-c7000_stop(STRUCT_NET_DEVICE *dev)
+c7000_stop(struct net_device *dev)
 {
 	int				i;
 	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
 	struct	c7000_unit		*cup;
 	int				rc;
 
-#ifdef NEWSTUFF
-/* nothing? */
-#else
-	dev->start = 0;
-#endif
 	c7000_set_busy(dev);
 
 	/*
@@ -2236,7 +2180,7 @@ c7000_stop(STRUCT_NET_DEVICE *dev)
 */
 
 static int
-c7000_config(STRUCT_NET_DEVICE *dev, struct ifmap *map)
+c7000_config(struct net_device *dev, struct ifmap *map)
 {
 	CPrintk(1, "c7000: c7000_config: entered for base unit 0x%lx\n", dev->base_addr);
 	return(0);
@@ -2247,12 +2191,12 @@ c7000_config(STRUCT_NET_DEVICE *dev, str
 */
 
 static int
-c7000_xmit(struct sk_buff *skb, STRUCT_NET_DEVICE *dev)
+c7000_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct	c7000_controller	*ccp = (struct c7000_controller *)dev->priv;
 	struct	c7000_unit		*cup;
-	__u32				saveflags;
-	__u32				parm;
+	unsigned long			saveflags;
+	unsigned long			parm;
 	__u8				flags = 0x00;
 	struct	c7000_buffer		*buf, *pbuf;
 	int				rc;
@@ -2350,7 +2294,7 @@ c7000_xmit(struct sk_buff *skb, STRUCT_N
 	if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) {
 		CPrintk(1, "c7000: c7000_xmit: start IO for unit 0x%x\n", cup->devno);
 		c7000_bld_wrt_chain(cup);
-		parm = (__u32) cup;
+		parm = (unsigned long)cup;
 		cup->state = C7000_WRITE;
 
 		if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
@@ -2385,7 +2329,7 @@ c7000_xmit(struct sk_buff *skb, STRUCT_N
 */
 
 static int
-c7000_ioctl(STRUCT_NET_DEVICE *dev, struct ifreq *ifr, int cmd)
+c7000_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	CPrintk(1, "c7000: c7000_ioctl: entered for base unit 0x%lx with cmd %d\n", dev->base_addr, cmd);
 	return(0);
@@ -2461,7 +2405,7 @@ static void
 c7000_retry_io(struct c7000_unit *cup)
 {
 	int	rc;
-	__u32	parm;
+	unsigned long	parm;
 	__u8	flags = 0x00;
 	ccw1_t	*ccwp;
 
@@ -2472,7 +2416,7 @@ c7000_retry_io(struct c7000_unit *cup)
 	}
 
 	set_bit(0, (void *)&cup->IO_active);
-	parm = (__u32)cup;
+	parm = (unsigned long)cup;
 
 	if (cup->state == C7000_READ || cup->state == C7000_WRITE)
 		ccwp = &cup->proc_head->ccws[0];
@@ -2560,14 +2504,10 @@ c7000_proc_wintr(struct c7000_unit *cup)
 		*/
 
 		buf = c7000_dequeue_buffer(cup);
+		ccp->stats.tx_bytes += buf->len;
+		ccp->stats.tx_packets++;
 		c7000_release_buffer(cup, buf);
 		num_write++;
-
-		/*
-			Update transmitted packets statistic.
-		*/
-
-		ccp->stats.tx_packets++;
 	}
 
 	CPrintk(1, "c7000: c7000_proc_wintr: %d buffers written for unit 0x%x\n", num_write, cup->devno);
@@ -2584,8 +2524,8 @@ c7000_intr(int irq, void *initparm, stru
 	devstat_t			*devstat = ((devstat_t *) initparm);
 	struct	c7000_unit		*cup = NULL;
 	struct	c7000_controller	*ccp = NULL;
-	STRUCT_NET_DEVICE		*dev = NULL;
-	__u32				parm;
+	struct	net_device		*dev = NULL;
+	unsigned long			parm;
 	__u8				flags = 0x00;
 	int				rc;
 
@@ -2618,14 +2558,14 @@ c7000_intr(int irq, void *initparm, stru
 	ccp = cup->cntlp;
 
 	if (ccp == NULL) {
-		CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure 0x%x for unit 0x%x\n", (int)cup, cup->devno);
+		CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure %p for unit 0x%x\n", cup, cup->devno);
 		return;
 	}
 
 	dev = ccp->dev;
 
 	if (dev == NULL) {
-		CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure 0x%x for unit 0x%x\n", (int)ccp, cup->devno);
+		CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure %p for unit 0x%x\n", ccp, cup->devno);
 		return;
 	}
 
@@ -2777,7 +2717,7 @@ c7000_intr(int irq, void *initparm, stru
 			if ((devstat->flag & DEVSTAT_FINAL_STATUS) &&
 			    (cup->free != NULL)) {
 				c7000_bld_read_chain(cup);
-				parm = (__u32)cup;
+				parm = (unsigned long)cup;
 				set_bit(0, (void *)&cup->IO_active);
 
 				if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
@@ -2834,7 +2774,7 @@ c7000_intr(int irq, void *initparm, stru
 
 			if (cup->proc_head != NULL) {
 				c7000_bld_wrt_chain(cup);
-				parm = (__u32)cup;
+				parm = (unsigned long)cup;
 				set_bit(0, (void *)&cup->IO_active);
 
 				if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) {
@@ -2932,7 +2872,7 @@ c7000_fill_name(char *dst, char *src)
 */
 
 static int
-c7000_init(STRUCT_NET_DEVICE *dev)
+c7000_init(struct net_device *dev)
 {
 	struct	c7000_controller	*ccp;
 	int				i;
@@ -2970,7 +2910,7 @@ c7000_init(STRUCT_NET_DEVICE *dev)
         dev->addr_len = 0;
         dev->type = ARPHRD_SLIP;
         dev->tx_queue_len = C7000_TXQUEUE_LEN;
-	dev->flags = IFF_NOARP;   
+	dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
 	dev->open = c7000_open;
 	dev->stop = c7000_stop;
 	dev->set_config = c7000_config;
@@ -2987,7 +2927,7 @@ c7000_init(STRUCT_NET_DEVICE *dev)
 		return(-ENOMEM);
 	}
 
-	CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address 0x%x\n", (int)ccp);
+	CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address %p\n", ccp);
 	memset(ccp, '\0', sizeof(struct c7000_controller));
 	ccp->dev = dev;
 	ccp->base_addr = dev->base_addr;
@@ -3217,12 +3157,8 @@ init_module(void)
 			Initialize the device structure.
 		*/
 
-		memset(&c7000_devices[i], '\0', sizeof(STRUCT_NET_DEVICE));
-#ifdef NEWSTUFF
+		memset(&c7000_devices[i], '\0', sizeof(struct net_device));
 		strcpy(c7000_devices[i].name, ifnames[i]);
-#else
-		c7000_devices[i].name = &ifnames[i][0];
-#endif
 		c7000_devices[i].base_addr = bases[i];
 		c7000_devices[i].init = c7000_init;
 
@@ -3278,7 +3214,7 @@ cleanup_module(void)
 					free_irq(ccp->cunits[j].irq, &ccp->cunits[j].devstat);
 				}
 
-				CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address 0x%x\n", (int)ccp);
+				CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address %p\n", ccp);
 				kfree(ccp);
 			}
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/sbus/char/bpp.c linux-2.4.28-pre1/drivers/sbus/char/bpp.c
--- linux-2.4.27/drivers/sbus/char/bpp.c	2001-10-11 16:43:29.000000000 +0000
+++ linux-2.4.28-pre1/drivers/sbus/char/bpp.c	2004-08-15 19:47:37.000000000 +0000
@@ -1073,3 +1073,5 @@ static void __exit bpp_cleanup(void)
 
 module_init(bpp_init);
 module_exit(bpp_cleanup);
+
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/sbus/char/vfc_dev.c linux-2.4.28-pre1/drivers/sbus/char/vfc_dev.c
--- linux-2.4.27/drivers/sbus/char/vfc_dev.c	2001-08-12 17:38:48.000000000 +0000
+++ linux-2.4.28-pre1/drivers/sbus/char/vfc_dev.c	2004-08-15 19:50:21.000000000 +0000
@@ -743,4 +743,4 @@ void cleanup_module(void)
 }
 #endif
 
-
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/Config.in linux-2.4.28-pre1/drivers/scsi/Config.in
--- linux-2.4.27/drivers/scsi/Config.in	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/Config.in	2004-08-15 19:49:40.000000000 +0000
@@ -70,6 +70,8 @@ dep_tristate 'AMI MegaRAID support' CONF
 dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI
 dep_mbool 'Serial ATA (SATA) support' CONFIG_SCSI_SATA $CONFIG_SCSI
 dep_tristate '  ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate '  Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI
+dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI
 dep_tristate '  Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate '  Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/Makefile linux-2.4.28-pre1/drivers/scsi/Makefile
--- linux-2.4.27/drivers/scsi/Makefile	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/Makefile	2004-08-15 19:51:15.000000000 +0000
@@ -131,12 +131,14 @@ obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 obj-$(CONFIG_SCSI_SATA_SVW)	+= libata.o sata_svw.o
+obj-$(CONFIG_SCSI_ATA_PIIX)	+= libata.o ata_piix.o
 obj-$(CONFIG_SCSI_SATA_PROMISE)	+= libata.o sata_promise.o
 obj-$(CONFIG_SCSI_SATA_SIL)	+= libata.o sata_sil.o
 obj-$(CONFIG_SCSI_SATA_VIA)	+= libata.o sata_via.o
 obj-$(CONFIG_SCSI_SATA_VITESSE)	+= libata.o sata_vsc.o
 obj-$(CONFIG_SCSI_SATA_SIS)	+= libata.o sata_sis.o
 obj-$(CONFIG_SCSI_SATA_SX4)	+= libata.o sata_sx4.o
+obj-$(CONFIG_SCSI_SATA_NV)	+= libata.o sata_nv.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/ata_piix.c linux-2.4.28-pre1/drivers/scsi/ata_piix.c
--- linux-2.4.27/drivers/scsi/ata_piix.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/ata_piix.c	2004-08-15 19:51:56.000000000 +0000
@@ -0,0 +1,675 @@
+/*
+
+    ata_piix.c - Intel PATA/SATA controllers
+
+
+	Copyright 2003-2004 Red Hat Inc
+	Copyright 2003-2004 Jeff Garzik
+
+
+	Copyright header from piix.c:
+
+    Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+    Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+    Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+
+    May be copied or modified under the terms of the GNU General Public License
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"ata_piix"
+#define DRV_VERSION	"1.02"
+
+enum {
+	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
+	ICH5_PMR		= 0x90, /* port mapping register */
+	ICH5_PCS		= 0x92,	/* port control and status */
+
+	PIIX_FLAG_AHCI		= (1 << 28), /* AHCI possible */
+	PIIX_FLAG_CHECKINTR	= (1 << 29), /* make sure PCI INTx enabled */
+	PIIX_FLAG_COMBINED	= (1 << 30), /* combined mode possible */
+
+	/* combined mode.  if set, PATA is channel 0.
+	 * if clear, PATA is channel 1.
+	 */
+	PIIX_COMB_PATA_P0	= (1 << 1),
+	PIIX_COMB		= (1 << 2), /* combined mode enabled? */
+
+	PIIX_PORT_PRESENT	= (1 << 0),
+	PIIX_PORT_ENABLED	= (1 << 4),
+
+	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
+	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
+
+	ich5_pata		= 0,
+	ich5_sata		= 1,
+	piix4_pata		= 2,
+	ich6_sata		= 3,
+	ich6_sata_rm		= 4,
+};
+
+static int piix_init_one (struct pci_dev *pdev,
+				    const struct pci_device_id *ent);
+
+static void piix_pata_phy_reset(struct ata_port *ap);
+static void piix_sata_phy_reset(struct ata_port *ap);
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+
+static unsigned int in_module_init = 1;
+
+static struct pci_device_id piix_pci_tbl[] = {
+#ifdef ATA_ENABLE_PATA
+	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
+	{ 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+	{ 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+#endif
+
+	/* NOTE: The following PCI ids must be kept in sync with the
+	 * list in drivers/pci/quirks.c.
+	 */
+
+	{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver piix_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= piix_pci_tbl,
+	.probe			= piix_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template piix_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+	.port_disable		= ata_port_disable,
+	.set_piomode		= piix_set_piomode,
+	.set_dmamode		= piix_set_dmamode,
+
+	.tf_load		= ata_tf_load_pio,
+	.tf_read		= ata_tf_read_pio,
+	.check_status		= ata_check_status_pio,
+	.exec_command		= ata_exec_command_pio,
+
+	.phy_reset		= piix_pata_phy_reset,
+
+	.bmdma_setup		= ata_bmdma_setup_pio,
+	.bmdma_start		= ata_bmdma_start_pio,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_operations piix_sata_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load_pio,
+	.tf_read		= ata_tf_read_pio,
+	.check_status		= ata_check_status_pio,
+	.exec_command		= ata_exec_command_pio,
+
+	.phy_reset		= piix_sata_phy_reset,
+
+	.bmdma_setup		= ata_bmdma_setup_pio,
+	.bmdma_start		= ata_bmdma_start_pio,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info piix_port_info[] = {
+	/* ich5_pata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+				  PIIX_FLAG_CHECKINTR,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+#if 0
+		.mwdma_mask	= 0x06, /* mwdma1-2 */
+#else
+		.mwdma_mask	= 0x00, /* mwdma broken */
+#endif
+		.udma_mask	= ATA_UDMA_MASK_40C, /* FIXME: cbl det */
+		.port_ops	= &piix_pata_ops,
+	},
+
+	/* ich5_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+
+	/* piix4_pata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+#if 0
+		.mwdma_mask	= 0x06, /* mwdma1-2 */
+#else
+		.mwdma_mask	= 0x00, /* mwdma broken */
+#endif
+		.udma_mask	= ATA_UDMA_MASK_40C, /* FIXME: cbl det */
+		.port_ops	= &piix_pata_ops,
+	},
+
+	/* ich6_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+
+	/* ich6_sata_rm */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+};
+
+static struct pci_bits piix_enable_bits[] = {
+	{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
+	{ 0x43U, 1U, 0x80UL, 0x80UL },	/* port 1 */
+};
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+
+/**
+ *	piix_pata_cbl_detect - Probe host controller cable detect info
+ *	@ap: Port for which cable detect info is desired
+ *
+ *	Read 80c cable indicator from SATA PCI device's PCI config
+ *	register.  This register is normally set by firmware (BIOS).
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+static void piix_pata_cbl_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	u8 tmp, mask;
+
+	/* no 80c support in host controller? */
+	if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
+		goto cbl40;
+
+	/* check BIOS cable detect results */
+	mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+	pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
+	if ((tmp & mask) == 0)
+		goto cbl40;
+
+	ap->cbl = ATA_CBL_PATA80;
+	return;
+
+cbl40:
+	ap->cbl = ATA_CBL_PATA40;
+	ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+
+/**
+ *	piix_pata_phy_reset - Probe specified port on PATA host controller
+ *	@ap: Port to probe
+ *
+ *	Probe PATA phy.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_pata_phy_reset(struct ata_port *ap)
+{
+	if (!pci_test_config_bits(ap->host_set->pdev,
+				  &piix_enable_bits[ap->port_no])) {
+		ata_port_disable(ap);
+		printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+		return;
+	}
+
+	piix_pata_cbl_detect(ap);
+
+	ata_port_probe(ap);
+
+	ata_bus_reset(ap);
+}
+
+/**
+ *	piix_sata_probe - Probe PCI device for present SATA devices
+ *	@ap: Port associated with the PCI device we wish to probe
+ *
+ *	Reads SATA PCI device's PCI config register Port Configuration
+ *	and Status (PCS) to determine port and device availability.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ *
+ *	RETURNS:
+ *	Non-zero if device detected, zero otherwise.
+ */
+static int piix_sata_probe (struct ata_port *ap)
+{
+	struct pci_dev *pdev = ap->host_set->pdev;
+	int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
+	int orig_mask, mask, i;
+	u8 pcs;
+
+	mask = (PIIX_PORT_PRESENT << ap->port_no) |
+	       (PIIX_PORT_ENABLED << ap->port_no);
+
+	pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+	orig_mask = (int) pcs & 0xff;
+
+	/* TODO: this is vaguely wrong for ICH6 combined mode,
+	 * where only two of the four SATA ports are mapped
+	 * onto a single ATA channel.  It is also vaguely inaccurate
+	 * for ICH5, which has only two ports.  However, this is ok,
+	 * as further device presence detection code will handle
+	 * any false positives produced here.
+	 */
+
+	for (i = 0; i < 4; i++) {
+		mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i);
+
+		if ((orig_mask & mask) == mask)
+			if (combined || (i == ap->port_no))
+				return 1;
+	}
+
+	return 0;
+}
+
+/**
+ *	piix_sata_phy_reset - Probe specified port on SATA host controller
+ *	@ap: Port to probe
+ *
+ *	Probe SATA phy.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_sata_phy_reset(struct ata_port *ap)
+{
+	if (!piix_sata_probe(ap)) {
+		ata_port_disable(ap);
+		printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
+		return;
+	}
+
+	ap->cbl = ATA_CBL_SATA;
+
+	ata_port_probe(ap);
+
+	ata_bus_reset(ap);
+}
+
+/**
+ *	piix_set_piomode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *	@pio: PIO mode, 0 - 4
+ *
+ *	Set PIO mode for device, in host controller PCI config space.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+	unsigned int pio	= adev->pio_mode;
+	struct pci_dev *dev	= ap->host_set->pdev;
+	unsigned int is_slave	= (adev->devno != 0);
+	unsigned int master_port= ap->port_no ? 0x42 : 0x40;
+	unsigned int slave_port	= 0x44;
+	u16 master_data;
+	u8 slave_data;
+
+	static const	 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data |= 0x4000;
+		/* enable PPE, IE and TIME */
+		master_data |= 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data &= (ap->port_no ? 0x0f : 0xf0);
+		slave_data |=
+			(timings[pio][0] << 2) |
+			(timings[pio][1] << (ap->port_no ? 4 : 0));
+	} else {
+		master_data &= 0xccf8;
+		/* enable PPE, IE and TIME */
+		master_data |= 0x0007;
+		master_data |=
+			(timings[pio][0] << 12) |
+			(timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+}
+
+/**
+ *	piix_set_dmamode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *	@udma: udma mode, 0 - 6
+ *
+ *	Set UDMA mode for device, in host controller PCI config space.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+	unsigned int udma	= adev->dma_mode; /* FIXME: MWDMA too */
+	struct pci_dev *dev	= ap->host_set->pdev;
+	u8 maslave		= ap->port_no ? 0x42 : 0x40;
+	u8 speed		= udma;
+	unsigned int drive_dn	= (ap->port_no ? 2 : 0) + adev->devno;
+	int a_speed		= 3 << (drive_dn * 4);
+	int u_flag		= 1 << drive_dn;
+	int v_flag		= 0x01 << drive_dn;
+	int w_flag		= 0x10 << drive_dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg4a;
+	u8			reg48, reg54, reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	DPRINTK("reg4042 = 0x%04x\n", reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_byte(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive_dn * 4); break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive_dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive_dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:	break;
+		default:
+			BUG();
+			return;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if ((reg4a & a_speed) != u_speed)
+			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag))
+				pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+		} else
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+#define AHCI_PCI_BAR 5
+#define AHCI_GLOBAL_CTL 0x04
+#define AHCI_ENABLE (1 << 31)
+static int piix_disable_ahci(struct pci_dev *pdev)
+{
+	void *mmio;
+	unsigned long addr;
+	u32 tmp;
+	int rc = 0;
+
+	/* BUG: pci_enable_device has not yet been called.  This
+	 * works because this device is usually set up by BIOS.
+	 */
+
+	addr = pci_resource_start(pdev, AHCI_PCI_BAR);
+	if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))
+		return 0;
+	
+	mmio = ioremap(addr, 64);
+	if (!mmio)
+		return -ENOMEM;
+	
+	tmp = readl(mmio + AHCI_GLOBAL_CTL);
+	if (tmp & AHCI_ENABLE) {
+		tmp &= ~AHCI_ENABLE;
+		writel(tmp, mmio + AHCI_GLOBAL_CTL);
+
+		tmp = readl(mmio + AHCI_GLOBAL_CTL);
+		if (tmp & AHCI_ENABLE)
+			rc = -EIO;
+	}
+	
+	iounmap(mmio);
+	return rc;
+}
+
+/**
+ *	piix_init_one - Register PIIX ATA PCI device with kernel services
+ *	@pdev: PCI device to register
+ *	@ent: Entry in piix_pci_tbl matching with @pdev
+ *
+ *	Called from kernel PCI layer.  We probe for combined mode (sigh),
+ *	and then hand over control to libata, for it to do the rest.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *	Zero on success, or -ERRNO value.
+ */
+
+static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_port_info *port_info[2];
+	unsigned int combined = 0, n_ports = 1;
+	unsigned int pata_chan = 0, sata_chan = 0;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/* no hotplugging support (FIXME) */
+	if (!in_module_init)
+		return -ENODEV;
+
+	port_info[0] = &piix_port_info[ent->driver_data];
+	port_info[1] = NULL;
+
+	if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
+		int rc = piix_disable_ahci(pdev);
+		if (rc)
+			return rc;
+	}
+
+	if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
+		u8 tmp;
+		pci_read_config_byte(pdev, ICH5_PMR, &tmp);
+
+		if (tmp & PIIX_COMB) {
+			combined = 1;
+			if (tmp & PIIX_COMB_PATA_P0)
+				sata_chan = 1;
+			else
+				pata_chan = 1;
+		}
+	}
+
+	/* On ICH5, some BIOSen disable the interrupt using the
+	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
+	 * On ICH6, this bit has the same effect, but only when
+	 * MSI is disabled (and it is disabled, as we don't use
+	 * message-signalled interrupts currently).
+	 */
+	if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+		pci_enable_intx(pdev);
+
+	if (combined) {
+		port_info[sata_chan] = &piix_port_info[ent->driver_data];
+		port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
+		port_info[pata_chan] = &piix_port_info[ich5_pata];
+		n_ports++;
+
+		printk(KERN_ERR DRV_NAME ": combined mode not supported\n");
+		return -ENODEV;
+	}
+
+	return ata_pci_init_one(pdev, port_info, n_ports);
+}
+
+/**
+ *	piix_init -
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int __init piix_init(void)
+{
+	int rc;
+
+	DPRINTK("pci_module_init\n");
+	rc = pci_module_init(&piix_pci_driver);
+	if (rc)
+		return rc;
+
+	in_module_init = 0;
+
+	DPRINTK("scsi_register_host\n");
+	rc = scsi_register_module(MODULE_SCSI_HA, &piix_sht);
+	if (rc) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	DPRINTK("done\n");
+	return 0;
+
+err_out:
+	pci_unregister_driver(&piix_pci_driver);
+	return rc;
+}
+
+/**
+ *	piix_exit -
+ *
+ *	LOCKING:
+ *
+ */
+
+static void __exit piix_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &piix_sht);
+	pci_unregister_driver(&piix_pci_driver);
+}
+
+module_init(piix_init);
+module_exit(piix_exit);
+
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/esp.c linux-2.4.28-pre1/drivers/scsi/esp.c
--- linux-2.4.27/drivers/scsi/esp.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/esp.c	2004-08-15 19:51:56.000000000 +0000
@@ -4368,4 +4368,4 @@ static Scsi_Host_Template driver_templat
 
 #include "scsi_module.c"
 
-EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/fcal.c linux-2.4.28-pre1/drivers/scsi/fcal.c
--- linux-2.4.27/drivers/scsi/fcal.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/fcal.c	2004-08-15 19:47:43.000000000 +0000
@@ -300,4 +300,4 @@ static Scsi_Host_Template driver_templat
 
 #include "scsi_module.c"
 
-EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/libata-core.c linux-2.4.28-pre1/drivers/scsi/libata-core.c
--- linux-2.4.27/drivers/scsi/libata-core.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/libata-core.c	2004-08-15 19:50:22.000000000 +0000
@@ -49,13 +49,14 @@ static unsigned int ata_busy_sleep (stru
 				    unsigned long tmout_pat,
 			    	    unsigned long tmout);
 static void __ata_dev_select (struct ata_port *ap, unsigned int device);
-static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat);
-static void ata_host_set_pio(struct ata_port *ap);
-static void ata_host_set_udma(struct ata_port *ap);
-static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
-static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
 static void ata_set_mode(struct ata_port *ap);
-static int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift);
+static int fgb(u32 bitmap);
+static int ata_choose_xfer_mode(struct ata_port *ap,
+				u8 *xfer_mode_out,
+				unsigned int *xfer_shift_out);
+static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
 
 static unsigned int ata_unique_id = 1;
 static LIST_HEAD(ata_probe_list);
@@ -65,37 +66,6 @@ MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
 
-static const char * thr_state_name[] = {
-	"THR_UNKNOWN",
-	"THR_PORT_RESET",
-	"THR_AWAIT_DEATH",
-	"THR_PROBE_FAILED",
-	"THR_IDLE",
-	"THR_PROBE_SUCCESS",
-	"THR_PROBE_START",
-};
-
-/**
- *	ata_thr_state_name - convert thread state enum to string
- *	@thr_state: thread state to be converted to string
- *
- *	Converts the specified thread state id to a constant C string.
- *
- *	LOCKING:
- *	None.
- *
- *	RETURNS:
- *	The THR_xxx-prefixed string naming the specified thread
- *	state id, or the string "<invalid THR_xxx state>".
- */
-
-static const char *ata_thr_state_name(unsigned int thr_state)
-{
-	if (thr_state < ARRAY_SIZE(thr_state_name))
-		return thr_state_name[thr_state];
-	return "<invalid THR_xxx state>";
-}
-
 /**
  *	msleep - sleep for a number of milliseconds
  *	@msecs: number of milliseconds to sleep
@@ -113,6 +83,11 @@ static void msleep(unsigned long msecs)
 	schedule_timeout(msecs_to_jiffies(msecs) + 1);
 }
 
+void libata_msleep(unsigned long msecs)
+{
+	msleep(msecs);
+}
+
 /**
  *	ata_tf_load_pio - send taskfile registers to host controller
  *	@ap: Port to which output is sent
@@ -574,7 +549,7 @@ static void ata_dev_set_protocol(struct 
 	dev->write_cmd = (cmd >> 8) & 0xff;
 }
 
-static const char * udma_str[] = {
+static const char * xfer_mode_str[] = {
 	"UDMA/16",
 	"UDMA/25",
 	"UDMA/33",
@@ -583,6 +558,14 @@ static const char * udma_str[] = {
 	"UDMA/100",
 	"UDMA/133",
 	"UDMA7",
+	"MWDMA0",
+	"MWDMA1",
+	"MWDMA2",
+	"PIO0",
+	"PIO1",
+	"PIO2",
+	"PIO3",
+	"PIO4",
 };
 
 /**
@@ -600,16 +583,24 @@ static const char * udma_str[] = {
  *	@udma_mask, or the constant C string "<n/a>".
  */
 
-static const char *ata_udma_string(unsigned int udma_mask)
+static const char *ata_mode_string(unsigned int mask)
 {
 	int i;
 
-	for (i = 7; i >= 0; i--) {
-		if (udma_mask & (1 << i))
-			return udma_str[i];
-	}
+	for (i = 7; i >= 0; i--)
+		if (mask & (1 << i))
+			goto out;
+	for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--)
+		if (mask & (1 << i))
+			goto out;
+	for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--)
+		if (mask & (1 << i))
+			goto out;
 
 	return "<n/a>";
+
+out:
+	return xfer_mode_str[i];
 }
 
 /**
@@ -980,10 +971,14 @@ static void ata_dev_identify(struct ata_
 {
 	struct ata_device *dev = &ap->device[device];
 	unsigned int i;
-	u16 tmp, udma_modes;
+	u16 tmp;
+	unsigned long xfer_modes;
 	u8 status;
-	struct ata_taskfile tf;
 	unsigned int using_edd;
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	unsigned long flags;
+	int rc;
 
 	if (!ata_dev_present(dev)) {
 		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
@@ -1003,27 +998,34 @@ static void ata_dev_identify(struct ata_
 
 	ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
 
-retry:
-	ata_tf_init(ap, &tf, device);
-	tf.ctl |= ATA_NIEN;
-	tf.protocol = ATA_PROT_PIO;
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
 
+	ata_sg_init_one(qc, dev->id, sizeof(dev->id));
+	qc->pci_dma_dir = PCI_DMA_FROMDEVICE;
+	qc->tf.protocol = ATA_PROT_PIO;
+	qc->nsect = 1;
+
+retry:
 	if (dev->class == ATA_DEV_ATA) {
-		tf.command = ATA_CMD_ID_ATA;
+		qc->tf.command = ATA_CMD_ID_ATA;
 		DPRINTK("do ATA identify\n");
 	} else {
-		tf.command = ATA_CMD_ID_ATAPI;
+		qc->tf.command = ATA_CMD_ID_ATAPI;
 		DPRINTK("do ATAPI identify\n");
 	}
 
-	ata_tf_to_host(ap, &tf);
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
 
-	/* crazy ATAPI devices... */
-	if (dev->class == ATA_DEV_ATAPI)
-		msleep(150);
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
-	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT))
+	if (rc)
 		goto err_out;
+	else
+		wait_for_completion(&wait);
 
 	status = ata_chk_status(ap);
 	if (status & ATA_ERR) {
@@ -1038,45 +1040,20 @@ retry:
 		 * ATA software reset (SRST, the default) does not appear
 		 * to have this problem.
 		 */
-		if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) {
+		if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) {
 			u8 err = ata_chk_err(ap);
 			if (err & ATA_ABORTED) {
 				dev->class = ATA_DEV_ATAPI;
+				qc->cursg = 0;
+				qc->cursg_ofs = 0;
+				qc->cursect = 0;
+				qc->nsect = 1;
 				goto retry;
 			}
 		}
 		goto err_out;
 	}
 
-	/* make sure we have BSY=0, DRQ=1 */
-	if ((status & ATA_DRQ) == 0) {
-		printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n",
-		       ap->id, device,
-		       dev->class == ATA_DEV_ATA ? "" : "PI",
-		       status);
-		goto err_out;
-	}
-
-	/* read IDENTIFY [X] DEVICE page */
-	if (ap->flags & ATA_FLAG_MMIO) {
-		for (i = 0; i < ATA_ID_WORDS; i++)
-			dev->id[i] = readw((void *)ap->ioaddr.data_addr);
-	} else
-		for (i = 0; i < ATA_ID_WORDS; i++)
-			dev->id[i] = inw(ap->ioaddr.data_addr);
-
-	/* wait for host_idle */
-	status = ata_wait_idle(ap);
-	if (status & (ATA_BUSY | ATA_DRQ)) {
-		printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n",
-		       ap->id, device,
-		       dev->class == ATA_DEV_ATA ? "" : "PI",
-		       status);
-		goto err_out;
-	}
-
-	ata_irq_on(ap);	/* re-enable interrupts */
-
 	/* print device capabilities */
 	printk(KERN_DEBUG "ata%u: dev %u cfg "
 	       "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
@@ -1095,12 +1072,13 @@ retry:
 		goto err_out_nosup;
 	}
 
-	/* we require UDMA support */
-	udma_modes =
-	tmp = dev->id[ATA_ID_UDMA_MODES];
-	if ((tmp & 0xff) == 0) {
-		printk(KERN_DEBUG "ata%u: no udma\n", ap->id);
-		goto err_out_nosup;
+	/* quick-n-dirty find max transfer mode; for printk only */
+	xfer_modes = dev->id[ATA_ID_UDMA_MODES];
+	if (!xfer_modes)
+		xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
+	if (!xfer_modes) {
+		xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3);
+		xfer_modes |= (0x7 << ATA_SHIFT_PIO);
 	}
 
 	ata_dump_id(dev);
@@ -1133,7 +1111,7 @@ retry:
 		/* print device info to dmesg */
 		printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n",
 		       ap->id, device,
-		       ata_udma_string(udma_modes),
+		       ata_mode_string(xfer_modes),
 		       (unsigned long long)dev->n_sectors,
 		       dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
 	}
@@ -1143,15 +1121,18 @@ retry:
 		if (ata_id_is_ata(dev))		/* sanity check */
 			goto err_out_nosup;
 
-		/* see if 16-byte commands supported */
-		tmp = dev->id[0] & 0x3;
-		if (tmp == 1)
-			ap->host->max_cmd_len = 16;
+		rc = atapi_cdb_len(dev->id);
+		if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
+			printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+			goto err_out_nosup;
+		}
+		ap->cdb_len = (unsigned int) rc;
+		ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
 
 		/* print device info to dmesg */
 		printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
 		       ap->id, device,
-		       ata_udma_string(udma_modes));
+		       ata_mode_string(xfer_modes));
 	}
 
 	DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
@@ -1167,13 +1148,16 @@ err_out:
 }
 
 /**
- *	ata_port_reset -
- *	@ap:
+ *	ata_bus_probe - Reset and probe ATA bus
+ *	@ap: Bus to probe
  *
  *	LOCKING:
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
  */
 
-static void ata_port_reset(struct ata_port *ap)
+static int ata_bus_probe(struct ata_port *ap)
 {
 	unsigned int i, found = 0;
 
@@ -1197,14 +1181,12 @@ static void ata_port_reset(struct ata_po
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		goto err_out_disable;
 
-	ap->thr_state = THR_PROBE_SUCCESS;
-
-	return;
+	return 0;
 
 err_out_disable:
 	ap->ops->port_disable(ap);
 err_out:
-	ap->thr_state = THR_PROBE_FAILED;
+	return -1;
 }
 
 /**
@@ -1281,6 +1263,101 @@ void ata_port_disable(struct ata_port *a
 	ap->flags |= ATA_FLAG_PORT_DISABLED;
 }
 
+static struct {
+	unsigned int shift;
+	u8 base;
+} xfer_mode_classes[] = {
+	{ ATA_SHIFT_UDMA,	XFER_UDMA_0 },
+	{ ATA_SHIFT_MWDMA,	XFER_MW_DMA_0 },
+	{ ATA_SHIFT_PIO,	XFER_PIO_0 },
+};
+
+static inline u8 base_from_shift(unsigned int shift)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
+		if (xfer_mode_classes[i].shift == shift)
+			return xfer_mode_classes[i].base;
+
+	return 0xff;
+}
+
+static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
+{
+	int ofs, idx;
+	u8 base;
+
+	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		return;
+
+	if (dev->xfer_shift == ATA_SHIFT_PIO)
+		dev->flags |= ATA_DFLAG_PIO;
+
+	ata_dev_set_xfermode(ap, dev);
+
+	base = base_from_shift(dev->xfer_shift);
+	ofs = dev->xfer_mode - base;
+	idx = ofs + dev->xfer_shift;
+	WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
+
+	DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
+		idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+
+	printk(KERN_INFO "ata%u: dev %u configured for %s\n",
+		ap->id, dev->devno, xfer_mode_str[idx]);
+}
+
+static int ata_host_set_pio(struct ata_port *ap)
+{
+	unsigned int mask;
+	int x, i;
+	u8 base, xfer_mode;
+
+	mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
+	x = fgb(mask);
+	if (x < 0) {
+		printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+		return -1;
+	}
+
+	base = base_from_shift(ATA_SHIFT_PIO);
+	xfer_mode = base + x;
+
+	DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
+		(int)base, (int)xfer_mode, mask, x);
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		if (ata_dev_present(dev)) {
+			dev->pio_mode = xfer_mode;
+			dev->xfer_mode = xfer_mode;
+			dev->xfer_shift = ATA_SHIFT_PIO;
+			if (ap->ops->set_piomode)
+				ap->ops->set_piomode(ap, dev);
+		}
+	}
+
+	return 0;
+}
+
+static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
+			    unsigned int xfer_shift)
+{
+	int i;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		if (ata_dev_present(dev)) {
+			dev->dma_mode = xfer_mode;
+			dev->xfer_mode = xfer_mode;
+			dev->xfer_shift = xfer_shift;
+			if (ap->ops->set_dmamode)
+				ap->ops->set_dmamode(ap, dev);
+		}
+	}
+}
+
 /**
  *	ata_set_mode - Program timings and issue SET FEATURES - XFER
  *	@ap: port on which timings will be programmed
@@ -1290,29 +1367,28 @@ void ata_port_disable(struct ata_port *a
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-	unsigned int force_pio, i;
-
-	ata_host_set_pio(ap);
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		return;
+	unsigned int i, xfer_shift;
+	u8 xfer_mode;
+	int rc;
 
-	ata_host_set_udma(ap);
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		return;
+	/* step 1: always set host PIO timings */
+	rc = ata_host_set_pio(ap);
+	if (rc)
+		goto err_out;
 
-#ifdef ATA_FORCE_PIO
-	force_pio = 1;
-#else
-	force_pio = 0;
-#endif
+	/* step 2: choose the best data xfer mode */
+	xfer_mode = xfer_shift = 0;
+	rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
+	if (rc)
+		goto err_out;
 
-	if (force_pio) {
-		ata_dev_set_pio(ap, 0);
-		ata_dev_set_pio(ap, 1);
-	} else {
-		ata_dev_set_udma(ap, 0);
-		ata_dev_set_udma(ap, 1);
-	}
+	/* step 3: if that xfer mode isn't PIO, set host DMA timings */
+	if (xfer_shift != ATA_SHIFT_PIO)
+		ata_host_set_dma(ap, xfer_mode, xfer_shift);
+
+	/* step 4: update devices' xfer mode */
+	ata_dev_set_mode(ap, &ap->device[0]);
+	ata_dev_set_mode(ap, &ap->device[1]);
 
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		return;
@@ -1324,6 +1400,11 @@ static void ata_set_mode(struct ata_port
 		struct ata_device *dev = &ap->device[i];
 		ata_dev_set_protocol(dev);
 	}
+
+	return;
+
+err_out:
+	ata_port_disable(ap);
 }
 
 /**
@@ -1585,116 +1666,102 @@ err_out:
 	DPRINTK("EXIT\n");
 }
 
-/**
- *	ata_host_set_pio -
- *	@ap:
- *
- *	LOCKING:
- */
-
-static void ata_host_set_pio(struct ata_port *ap)
+static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift)
 {
 	struct ata_device *master, *slave;
-	unsigned int pio, i;
-	u16 mask;
+	unsigned int mask;
 
 	master = &ap->device[0];
 	slave = &ap->device[1];
 
 	assert (ata_dev_present(master) || ata_dev_present(slave));
 
-	mask = ap->pio_mask;
-	if (ata_dev_present(master))
-		mask &= (master->id[ATA_ID_PIO_MODES] & 0x03);
-	if (ata_dev_present(slave))
-		mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03);
-
-	/* require pio mode 3 or 4 support for host and all devices */
-	if (mask == 0) {
-		printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n",
-		       ap->id);
-		goto err_out;
+	if (shift == ATA_SHIFT_UDMA) {
+		mask = ap->udma_mask;
+		if (ata_dev_present(master))
+			mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
+		if (ata_dev_present(slave))
+			mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
+	}
+	else if (shift == ATA_SHIFT_MWDMA) {
+		mask = ap->mwdma_mask;
+		if (ata_dev_present(master))
+			mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
+		if (ata_dev_present(slave))
+			mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
+	}
+	else if (shift == ATA_SHIFT_PIO) {
+		mask = ap->pio_mask;
+		if (ata_dev_present(master)) {
+			/* spec doesn't return explicit support for
+			 * PIO0-2, so we fake it
+			 */
+			u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
+			tmp_mode <<= 3;
+			tmp_mode |= 0x7;
+			mask &= tmp_mode;
+		}
+		if (ata_dev_present(slave)) {
+			/* spec doesn't return explicit support for
+			 * PIO0-2, so we fake it
+			 */
+			u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
+			tmp_mode <<= 3;
+			tmp_mode |= 0x7;
+			mask &= tmp_mode;
+		}
+	}
+	else {
+		mask = 0xffffffff; /* shut up compiler warning */
+		BUG();
 	}
 
-	pio = (mask & ATA_ID_PIO4) ? 4 : 3;
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_present(&ap->device[i])) {
-			ap->device[i].pio_mode = (pio == 3) ?
-				XFER_PIO_3 : XFER_PIO_4;
-			if (ap->ops->set_piomode)
-				ap->ops->set_piomode(ap, &ap->device[i], pio);
-		}
+	return mask;
+}
 
-	return;
+/* find greatest bit */
+static int fgb(u32 bitmap)
+{
+	unsigned int i;
+	int x = -1;
 
-err_out:
-	ap->ops->port_disable(ap);
+	for (i = 0; i < 32; i++)
+		if (bitmap & (1 << i))
+			x = i;
+
+	return x;
 }
 
 /**
- *	ata_host_set_udma -
+ *	ata_choose_xfer_mode -
  *	@ap:
  *
  *	LOCKING:
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
  */
 
-static void ata_host_set_udma(struct ata_port *ap)
-{
-	struct ata_device *master, *slave;
-	u16 mask;
-	unsigned int i, j;
-	int udma_mode = -1;
-
-	master = &ap->device[0];
-	slave = &ap->device[1];
-
-	assert (ata_dev_present(master) || ata_dev_present(slave));
-	assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0);
-
-	DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n",
-		ap->udma_mask,
-		(!ata_dev_present(master)) ? 0xff :
-			(master->id[ATA_ID_UDMA_MODES] & 0xff),
-		(!ata_dev_present(slave)) ? 0xff :
-			(slave->id[ATA_ID_UDMA_MODES] & 0xff));
-
-	mask = ap->udma_mask;
-	if (ata_dev_present(master))
-		mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
-	if (ata_dev_present(slave))
-		mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
-
-	i = XFER_UDMA_7;
-	while (i >= XFER_UDMA_0) {
-		j = i - XFER_UDMA_0;
-		DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j);
-		if (mask & (1 << j)) {
-			udma_mode = i;
-			break;
+static int ata_choose_xfer_mode(struct ata_port *ap,
+				u8 *xfer_mode_out,
+				unsigned int *xfer_shift_out)
+{
+	unsigned int mask, shift;
+	int x, i;
+
+	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
+		shift = xfer_mode_classes[i].shift;
+		mask = ata_get_mode_mask(ap, shift);
+
+		x = fgb(mask);
+		if (x >= 0) {
+			*xfer_mode_out = xfer_mode_classes[i].base + x;
+			*xfer_shift_out = shift;
+			return 0;
 		}
-
-		i--;
 	}
 
-	/* require udma for host and all attached devices */
-	if (udma_mode < 0) {
-		printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n",
-		       ap->id);
-		goto err_out;
-	}
-
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_present(&ap->device[i])) {
-			ap->device[i].udma_mode = udma_mode;
-			if (ap->ops->set_udmamode)
-				ap->ops->set_udmamode(ap, &ap->device[i],
-						      udma_mode);
-		}
-
-	return;
-
-err_out:
-	ap->ops->port_disable(ap);
+	return -1;
 }
 
 /**
@@ -1707,89 +1774,39 @@ err_out:
 
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
 {
-	struct ata_taskfile tf;
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	int rc;
+	unsigned long flags;
 
 	/* set up set-features taskfile */
 	DPRINTK("set features - xfer mode\n");
-	ata_tf_init(ap, &tf, dev->devno);
-	tf.ctl |= ATA_NIEN;
-	tf.command = ATA_CMD_SET_FEATURES;
-	tf.feature = SETFEATURES_XFER;
-	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-	tf.protocol = ATA_PROT_NODATA;
-	if (dev->flags & ATA_DFLAG_PIO)
-		tf.nsect = dev->pio_mode;
-	else
-		tf.nsect = dev->udma_mode;
 
-	/* do bus reset */
-	ata_tf_to_host(ap, &tf);
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
 
-	/* crazy ATAPI devices... */
-	if (dev->class == ATA_DEV_ATAPI)
-		msleep(150);
+	qc->tf.command = ATA_CMD_SET_FEATURES;
+	qc->tf.feature = SETFEATURES_XFER;
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	qc->tf.protocol = ATA_PROT_NODATA;
+	qc->tf.nsect = dev->xfer_mode;
 
-	ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
 
-	ata_irq_on(ap);	/* re-enable interrupts */
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
 
-	ata_wait_idle(ap);
+	if (rc)
+		ata_port_disable(ap);
+	else
+		wait_for_completion(&wait);
 
 	DPRINTK("EXIT\n");
 }
 
 /**
- *	ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA
- *	@ap: Port associated with device @dev
- *	@device: Device whose mode will be set
- *
- *	LOCKING:
- */
-
-static void ata_dev_set_udma(struct ata_port *ap, unsigned int device)
-{
-	struct ata_device *dev = &ap->device[device];
-
-	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
-		return;
-
-	ata_dev_set_xfermode(ap, dev);
-
-	assert((dev->udma_mode >= XFER_UDMA_0) &&
-	       (dev->udma_mode <= XFER_UDMA_7));
-	printk(KERN_INFO "ata%u: dev %u configured for %s\n",
-	       ap->id, device,
-	       udma_str[dev->udma_mode - XFER_UDMA_0]);
-}
-
-/**
- *	ata_dev_set_pio - Set ATA device's transfer mode to PIO
- *	@ap: Port associated with device @dev
- *	@device: Device whose mode will be set
- *
- *	LOCKING:
- */
-
-static void ata_dev_set_pio(struct ata_port *ap, unsigned int device)
-{
-	struct ata_device *dev = &ap->device[device];
-
-	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
-		return;
-
-	/* force PIO mode */
-	dev->flags |= ATA_DFLAG_PIO;
-
-	ata_dev_set_xfermode(ap, dev);
-
-	assert((dev->pio_mode >= XFER_PIO_3) &&
-	       (dev->pio_mode <= XFER_PIO_4));
-	printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n",
-	       ap->id, device,
-	       dev->pio_mode == 3 ? '3' : '4');
-}
-
-/**
  *	ata_sg_clean -
  *	@qc:
  *
@@ -1799,37 +1816,35 @@ static void ata_dev_set_pio(struct ata_p
 static void ata_sg_clean(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scsi_cmnd *cmd = qc->scsicmd;
 	struct scatterlist *sg = qc->sg;
-	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	int dir = qc->pci_dma_dir;
 
-	assert(dir == SCSI_DATA_READ || dir == SCSI_DATA_WRITE);
-	assert(qc->flags & ATA_QCFLAG_SG);
+	assert(qc->flags & ATA_QCFLAG_DMAMAP);
 	assert(sg != NULL);
 
-	if (!cmd->use_sg)
+	if (qc->flags & ATA_QCFLAG_SINGLE)
 		assert(qc->n_elem == 1);
 
 	DPRINTK("unmapping %u sg elements\n", qc->n_elem);
 
-	if (cmd->use_sg)
+	if (qc->flags & ATA_QCFLAG_SG)
 		pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir);
 	else
 		pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]),
 				 sg_dma_len(&sg[0]), dir);
 
-	qc->flags &= ~ATA_QCFLAG_SG;
+	qc->flags &= ~ATA_QCFLAG_DMAMAP;
 	qc->sg = NULL;
 }
 
 /**
- *	ata_fill_sg -
- *	@qc:
+ *	ata_fill_sg - Fill PCI IDE PRD table
+ *	@qc: Metadata associated with taskfile to be transferred
  *
  *	LOCKING:
  *
  */
-void ata_fill_sg(struct ata_queued_cmd *qc)
+static void ata_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct scatterlist *sg = qc->sg;
 	struct ata_port *ap = qc->ap;
@@ -1871,6 +1886,48 @@ void ata_fill_sg(struct ata_queued_cmd *
 }
 
 /**
+ *	ata_qc_prep - Prepare taskfile for submission
+ *	@qc: Metadata associated with taskfile to be prepared
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+void ata_qc_prep(struct ata_queued_cmd *qc)
+{
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+		return;
+
+	ata_fill_sg(qc);
+}
+
+void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
+{
+	struct scatterlist *sg;
+
+	qc->flags |= ATA_QCFLAG_SINGLE;
+
+	memset(&qc->sgent, 0, sizeof(qc->sgent));
+	qc->sg = &qc->sgent;
+	qc->n_elem = 1;
+	qc->buf_virt = buf;
+
+	sg = qc->sg;
+	sg->page = virt_to_page(buf);
+	sg->offset = (unsigned long) buf & ~PAGE_MASK;
+	sg_dma_len(sg) = buflen;
+
+	WARN_ON(buflen > PAGE_SIZE);
+}
+
+void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
+		 unsigned int n_elem)
+{
+	qc->flags |= ATA_QCFLAG_SG;
+	qc->sg = sg;
+	qc->n_elem = n_elem;
+}
+
+/**
  *	ata_sg_setup_one -
  *	@qc:
  *
@@ -1884,29 +1941,16 @@ void ata_fill_sg(struct ata_queued_cmd *
 static int ata_sg_setup_one(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scsi_cmnd *cmd = qc->scsicmd;
-	int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	int dir = qc->pci_dma_dir;
 	struct scatterlist *sg = qc->sg;
-	unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
 	dma_addr_t dma_address;
 
-	assert(sg == &qc->sgent);
-	assert(qc->n_elem == 1);
-
-	sg->address = cmd->request_buffer;
-	sg->page = virt_to_page(cmd->request_buffer);
-	sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK;
-	sg_dma_len(sg) = cmd->request_bufflen;
-
-	if (!have_sg)
-		return 0;
-
-	dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer,
-				     cmd->request_bufflen, dir);
+	dma_address = pci_map_single(ap->host_set->pdev, qc->buf_virt,
+				     sg_dma_len(sg), dir);
 
 	sg_dma_address(sg) = dma_address;
 
-	DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen,
+	DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
 		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
 
 	return 0;
@@ -1926,24 +1970,19 @@ static int ata_sg_setup_one(struct ata_q
 static int ata_sg_setup(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scsi_cmnd *cmd = qc->scsicmd;
-	struct scatterlist *sg;
-	int n_elem;
-	unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
+	struct scatterlist *sg = qc->sg;
+	int n_elem, dir;
 
-	VPRINTK("ENTER, ata%u, use_sg %d\n", ap->id, cmd->use_sg);
-	assert(cmd->use_sg > 0);
+	VPRINTK("ENTER, ata%u\n", ap->id);
+	assert(qc->flags & ATA_QCFLAG_SG);
+
+	dir = qc->pci_dma_dir;
+	n_elem = pci_map_sg(ap->host_set->pdev, sg, qc->n_elem, dir);
+	if (n_elem < 1)
+		return -1;
+
+	DPRINTK("%d sg elements mapped\n", n_elem);
 
-	sg = (struct scatterlist *)cmd->request_buffer;
-	if (have_sg) {
-		int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
-		n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir);
-		if (n_elem < 1)
-			return -1;
-		DPRINTK("%d sg elements mapped\n", n_elem);
-	} else {
-		n_elem = cmd->use_sg;
-	}
 	qc->n_elem = n_elem;
 
 	return 0;
@@ -2028,7 +2067,7 @@ static void ata_pio_complete (struct ata
 	}
 
 	drv_stat = ata_wait_idle(ap);
-	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+	if (!ata_ok(drv_stat)) {
 		ap->pio_task_state = PIO_ST_ERR;
 		return;
 	}
@@ -2043,6 +2082,43 @@ static void ata_pio_complete (struct ata
 	ata_qc_complete(qc, drv_stat);
 }
 
+static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
+			       unsigned int buflen, int write_data)
+{
+	unsigned int i;
+	unsigned int words = buflen >> 1;
+	u16 *buf16 = (u16 *) buf;
+	void *mmio = (void *)ap->ioaddr.data_addr;
+
+	if (write_data) {
+		for (i = 0; i < words; i++)
+			writew(buf16[i], mmio);
+	} else {
+		for (i = 0; i < words; i++)
+			buf16[i] = readw(mmio);
+	}
+}
+
+static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
+			      unsigned int buflen, int write_data)
+{
+	unsigned int dwords = buflen >> 2;
+
+	if (write_data)
+		outsl(ap->ioaddr.data_addr, buf, dwords);
+	else
+		insl(ap->ioaddr.data_addr, buf, dwords);
+}
+
+static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
+			  unsigned int buflen, int do_write)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_mmio_data_xfer(ap, buf, buflen, do_write);
+	else
+		ata_pio_data_xfer(ap, buf, buflen, do_write);
+}
+
 /**
  *	ata_pio_sector -
  *	@ap:
@@ -2054,9 +2130,10 @@ static void ata_pio_sector(struct ata_po
 {
 	struct ata_queued_cmd *qc;
 	struct scatterlist *sg;
-	struct scsi_cmnd *cmd;
+	struct page *page;
 	unsigned char *buf;
 	u8 status;
+	int do_write;
 
 	/*
 	 * This is purely hueristic.  This is a fast path.
@@ -2086,36 +2163,51 @@ static void ata_pio_sector(struct ata_po
 	qc = ata_qc_from_tag(ap, ap->active_tag);
 	assert(qc != NULL);
 
-	cmd = qc->scsicmd;
 	sg = qc->sg;
 
 	if (qc->cursect == (qc->nsect - 1))
 		ap->pio_task_state = PIO_ST_LAST;
 
-	buf = kmap(sg[qc->cursg].page) +
+	page = sg[qc->cursg].page;
+	buf = kmap(page) +
 	      sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE);
 
 	qc->cursect++;
 	qc->cursg_ofs++;
 
-	if (cmd->use_sg)
-		if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
-			qc->cursg++;
-			qc->cursg_ofs = 0;
-		}
+	if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+		qc->cursg++;
+		qc->cursg_ofs = 0;
+	}
 
 	DPRINTK("data %s, drv_stat 0x%X\n",
 		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read",
 		status);
 
 	/* do the actual data transfer */
-	/* FIXME: mmio-ize */
-	if (qc->tf.flags & ATA_TFLAG_WRITE)
-		outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
-	else
-		insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS);
+	do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+	ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
+
+	kunmap(page);
+}
+
+static void ata_pio_error(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	u8 drv_stat;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	drv_stat = ata_chk_status(ap);
+	printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
+	       ap->id, drv_stat);
+
+	ap->pio_task_state = PIO_ST_IDLE;
+
+	ata_irq_on(ap);
 
-	kunmap(sg[qc->cursg].page);
+	ata_qc_complete(qc, drv_stat | ATA_ERR);
 }
 
 static void ata_pio_task(void *_data)
@@ -2138,15 +2230,8 @@ static void ata_pio_task(void *_data)
 		break;
 
 	case PIO_ST_TMOUT:
-		printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */
-		       ap->id);
-		timeout = 11 * HZ;
-		break;
-
 	case PIO_ST_ERR:
-		printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */
-		       ap->id);
-		timeout = 11 * HZ;
+		ata_pio_error(ap);
 		break;
 	}
 
@@ -2162,8 +2247,8 @@ static void ata_pio_task(void *_data)
 }
 
 /**
- *	ata_eng_timeout - Handle timeout of queued command
- *	@ap: Port on which timed-out command is active
+ *	ata_qc_timeout - Handle timeout of queued command
+ *	@qc: Command that timed out
  *
  *	Some part of the kernel (currently, only the SCSI layer)
  *	has noticed that the active command on port @ap has not
@@ -2177,23 +2262,15 @@ static void ata_pio_task(void *_data)
  *	transaction completed successfully.
  *
  *	LOCKING:
- *	Inherited from SCSI layer (none, can sleep)
  */
 
-void ata_eng_timeout(struct ata_port *ap)
+static void ata_qc_timeout(struct ata_queued_cmd *qc)
 {
-	u8 host_stat, drv_stat;
-	struct ata_queued_cmd *qc;
+	struct ata_port *ap = qc->ap;
+	u8 host_stat = 0, drv_stat;
 
 	DPRINTK("ENTER\n");
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
-		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-		       ap->id);
-		goto out;
-	}
-
 	/* hack alert!  We cannot use the supplied completion
 	 * function from inside the ->eh_strategy_handler() thread.
 	 * libata is the only user of ->eh_strategy_handler() in
@@ -2203,38 +2280,68 @@ void ata_eng_timeout(struct ata_port *ap
 	qc->scsidone = scsi_finish_command;
 
 	switch (qc->tf.protocol) {
+
 	case ATA_PROT_DMA:
-		if (ap->flags & ATA_FLAG_MMIO) {
-			void *mmio = (void *) ap->ioaddr.bmdma_addr;
-			host_stat = readb(mmio + ATA_DMA_STATUS);
-		} else
-			host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	case ATA_PROT_ATAPI_DMA:
+		host_stat = ata_bmdma_status(ap);
 
-		printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n",
-		       ap->id, host_stat);
+		/* before we do anything else, clear DMA-Start bit */
+		ata_bmdma_stop(ap);
 
-		ata_dma_complete(qc, host_stat);
-		break;
+		/* fall through */
 
-	case ATA_PROT_NODATA:
-		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+	default:
+		ata_altstatus(ap);
+		drv_stat = ata_chk_status(ap);
+
+		/* ack bmdma irq events */
+		ata_bmdma_ack_irq(ap);
 
-		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
-		       ap->id, qc->tf.command, drv_stat);
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat, host_stat);
 
+		/* complete taskfile transaction */
 		ata_qc_complete(qc, drv_stat);
 		break;
+	}
 
-	default:
-		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_eng_timeout - Handle timeout of queued command
+ *	@ap: Port on which timed-out command is active
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ */
 
-		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
-		       ap->id, qc->tf.command, drv_stat);
+void ata_eng_timeout(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
 
-		ata_qc_complete(qc, drv_stat);
-		break;
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
 	}
 
+	ata_qc_timeout(qc);
+
 out:
 	DPRINTK("EXIT\n");
 }
@@ -2289,8 +2396,6 @@ struct ata_queued_cmd *ata_qc_new_init(s
 
 		ata_tf_init(ap, &qc->tf, dev->devno);
 
-		if (likely((dev->flags & ATA_DFLAG_PIO) == 0))
-			qc->flags |= ATA_QCFLAG_DMA;
 		if (dev->flags & ATA_DFLAG_LBA48)
 			qc->tf.flags |= ATA_TFLAG_LBA48;
 	}
@@ -2298,6 +2403,11 @@ struct ata_queued_cmd *ata_qc_new_init(s
 	return qc;
 }
 
+static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	return 0;
+}
+
 /**
  *	ata_qc_complete - Complete an active ATA command
  *	@qc: Command to complete
@@ -2310,29 +2420,25 @@ struct ata_queued_cmd *ata_qc_new_init(s
 void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
 {
 	struct ata_port *ap = qc->ap;
-	struct scsi_cmnd *cmd = qc->scsicmd;
 	unsigned int tag, do_clear = 0;
+	int rc;
 
 	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
 	assert(qc->flags & ATA_QCFLAG_ACTIVE);
 
-	if (likely(qc->flags & ATA_QCFLAG_SG))
+	if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
 		ata_sg_clean(qc);
 
-	if (cmd) {
-		if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
-			if (is_atapi_taskfile(&qc->tf))
-				cmd->result = SAM_STAT_CHECK_CONDITION;
-			else
-				ata_to_sense_error(qc);
-		} else {
-			cmd->result = SAM_STAT_GOOD;
-		}
+	/* call completion callback */
+	rc = qc->complete_fn(qc, drv_stat);
 
-		qc->scsidone(cmd);
-	}
+	/* if callback indicates not to complete command (non-zero),
+	 * return immediately
+	 */
+	if (rc != 0)
+		return;
 
-	qc->flags &= ~ATA_QCFLAG_ACTIVE;
+	qc->flags = 0;
 	tag = qc->tag;
 	if (likely(ata_tag_valid(tag))) {
 		if (tag == ap->active_tag)
@@ -2341,11 +2447,16 @@ void ata_qc_complete(struct ata_queued_c
 		do_clear = 1;
 	}
 
-	if (qc->waiting)
-		complete(qc->waiting);
+	if (qc->waiting) {
+		struct completion *waiting = qc->waiting;
+		qc->waiting = NULL;
+		complete(waiting);
+	}
 
 	if (likely(do_clear))
 		clear_bit(tag, &ap->qactive);
+
+	VPRINTK("EXIT\n");
 }
 
 /**
@@ -2367,25 +2478,21 @@ void ata_qc_complete(struct ata_queued_c
 int ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scsi_cmnd *cmd = qc->scsicmd;
 
 	if (qc->flags & ATA_QCFLAG_SG) {
-		/* set up SG table */
-		if (cmd->use_sg) {
-			if (ata_sg_setup(qc))
-				goto err_out;
-		} else {
-			if (ata_sg_setup_one(qc))
-				goto err_out;
-		}
-
-		ap->ops->fill_sg(qc);
+		if (ata_sg_setup(qc))
+			goto err_out;
+	} else if (qc->flags & ATA_QCFLAG_SINGLE) {
+		if (ata_sg_setup_one(qc))
+			goto err_out;
 	}
 
+	ap->ops->qc_prep(qc);
+
 	qc->ap->active_tag = qc->tag;
 	qc->flags |= ATA_QCFLAG_ACTIVE;
 
-	return ata_qc_issue_prot(qc);
+	return ap->ops->qc_issue(qc);
 
 err_out:
 	return -1;
@@ -2407,7 +2514,7 @@ err_out:
  *	Zero on success, negative on error.
  */
 
-static int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 
@@ -2432,6 +2539,12 @@ static int ata_qc_issue_prot(struct ata_
 		break;
 
 	case ATA_PROT_ATAPI:
+		ata_qc_set_polling(qc);
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		schedule_task(&ap->packet_task);
+		break;
+
+	case ATA_PROT_ATAPI_NODATA:
 		ata_tf_to_host_nolock(ap, &qc->tf);
 		schedule_task(&ap->packet_task);
 		break;
@@ -2461,7 +2574,7 @@ void ata_bmdma_setup_mmio (struct ata_qu
 {
 	struct ata_port *ap = qc->ap;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
-	u8 host_stat, dmactl;
+	u8 dmactl;
 	void *mmio = (void *) ap->ioaddr.bmdma_addr;
 
 	/* load PRD table addr. */
@@ -2475,10 +2588,6 @@ void ata_bmdma_setup_mmio (struct ata_qu
 		dmactl |= ATA_DMA_WR;
 	writeb(dmactl, mmio + ATA_DMA_CMD);
 
-	/* clear interrupt, error bits */
-	host_stat = readb(mmio + ATA_DMA_STATUS);
-	writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS);
-
 	/* issue r/w command */
 	ap->ops->exec_command(ap, &qc->tf);
 }
@@ -2526,7 +2635,7 @@ void ata_bmdma_setup_pio (struct ata_que
 {
 	struct ata_port *ap = qc->ap;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
-	u8 host_stat, dmactl;
+	u8 dmactl;
 
 	/* load PRD table addr. */
 	outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
@@ -2538,11 +2647,6 @@ void ata_bmdma_setup_pio (struct ata_que
 		dmactl |= ATA_DMA_WR;
 	outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 
-	/* clear interrupt, error bits */
-	host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-	outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-	     ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
 	/* issue r/w command */
 	ap->ops->exec_command(ap, &qc->tf);
 }
@@ -2566,48 +2670,9 @@ void ata_bmdma_start_pio (struct ata_que
 	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
-/**
- *	ata_dma_complete - Complete an active ATA BMDMA command
- *	@qc: Command to complete
- *	@host_stat: BMDMA status register contents
- *
- *	LOCKING:
- */
-
-static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat)
+void ata_bmdma_irq_clear(struct ata_port *ap)
 {
-	struct ata_port *ap = qc->ap;
-	VPRINTK("ENTER\n");
-
-	if (ap->flags & ATA_FLAG_MMIO) {
-		void *mmio = (void *) ap->ioaddr.bmdma_addr;
-
-		/* clear start/stop bit */
-		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
-		       mmio + ATA_DMA_CMD);
-
-		/* ack intr, err bits */
-		writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-		       mmio + ATA_DMA_STATUS);
-	} else {
-		/* clear start/stop bit */
-		outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
-		     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
-		/* ack intr, err bits */
-		outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-		     ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-	}
-
-
-	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
-	ata_altstatus(ap);		/* dummy read */
-
-	DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n",
-		ap->id, (u32) host_stat, (u32) ata_chk_status(ap));
-
-	/* get drive status; clear intr; complete txn */
-	ata_qc_complete(qc, ata_wait_idle(ap));
+	ata_bmdma_ack_irq(ap);
 }
 
 /**
@@ -2630,59 +2695,63 @@ inline unsigned int ata_host_intr (struc
 				   struct ata_queued_cmd *qc)
 {
 	u8 status, host_stat;
-	unsigned int handled = 0;
 
 	switch (qc->tf.protocol) {
 
-	/* BMDMA completion */
 	case ATA_PROT_DMA:
 	case ATA_PROT_ATAPI_DMA:
-		if (ap->flags & ATA_FLAG_MMIO) {
-			void *mmio = (void *) ap->ioaddr.bmdma_addr;
-			host_stat = readb(mmio + ATA_DMA_STATUS);
-		} else
-			host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-		VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat);
+	case ATA_PROT_ATAPI:
+		/* check status of DMA engine */
+		host_stat = ata_bmdma_status(ap);
+		VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
 
-		if (!(host_stat & ATA_DMA_INTR)) {
-			ap->stats.idle_irq++;
-			break;
-		}
+		/* if it's not our irq... */
+		if (!(host_stat & ATA_DMA_INTR))
+			goto idle_irq;
 
-		ata_dma_complete(qc, host_stat);
-		handled = 1;
-		break;
+		/* before we do anything else, clear DMA-Start bit */
+		ata_bmdma_stop(ap);
 
-	/* command completion, but no data xfer */
-	/* FIXME: a shared interrupt _will_ cause a non-data command
-	 * to be completed prematurely, with an error.
-	 *
-	 * This doesn't matter right now, since we aren't sending
-	 * non-data commands down this pipe except in development
-	 * situations.
-	 */
-	case ATA_PROT_ATAPI:
+		/* fall through */
+
+	case ATA_PROT_ATAPI_NODATA:
 	case ATA_PROT_NODATA:
-		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		/* check altstatus */
+		status = ata_altstatus(ap);
+		if (status & ATA_BUSY)
+			goto idle_irq;
+
+		/* check main status, clearing INTRQ */
+		status = ata_chk_status(ap);
+		if (unlikely(status & ATA_BUSY))
+			goto idle_irq;
+		DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+			ap->id, qc->tf.protocol, status);
+
+		/* ack bmdma irq events */
+		ata_bmdma_ack_irq(ap);
+
+		/* complete taskfile transaction */
 		ata_qc_complete(qc, status);
-		handled = 1;
 		break;
 
 	default:
-		ap->stats.idle_irq++;
+		goto idle_irq;
+	}
+
+	return 1;	/* irq handled */
+
+idle_irq:
+	ap->stats.idle_irq++;
 
 #ifdef ATA_IRQ_TRAP
-		if ((ap->stats.idle_irq % 1000) == 0) {
-			handled = 1;
-			ata_irq_ack(ap, 0); /* debug trap */
-			printk(KERN_WARNING "ata%d: irq trap\n", ap->id);
-		}
-#endif
-		break;
+	if ((ap->stats.idle_irq % 1000) == 0) {
+		handled = 1;
+		ata_irq_ack(ap, 0); /* debug trap */
+		printk(KERN_WARNING "ata%d: irq trap\n", ap->id);
 	}
-
-	return handled;
+#endif
+	return 0;	/* irq not handled */
 }
 
 /**
@@ -2716,7 +2785,7 @@ irqreturn_t ata_interrupt (int irq, void
 
 			qc = ata_qc_from_tag(ap, ap->active_tag);
 			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
-				handled += ata_host_intr(ap, qc);
+				handled |= ata_host_intr(ap, qc);
 		}
 	}
 
@@ -2726,62 +2795,6 @@ irqreturn_t ata_interrupt (int irq, void
 }
 
 /**
- *	ata_thread_iter -
- *	@ap:
- *
- *	LOCKING:
- *
- *	RETURNS:
- *
- */
-
-static unsigned long ata_thread_iter(struct ata_port *ap)
-{
-	long timeout = 0;
-
-	DPRINTK("ata%u: thr_state %s\n",
-		ap->id, ata_thr_state_name(ap->thr_state));
-
-	switch (ap->thr_state) {
-	case THR_UNKNOWN:
-		ap->thr_state = THR_PORT_RESET;
-		break;
-
-	case THR_PROBE_START:
-		ap->thr_state = THR_PORT_RESET;
-		break;
-
-	case THR_PORT_RESET:
-		ata_port_reset(ap);
-		break;
-
-	case THR_PROBE_SUCCESS:
-		up(&ap->probe_sem);
-		ap->thr_state = THR_IDLE;
-		break;
-
-	case THR_PROBE_FAILED:
-		up(&ap->probe_sem);
-		ap->thr_state = THR_AWAIT_DEATH;
-		break;
-
-	case THR_AWAIT_DEATH:
-	case THR_IDLE:
-		timeout = -1;
-		break;
-
-	default:
-		printk(KERN_DEBUG "ata%u: unknown thr state %s\n",
-		       ap->id, ata_thr_state_name(ap->thr_state));
-		break;
-	}
-
-	DPRINTK("ata%u: new thr_state %s, returning %ld\n",
-		ap->id, ata_thr_state_name(ap->thr_state), timeout);
-	return timeout;
-}
-
-/**
  *	atapi_packet_task - Write CDB bytes to hardware
  *	@_data: Port to which ATAPI device is attached.
  *
@@ -2812,21 +2825,20 @@ static void atapi_packet_task(void *_dat
 
 	/* make sure DRQ is set */
 	status = ata_chk_status(ap);
-	if ((status & ATA_DRQ) == 0)
+	if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
 		goto err_out;
 
 	/* send SCSI cdb */
-	/* FIXME: mmio-ize */
 	DPRINTK("send cdb\n");
-	outsl(ap->ioaddr.data_addr,
-	      qc->scsicmd->cmnd, ap->host->max_cmd_len / 4);
+	assert(ap->cdb_len >= 12);
+	ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
 
 	/* if we are DMA'ing, irq handler takes over from here */
 	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
 		ap->ops->bmdma_start(qc);	    /* initiate bmdma */
 
 	/* non-data commands are also handled via irq */
-	else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) {
+	else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
 		/* do nothing */
 	}
 
@@ -2862,23 +2874,6 @@ void ata_port_stop (struct ata_port *ap)
 	pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
 }
 
-static void ata_probe_task(void *_data)
-{
-	struct ata_port *ap = _data;
-	long timeout;
-
-	timeout = ata_thread_iter(ap);
-	if (timeout < 0)
-		return;
-
-	if (timeout > 0) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(timeout);
-	}
-
-	schedule_task(&ap->probe_task);
-}
-
 /**
  *	ata_host_remove - Unregister SCSI host structure with upper layers
  *	@ap: Port to unregister
@@ -2931,24 +2926,20 @@ static void ata_host_init(struct ata_por
 	ap->host_set = host_set;
 	ap->port_no = port_no;
 	ap->pio_mask = ent->pio_mask;
+	ap->mwdma_mask = ent->mwdma_mask;
 	ap->udma_mask = ent->udma_mask;
 	ap->flags |= ent->host_flags;
 	ap->ops = ent->port_ops;
-	ap->thr_state = THR_PROBE_START;
 	ap->cbl = ATA_CBL_NONE;
-	ap->device[0].flags = ATA_DFLAG_MASTER;
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
 	INIT_TQUEUE(&ap->packet_task, atapi_packet_task, ap);
 	INIT_TQUEUE(&ap->pio_task, ata_pio_task, ap);
-	INIT_TQUEUE(&ap->probe_task, ata_probe_task, ap);
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
 		ap->device[i].devno = i;
 
-	init_MUTEX_LOCKED(&ap->probe_sem);
-
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
 	ap->stats.idle_irq = 1;
@@ -3027,28 +3018,35 @@ int ata_device_add(struct ata_probe_ent 
 	host_set->irq = ent->irq;
 	host_set->mmio_base = ent->mmio_base;
 	host_set->private_data = ent->private_data;
+	host_set->ops = ent->port_ops;
 
 	/* register each port bound to this device */
 	for (i = 0; i < ent->n_ports; i++) {
 		struct ata_port *ap;
+		unsigned long xfer_mode_mask;
 
 		ap = ata_host_add(ent, host_set, i);
 		if (!ap)
 			goto err_out;
 
 		host_set->ports[i] = ap;
+		xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
+				(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
+				(ap->pio_mask << ATA_SHIFT_PIO);
 
 		/* print per-port info to dmesg */
 		printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX "
 				 "bmdma 0x%lX irq %lu\n",
 			ap->id,
 			ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
-			ata_udma_string(ent->udma_mask),
+			ata_mode_string(xfer_mode_mask),
 	       		ap->ioaddr.cmd_addr,
 	       		ap->ioaddr.ctl_addr,
 	       		ap->ioaddr.bmdma_addr,
 	       		ent->irq);
 
+		ata_chk_status(ap);
+		host_set->ops->irq_clear(ap);
 		count++;
 	}
 
@@ -3066,16 +3064,22 @@ int ata_device_add(struct ata_probe_ent 
 	DPRINTK("probe begin\n");
 	for (i = 0; i < count; i++) {
 		struct ata_port *ap;
+		int rc;
 
 		ap = host_set->ports[i];
 
 		DPRINTK("ata%u: probe begin\n", ap->id);
-		schedule_task(&ap->probe_task);		/* start probe */
-
-		DPRINTK("ata%u: probe-wait begin\n", ap->id);
-		down(&ap->probe_sem);	/* wait for end */
+		rc = ata_bus_probe(ap);
+		DPRINTK("ata%u: probe end\n", ap->id);
 
-		DPRINTK("ata%u: probe-wait end\n", ap->id);
+		if (rc) {
+			/* FIXME: do something useful here?
+			 * Current libata behavior will
+			 * tear down everything when
+			 * the module is removed
+			 * or the h/w is unplugged.
+			 */
+		}
 	}
 
 	pci_set_drvdata(pdev, host_set);
@@ -3276,6 +3280,7 @@ int ata_pci_init_one (struct pci_dev *pd
 	probe_ent->sht = port0->sht;
 	probe_ent->host_flags = port0->host_flags;
 	probe_ent->pio_mask = port0->pio_mask;
+	probe_ent->mwdma_mask = port0->mwdma_mask;
 	probe_ent->udma_mask = port0->udma_mask;
 	probe_ent->port_ops = port0->port_ops;
 
@@ -3298,6 +3303,7 @@ int ata_pci_init_one (struct pci_dev *pd
 		probe_ent2->sht = port1->sht;
 		probe_ent2->host_flags = port1->host_flags;
 		probe_ent2->pio_mask = port1->pio_mask;
+		probe_ent2->mwdma_mask = port1->mwdma_mask;
 		probe_ent2->udma_mask = port1->udma_mask;
 		probe_ent2->port_ops = port1->port_ops;
 	} else {
@@ -3383,10 +3389,10 @@ void ata_pci_remove_one (struct pci_dev 
 	/* FIXME: handle 'rc' failure? */
 
 	free_irq(host_set->irq, host_set);
+	if (host_set->ops->host_stop)
+		host_set->ops->host_stop(host_set);
 	if (host_set->mmio_base)
 		iounmap(host_set->mmio_base);
-	if (host_set->ports[0]->ops->host_stop)
-		host_set->ports[0]->ops->host_stop(host_set);
 
 	pci_release_regions(pdev);
 
@@ -3492,7 +3498,10 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_sg_init);
+EXPORT_SYMBOL_GPL(ata_sg_init_one);
 EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_tf_load_pio);
 EXPORT_SYMBOL_GPL(ata_tf_load_mmio);
@@ -3507,11 +3516,12 @@ EXPORT_SYMBOL_GPL(ata_exec_command_mmio)
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
 EXPORT_SYMBOL_GPL(ata_interrupt);
-EXPORT_SYMBOL_GPL(ata_fill_sg);
+EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio);
 EXPORT_SYMBOL_GPL(ata_bmdma_start_pio);
 EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio);
 EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio);
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
@@ -3523,5 +3533,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_error);
 EXPORT_SYMBOL_GPL(ata_scsi_detect);
 EXPORT_SYMBOL_GPL(ata_add_to_probe_list);
 EXPORT_SYMBOL_GPL(ata_scsi_release);
+EXPORT_SYMBOL_GPL(libata_msleep);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_dev_id_string);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/libata-scsi.c linux-2.4.28-pre1/drivers/scsi/libata-scsi.c
--- linux-2.4.27/drivers/scsi/libata-scsi.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/libata-scsi.c	2004-08-15 19:48:02.000000000 +0000
@@ -295,6 +295,20 @@ static unsigned int ata_scsi_rw_xlat(str
 	return 1;
 }
 
+static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+		ata_to_sense_error(qc);
+	else
+		cmd->result = SAM_STAT_GOOD;
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
+
 /**
  *	ata_scsi_translate - Translate then issue SCSI command to ATA device
  *	@ap: ATA port to which the command is addressed
@@ -328,6 +342,7 @@ static void ata_scsi_translate(struct at
 	if (!qc)
 		return;
 
+	/* data is present; dma-map it */
 	if (cmd->sc_data_direction == SCSI_DATA_READ ||
 	    cmd->sc_data_direction == SCSI_DATA_WRITE) {
 		if (unlikely(cmd->request_bufflen < 1)) {
@@ -336,9 +351,17 @@ static void ata_scsi_translate(struct at
 			goto err_out;
 		}
 
-		qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
+		if (cmd->use_sg)
+			ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+		else
+			ata_sg_init_one(qc, cmd->request_buffer,
+					cmd->request_bufflen);
+
+		qc->pci_dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 	}
 
+	qc->complete_fn = ata_scsi_qc_complete;
+
 	if (xlat_func(qc, scsicmd))
 		goto err_out;
 
@@ -897,6 +920,31 @@ void ata_scsi_badcmd(struct scsi_cmnd *c
 	done(cmd);
 }
 
+static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+		cmd->result = SAM_STAT_CHECK_CONDITION;
+	else {
+		u8 *scsicmd = cmd->cmnd;
+
+		if (scsicmd[0] == INQUIRY) {
+			u8 *buf = NULL;
+			unsigned int buflen;
+
+			buflen = ata_scsi_rbuf_get(cmd, &buf);
+			buf[2] = 0x5;
+			buf[3] = (buf[3] & 0xf0) | 2;
+			ata_scsi_rbuf_put(cmd);
+		}
+		cmd->result = SAM_STAT_GOOD;
+	}
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
 /**
  *	atapi_xlat - Initialize PACKET taskfile
  *	@qc: command structure to be initialized
@@ -912,6 +960,13 @@ void ata_scsi_badcmd(struct scsi_cmnd *c
 static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
 {
 	struct scsi_cmnd *cmd = qc->scsicmd;
+	struct ata_device *dev = qc->dev;
+	int using_pio = (dev->flags & ATA_DFLAG_PIO);
+	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
+
+	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+
+	qc->complete_fn = atapi_qc_complete;
 
 	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
@@ -921,19 +976,18 @@ static unsigned int atapi_xlat(struct at
 
 	qc->tf.command = ATA_CMD_PACKET;
 
-	/* no data - interrupt-driven */
-	if (cmd->sc_data_direction == SCSI_DATA_NONE)
-		qc->tf.protocol = ATA_PROT_ATAPI;
-
-	/* PIO data xfer - polling */
-	else if ((qc->flags & ATA_QCFLAG_DMA) == 0) {
-		ata_qc_set_polling(qc);
-		qc->tf.protocol = ATA_PROT_ATAPI;
+	/* no data, or PIO data xfer */
+	if (using_pio || nodata) {
+		if (nodata)
+			qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+		else
+			qc->tf.protocol = ATA_PROT_ATAPI;
 		qc->tf.lbam = (8 * 1024) & 0xff;
 		qc->tf.lbah = (8 * 1024) >> 8;
+	}
 
-	/* DMA data xfer - interrupt-driven */
-	} else {
+	/* DMA data xfer */
+	else {
 		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
 		qc->tf.feature |= ATAPI_PKT_DMA;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/pluto.c linux-2.4.28-pre1/drivers/scsi/pluto.c
--- linux-2.4.27/drivers/scsi/pluto.c	2001-02-09 19:30:23.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/pluto.c	2004-08-15 19:49:16.000000000 +0000
@@ -339,4 +339,4 @@ static Scsi_Host_Template driver_templat
 
 #include "scsi_module.c"
 
-EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/qlogicfc.c linux-2.4.28-pre1/drivers/scsi/qlogicfc.c
--- linux-2.4.27/drivers/scsi/qlogicfc.c	2004-04-14 13:05:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/qlogicfc.c	2004-08-15 19:51:00.000000000 +0000
@@ -722,7 +722,7 @@ int isp2x00_detect(Scsi_Host_Template * 
 				continue;
 
 			/* Try to configure DMA attributes. */
-			if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
+			if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) &&
 			    pci_set_dma_mask(pdev, (u64) 0xffffffff))
 					continue;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/qlogicpti.c linux-2.4.28-pre1/drivers/scsi/qlogicpti.c
--- linux-2.4.27/drivers/scsi/qlogicpti.c	2004-04-14 13:05:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/qlogicpti.c	2004-08-15 19:50:48.000000000 +0000
@@ -1533,4 +1533,4 @@ static Scsi_Host_Template driver_templat
 
 #include "scsi_module.c"
 
-EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_nv.c linux-2.4.28-pre1/drivers/scsi/sata_nv.c
--- linux-2.4.27/drivers/scsi/sata_nv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_nv.c	2004-08-15 19:51:52.000000000 +0000
@@ -0,0 +1,365 @@
+/*
+ *  sata_nv.c - NVIDIA nForce SATA
+ *
+ *  Copyright 2004 NVIDIA Corp.  All rights reserved.
+ *  Copyright 2004 Andrew Chew
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME			"sata_nv"
+#define DRV_VERSION			"0.01"
+
+#define NV_PORTS			2
+#define NV_PIO_MASK			0x1f
+#define NV_MWDMA_MASK			0x07
+#define NV_UDMA_MASK			0x7f
+#define NV_PORT0_BMDMA_REG_OFFSET	0x00
+#define NV_PORT1_BMDMA_REG_OFFSET	0x08
+#define NV_PORT0_SCR_REG_OFFSET		0x00
+#define NV_PORT1_SCR_REG_OFFSET		0x40
+
+#define NV_INT_STATUS			0x10
+#define NV_INT_STATUS_PDEV_INT		0x01
+#define NV_INT_STATUS_PDEV_PM		0x02
+#define NV_INT_STATUS_PDEV_ADDED	0x04
+#define NV_INT_STATUS_PDEV_REMOVED	0x08
+#define NV_INT_STATUS_SDEV_INT		0x10
+#define NV_INT_STATUS_SDEV_PM		0x20
+#define NV_INT_STATUS_SDEV_ADDED	0x40
+#define NV_INT_STATUS_SDEV_REMOVED	0x80
+#define NV_INT_STATUS_PDEV_HOTPLUG	(NV_INT_STATUS_PDEV_ADDED | \
+					NV_INT_STATUS_PDEV_REMOVED)
+#define NV_INT_STATUS_SDEV_HOTPLUG	(NV_INT_STATUS_SDEV_ADDED | \
+					NV_INT_STATUS_SDEV_REMOVED)
+#define NV_INT_STATUS_HOTPLUG		(NV_INT_STATUS_PDEV_HOTPLUG | \
+					NV_INT_STATUS_SDEV_HOTPLUG)
+
+#define NV_INT_ENABLE			0x11
+#define NV_INT_ENABLE_PDEV_MASK		0x01
+#define NV_INT_ENABLE_PDEV_PM		0x02
+#define NV_INT_ENABLE_PDEV_ADDED	0x04
+#define NV_INT_ENABLE_PDEV_REMOVED	0x08
+#define NV_INT_ENABLE_SDEV_MASK		0x10
+#define NV_INT_ENABLE_SDEV_PM		0x20
+#define NV_INT_ENABLE_SDEV_ADDED	0x40
+#define NV_INT_ENABLE_SDEV_REMOVED	0x80
+#define NV_INT_ENABLE_PDEV_HOTPLUG	(NV_INT_ENABLE_PDEV_ADDED | \
+					NV_INT_ENABLE_PDEV_REMOVED)
+#define NV_INT_ENABLE_SDEV_HOTPLUG	(NV_INT_ENABLE_SDEV_ADDED | \
+					NV_INT_ENABLE_SDEV_REMOVED)
+#define NV_INT_ENABLE_HOTPLUG		(NV_INT_ENABLE_PDEV_HOTPLUG | \
+					NV_INT_ENABLE_SDEV_HOTPLUG)
+
+#define NV_INT_CONFIG			0x12
+#define NV_INT_CONFIG_METHD		0x01 // 0 = INT, 1 = SMI
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void nv_host_stop (struct ata_host_set *host_set);
+
+static struct pci_device_id nv_pci_tbl[] = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, } /* terminate list */
+};
+
+static struct pci_driver nv_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= nv_pci_tbl,
+	.probe			= nv_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template nv_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.detect			= ata_scsi_detect,
+	.release		= ata_scsi_release,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.use_new_eh_code	= ATA_SHT_NEW_EH_CODE,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations nv_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load_pio,
+	.tf_read		= ata_tf_read_pio,
+	.exec_command		= ata_exec_command_pio,
+	.check_status		= ata_check_status_pio,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup		= ata_bmdma_setup_pio,
+	.bmdma_start		= ata_bmdma_start_pio,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= nv_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= nv_scr_read,
+	.scr_write		= nv_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+	.host_stop		= nv_host_stop,
+};
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+
+irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	unsigned long flags;
+	u8 intr_status;
+	u8 intr_enable;
+
+	spin_lock_irqsave(&host_set->lock, flags);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+		if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+				handled += ata_host_intr(ap, qc);
+		}
+
+		intr_status = inb(ap->ioaddr.scr_addr + NV_INT_STATUS);
+		intr_enable = inb(ap->ioaddr.scr_addr + NV_INT_ENABLE);
+
+		// Clear interrupt status.
+		outb(0xff, ap->ioaddr.scr_addr + NV_INT_STATUS);
+
+		if (intr_status & NV_INT_STATUS_HOTPLUG) {
+			if (intr_status & NV_INT_STATUS_PDEV_ADDED) {
+				printk(KERN_WARNING "ata%u: "
+					"Primary device added\n", ap->id);
+			}
+
+			if (intr_status & NV_INT_STATUS_PDEV_REMOVED) {
+				printk(KERN_WARNING "ata%u: "
+					"Primary device removed\n", ap->id);
+			}
+
+			if (intr_status & NV_INT_STATUS_SDEV_ADDED) {
+				printk(KERN_WARNING "ata%u: "
+					"Secondary device added\n", ap->id);
+			}
+
+			if (intr_status & NV_INT_STATUS_SDEV_REMOVED) {
+				printk(KERN_WARNING "ata%u: "
+					"Secondary device removed\n", ap->id);
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+
+	outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_host_stop (struct ata_host_set *host_set)
+{
+	int i;
+
+	for (i=0; i<host_set->n_ports; i++) {
+		u8 intr_mask;
+
+		// Disable hotplug event interrupts.
+		intr_mask = inb(host_set->ports[i]->ioaddr.scr_addr +
+				NV_INT_ENABLE);
+		intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
+		outb(intr_mask, host_set->ports[i]->ioaddr.scr_addr +
+				NV_INT_ENABLE);
+	}
+}
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version = 0;
+	struct ata_probe_ent *probe_ent = NULL;
+	int i;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	probe_ent->pdev = pdev;
+	probe_ent->sht = &nv_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA |
+				ATA_FLAG_SATA_RESET |
+				ATA_FLAG_SRST |
+				ATA_FLAG_NO_LEGACY;
+	probe_ent->port_ops = &nv_ops;
+	probe_ent->n_ports = NV_PORTS;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->pio_mask = NV_PIO_MASK;
+	probe_ent->mwdma_mask = NV_MWDMA_MASK;
+	probe_ent->udma_mask = NV_UDMA_MASK;
+
+	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+	ata_std_ports(&probe_ent->port[0]);
+	probe_ent->port[0].altstatus_addr =
+	probe_ent->port[0].ctl_addr =
+		pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+	probe_ent->port[0].bmdma_addr =
+		pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET;
+	probe_ent->port[0].scr_addr =
+		pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET;
+
+	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+	ata_std_ports(&probe_ent->port[1]);
+	probe_ent->port[1].altstatus_addr =
+	probe_ent->port[1].ctl_addr =
+		pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+	probe_ent->port[1].bmdma_addr =
+		pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET;
+	probe_ent->port[1].scr_addr =
+		pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET;
+
+	pci_set_master(pdev);
+
+	// Enable hotplug event interrupts.
+	for (i=0; i<probe_ent->n_ports; i++) {
+		u8 intr_mask;
+
+		outb(NV_INT_STATUS_HOTPLUG, probe_ent->port[i].scr_addr +
+						NV_INT_STATUS);
+
+		intr_mask = inb(probe_ent->port[i].scr_addr + NV_INT_ENABLE);
+		intr_mask |= NV_INT_ENABLE_HOTPLUG;
+		outb(intr_mask, probe_ent->port[i].scr_addr + NV_INT_ENABLE);
+	}
+
+	ata_add_to_probe_list(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+static int __init nv_init(void)
+{
+	int rc;
+
+	rc = pci_module_init(&nv_pci_driver);
+	if (rc)
+		return rc;
+	
+	rc = scsi_register_module(MODULE_SCSI_HA, &nv_sht);
+	if (rc) {
+		pci_unregister_driver(&nv_pci_driver);
+		/* TODO: does scsi_register_module return errno val? */
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit nv_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &nv_sht);
+	pci_unregister_driver(&nv_pci_driver);
+}
+
+module_init(nv_init);
+module_exit(nv_exit);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_promise.c linux-2.4.28-pre1/drivers/scsi/sata_promise.c
--- linux-2.4.27/drivers/scsi/sata_promise.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_promise.c	2004-08-15 19:47:21.000000000 +0000
@@ -42,6 +42,7 @@
 #define DRV_NAME	"sata_promise"
 #define DRV_VERSION	"1.00"
 
+#define msleep libata_msleep	/* 2.4-specific */
 
 enum {
 	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
@@ -74,18 +75,16 @@ struct pdc_port_priv {
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void pdc_dma_setup(struct ata_queued_cmd *qc);
-static void pdc_dma_start(struct ata_queued_cmd *qc);
 static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 static void pdc_eng_timeout(struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc_port_stop(struct ata_port *ap);
 static void pdc_phy_reset(struct ata_port *ap);
-static void pdc_fill_sg(struct ata_queued_cmd *qc);
+static void pdc_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
-static inline void pdc_dma_complete (struct ata_port *ap,
-                                     struct ata_queued_cmd *qc, int have_err);
+static void pdc_irq_clear(struct ata_port *ap);
+static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 
 static Scsi_Host_Template pdc_sata_sht = {
 	.module			= THIS_MODULE,
@@ -113,11 +112,11 @@ static struct ata_port_operations pdc_sa
 	.check_status		= ata_check_status_mmio,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= pdc_phy_reset,
-	.bmdma_setup            = pdc_dma_setup,
-	.bmdma_start            = pdc_dma_start,
-	.fill_sg		= pdc_fill_sg,
+	.qc_prep		= pdc_qc_prep,
+	.qc_issue		= pdc_qc_issue_prot,
 	.eng_timeout		= pdc_eng_timeout,
 	.irq_handler		= pdc_interrupt,
+	.irq_clear		= pdc_irq_clear,
 	.scr_read		= pdc_sata_scr_read,
 	.scr_write		= pdc_sata_scr_write,
 	.port_start		= pdc_port_start,
@@ -130,7 +129,8 @@ static struct ata_port_info pdc_port_inf
 		.sht		= &pdc_sata_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x03, /* pio3-4 */
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
@@ -140,7 +140,8 @@ static struct ata_port_info pdc_port_inf
 		.sht		= &pdc_sata_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x03, /* pio3-4 */
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
@@ -262,33 +263,33 @@ static void pdc_sata_scr_write (struct a
 	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void pdc_fill_sg(struct ata_queued_cmd *qc)
+static void pdc_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct pdc_port_priv *pp = qc->ap->private_data;
 	unsigned int i;
 
 	VPRINTK("ENTER\n");
 
-	ata_fill_sg(qc);
-
-	i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,  qc->dev->devno, pp->pkt);
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		ata_qc_prep(qc);
+		/* fall through */
 
-	if (qc->tf.flags & ATA_TFLAG_LBA48)
-		i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
-	else
-		i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
+	case ATA_PROT_NODATA:
+		i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
+				   qc->dev->devno, pp->pkt);
 
-	pdc_pkt_footer(&qc->tf, pp->pkt, i);
-}
+		if (qc->tf.flags & ATA_TFLAG_LBA48)
+			i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
+		else
+			i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
 
-static inline void pdc_dma_complete (struct ata_port *ap,
-                                     struct ata_queued_cmd *qc,
-				     int have_err)
-{
-	u8 err_bit = have_err ? ATA_ERR : 0;
+		pdc_pkt_footer(&qc->tf, pp->pkt, i);
+		break;
 
-	/* get drive status; clear intr; complete txn */
-	ata_qc_complete(qc, ata_wait_idle(ap) | err_bit);
+	default:
+		break;
+	}
 }
 
 static void pdc_eng_timeout(struct ata_port *ap)
@@ -315,17 +316,9 @@ static void pdc_eng_timeout(struct ata_p
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
-		printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
-		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
-		break;
-
 	case ATA_PROT_NODATA:
-		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-
-		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
-		       ap->id, qc->tf.command, drv_stat);
-
-		ata_qc_complete(qc, drv_stat);
+		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
 		break;
 
 	default:
@@ -358,13 +351,8 @@ static inline unsigned int pdc_host_intr
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
-		pdc_dma_complete(ap, qc, have_err);
-		handled = 1;
-		break;
-
-	case ATA_PROT_NODATA:   /* command completion, but no data xfer */
-		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+	case ATA_PROT_NODATA:
+		status = ata_wait_idle(ap);
 		if (have_err)
 			status |= ATA_ERR;
 		ata_qc_complete(qc, status);
@@ -379,6 +367,14 @@ static inline unsigned int pdc_host_intr
         return handled;
 }
 
+static void pdc_irq_clear(struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	readl(mmio + PDC_INT_SEQMASK);
+}
+
 static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
@@ -432,13 +428,7 @@ static irqreturn_t pdc_interrupt (int ir
 	return IRQ_RETVAL(handled);
 }
 
-static void pdc_dma_setup(struct ata_queued_cmd *qc)
-{
-	/* nothing for now.  later, we will call standard
-	 * code in libata-core for ATAPI here */
-}
-
-static void pdc_dma_start(struct ata_queued_cmd *qc)
+static inline void pdc_packet_start(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct pdc_port_priv *pp = ap->private_data;
@@ -456,17 +446,38 @@ static void pdc_dma_start(struct ata_que
 	readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
 }
 
+static int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		pdc_packet_start(qc);
+		return 0;
+
+	case ATA_PROT_ATAPI_DMA:
+		BUG();
+		break;
+
+	default:
+		break;
+	}
+
+	return ata_qc_issue_prot(qc);
+}
+
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	if (tf->protocol != ATA_PROT_DMA)
-		ata_tf_load_mmio(ap, tf);
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_tf_load_mmio(ap, tf);
 }
 
 
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	if (tf->protocol != ATA_PROT_DMA)
-		ata_exec_command_mmio(ap, tf);
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_exec_command_mmio(ap, tf);
 }
 
 
@@ -519,8 +530,7 @@ static void pdc_host_init(unsigned int c
 	writel(tmp, mmio + PDC_TBG_MODE);
 
 	readl(mmio + PDC_TBG_MODE);	/* flush */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(msecs_to_jiffies(10) + 1);
+	msleep(10);
 
 	/* adjust slew rate control register. */
 	tmp = readl(mmio + PDC_SLEW_CTL);
@@ -578,6 +588,7 @@ static int pdc_sata_init_one (struct pci
 	probe_ent->sht		= pdc_port_info[board_idx].sht;
 	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
 	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;
 	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
 	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_sil.c linux-2.4.28-pre1/drivers/scsi/sata_sil.c
--- linux-2.4.27/drivers/scsi/sata_sil.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_sil.c	2004-08-15 19:50:12.000000000 +0000
@@ -86,6 +86,7 @@ struct sil_drivelist {
 	{ "ST360015AS",		SIL_QUIRK_MOD15WRITE },
 	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },
 	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3160023AS",	SIL_QUIRK_MOD15WRITE },
 	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },
 	{ "ST360014ASL",	SIL_QUIRK_MOD15WRITE },
 	{ "ST380011ASL",	SIL_QUIRK_MOD15WRITE },
@@ -132,9 +133,11 @@ static struct ata_port_operations sil_op
 	.post_set_mode		= sil_post_set_mode,
 	.bmdma_setup            = ata_bmdma_setup_mmio,
 	.bmdma_start            = ata_bmdma_start_mmio,
-	.fill_sg		= ata_fill_sg,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
 	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= sil_scr_read,
 	.scr_write		= sil_scr_write,
 	.port_start		= ata_port_start,
@@ -147,7 +150,8 @@ static struct ata_port_info sil_port_inf
 		.sht		= &sil_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x03,			/* pio3-4 */
+		.pio_mask	= 0x1f,			/* pio0-4 */
+		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
 		.port_ops	= &sil_ops,
 	}, /* sil_3114 */
@@ -155,7 +159,8 @@ static struct ata_port_info sil_port_inf
 		.sht		= &sil_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x03,			/* pio3-4 */
+		.pio_mask	= 0x1f,			/* pio0-4 */
+		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= 0x3f,			/* udma0-5 */
 		.port_ops	= &sil_ops,
 	},
@@ -303,6 +308,7 @@ static void sil_dev_config(struct ata_po
 		       ap->id, dev->devno);
 		ap->host->max_sectors = 15;
 		ap->host->hostt->max_sectors = 15;
+		dev->flags |= ATA_DFLAG_LOCK_SECTORS;
 		return;
 	}
 
@@ -357,6 +363,7 @@ static int sil_init_one (struct pci_dev 
 	probe_ent->sht = sil_port_info[ent->driver_data].sht;
 	probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
 	probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
+	probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
 	probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
        	probe_ent->irq = pdev->irq;
        	probe_ent->irq_flags = SA_SHIRQ;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_sis.c linux-2.4.28-pre1/drivers/scsi/sata_sis.c
--- linux-2.4.27/drivers/scsi/sata_sis.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_sis.c	2004-08-15 19:49:41.000000000 +0000
@@ -101,9 +101,11 @@ static struct ata_port_operations sis_op
 	.phy_reset		= sata_phy_reset,
 	.bmdma_setup            = ata_bmdma_setup_pio,
 	.bmdma_start            = ata_bmdma_start_pio,
-	.fill_sg		= ata_fill_sg,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
 	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= sis_scr_read,
 	.scr_write		= sis_scr_write,
 	.port_start		= ata_port_start,
@@ -226,7 +228,8 @@ static int sis_init_one (struct pci_dev 
 		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
 	}
 
-	probe_ent->pio_mask = 0x03;
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x7;
 	probe_ent->udma_mask = 0x7f;
 	probe_ent->port_ops = &sis_ops;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_svw.c linux-2.4.28-pre1/drivers/scsi/sata_svw.c
--- linux-2.4.27/drivers/scsi/sata_svw.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_svw.c	2004-08-15 19:50:45.000000000 +0000
@@ -234,9 +234,11 @@ static struct ata_port_operations k2_sat
 	.phy_reset		= sata_phy_reset,
 	.bmdma_setup            = ata_bmdma_setup_mmio,
 	.bmdma_start            = ata_bmdma_start_mmio,
-	.fill_sg		= ata_fill_sg,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
 	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= k2_sata_scr_read,
 	.scr_write		= k2_sata_scr_write,
 	.port_start		= ata_port_start,
@@ -339,6 +341,7 @@ static int k2_sata_init_one (struct pci_
 	 * if we don't fill these
 	 */
 	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x7;
 	probe_ent->udma_mask = 0x7f;
 
 	/* We have 4 ports per PCI function */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_sx4.c linux-2.4.28-pre1/drivers/scsi/sata_sx4.c
--- linux-2.4.27/drivers/scsi/sata_sx4.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_sx4.c	2004-08-15 19:49:54.000000000 +0000
@@ -146,19 +146,15 @@ struct pdc_host_priv {
 
 
 static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void pdc20621_dma_setup(struct ata_queued_cmd *qc);
-static void pdc20621_dma_start(struct ata_queued_cmd *qc);
 static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 static void pdc_eng_timeout(struct ata_port *ap);
 static void pdc_20621_phy_reset (struct ata_port *ap);
 static int pdc_port_start(struct ata_port *ap);
 static void pdc_port_stop(struct ata_port *ap);
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
 static void pdc20621_host_stop(struct ata_host_set *host_set);
-static inline void pdc_dma_complete (struct ata_port *ap,
-                                     struct ata_queued_cmd *qc, int have_err);
 static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
 static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
 static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
@@ -171,6 +167,8 @@ static void pdc20621_get_from_dimm(struc
 #endif
 static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
 				 void *psource, u32 offset, u32 size);
+static void pdc20621_irq_clear(struct ata_port *ap);
+static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
 
 
 static Scsi_Host_Template pdc_sata_sht = {
@@ -199,11 +197,11 @@ static struct ata_port_operations pdc_20
 	.check_status		= ata_check_status_mmio,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= pdc_20621_phy_reset,
-	.bmdma_setup            = pdc20621_dma_setup,
-	.bmdma_start            = pdc20621_dma_start,
-	.fill_sg		= pdc20621_fill_sg,
+	.qc_prep		= pdc20621_qc_prep,
+	.qc_issue		= pdc20621_qc_issue_prot,
 	.eng_timeout		= pdc_eng_timeout,
 	.irq_handler		= pdc20621_interrupt,
+	.irq_clear		= pdc20621_irq_clear,
 	.port_start		= pdc_port_start,
 	.port_stop		= pdc_port_stop,
 	.host_stop		= pdc20621_host_stop,
@@ -215,7 +213,8 @@ static struct ata_port_info pdc_port_inf
 		.sht		= &pdc_sata_sht,
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
-		.pio_mask	= 0x03, /* pio3-4 */
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_20621_ops,
 	},
@@ -375,7 +374,10 @@ static inline unsigned int pdc20621_ata_
 
 	/* dimm dma S/G, and next-pkt */
 	dw = i >> 2;
-	buf32[dw] = cpu_to_le32(dimm_sg);
+	if (tf->protocol == ATA_PROT_NODATA)
+		buf32[dw] = 0;
+	else
+		buf32[dw] = cpu_to_le32(dimm_sg);
 	buf32[dw + 1] = 0;
 	i += 8;
 
@@ -435,7 +437,7 @@ static inline void pdc20621_host_pkt(str
 		buf32[dw + 3]);
 }
 
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
+static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
 {
 	struct scatterlist *sg = qc->sg;
 	struct ata_port *ap = qc->ap;
@@ -447,6 +449,8 @@ static void pdc20621_fill_sg(struct ata_
 	unsigned int i, last, idx, total_len = 0, sgt_len;
 	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
 
+	assert(qc->flags & ATA_QCFLAG_DMAMAP);
+
 	VPRINTK("ata%u: ENTER\n", ap->id);
 
 	/* hard-code chip #0 */
@@ -496,6 +500,56 @@ static void pdc20621_fill_sg(struct ata_
 	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
 }
 
+static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+	unsigned int portno = ap->port_no;
+	unsigned int i;
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+	else
+		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+	/* copy three S/G tables and two packets to DIMM MMIO window */
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+
+	/* force host FIFO dump */
+	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+	readl(dimm_mmio);	/* MMIO PCI posting flush */
+
+	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		pdc20621_dma_prep(qc);
+		break;
+	case ATA_PROT_NODATA:
+		pdc20621_nodata_prep(qc);
+		break;
+	default:
+		break;
+	}
+}
+
 static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
 				 unsigned int seq,
 				 u32 pkt_ofs)
@@ -571,13 +625,7 @@ static void pdc20621_dump_hdma(struct at
 static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
 #endif /* ATA_VERBOSE_DEBUG */
 
-static void pdc20621_dma_setup(struct ata_queued_cmd *qc)
-{
-	/* nothing for now.  later, we will call standard
-	 * code in libata-core for ATAPI here */
-}
-
-static void pdc20621_dma_start(struct ata_queued_cmd *qc)
+static void pdc20621_packet_start(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct ata_host_set *host_set = ap->host_set;
@@ -585,24 +633,21 @@ static void pdc20621_dma_start(struct at
 	void *mmio = host_set->mmio_base;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
 	u8 seq = (u8) (port_no + 1);
-	unsigned int doing_hdma = 0, port_ofs;
+	unsigned int port_ofs;
 
 	/* hard-code chip #0 */
 	mmio += PDC_CHIP0_OFS;
 
 	VPRINTK("ata%u: ENTER\n", ap->id);
 
+	wmb();			/* flush PRD, pkt writes */
+
 	port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
 
 	/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
-	if (rw) {
-		doing_hdma = 1;
+	if (rw && qc->tf.protocol == ATA_PROT_DMA) {
 		seq += 4;
-	}
 
-	wmb();			/* flush PRD, pkt writes */
-
-	if (doing_hdma) {
 		pdc20621_dump_hdma(qc);
 		pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
 		VPRINTK("queued ofs 0x%x (%u), seq %u\n",
@@ -623,6 +668,25 @@ static void pdc20621_dma_start(struct at
 	}
 }
 
+static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		pdc20621_packet_start(qc);
+		return 0;
+
+	case ATA_PROT_ATAPI_DMA:
+		BUG();
+		break;
+
+	default:
+		break;
+	}
+
+	return ata_qc_issue_prot(qc);
+}
+
 static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
                                           struct ata_queued_cmd *qc,
 					  unsigned int doing_hdma,
@@ -643,7 +707,8 @@ static inline unsigned int pdc20621_host
 		if (doing_hdma) {
 			VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
 				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-			pdc_dma_complete(ap, qc, 0);
+			/* get drive status; clear intr; complete txn */
+			ata_qc_complete(qc, ata_wait_idle(ap));
 			pdc20621_pop_hdma(qc);
 		}
 
@@ -680,7 +745,8 @@ static inline unsigned int pdc20621_host
 		else {
 			VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
 				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-			pdc_dma_complete(ap, qc, 0);
+			/* get drive status; clear intr; complete txn */
+			ata_qc_complete(qc, ata_wait_idle(ap));
 			pdc20621_pop_hdma(qc);
 		}
 		handled = 1;
@@ -700,6 +766,16 @@ static inline unsigned int pdc20621_host
 	return handled;
 }
 
+static void pdc20621_irq_clear(struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	mmio += PDC_CHIP0_OFS;
+
+	readl(mmio + PDC_20621_SEQMASK);
+}
+
 static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
@@ -764,16 +840,6 @@ static irqreturn_t pdc20621_interrupt (i
 	return IRQ_RETVAL(handled);
 }
 
-static inline void pdc_dma_complete (struct ata_port *ap,
-                                     struct ata_queued_cmd *qc,
-				     int have_err)
-{
-	u8 err_bit = have_err ? ATA_ERR : 0;
-
-	/* get drive status; clear intr; complete txn */
-	ata_qc_complete(qc, ata_wait_idle(ap) | err_bit);
-}
-
 static void pdc_eng_timeout(struct ata_port *ap)
 {
 	u8 drv_stat;
@@ -798,17 +864,9 @@ static void pdc_eng_timeout(struct ata_p
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
-		printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
-		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
-		break;
-
 	case ATA_PROT_NODATA:
-		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-
-		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
-		       ap->id, qc->tf.command, drv_stat);
-
-		ata_qc_complete(qc, drv_stat);
+		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
 		break;
 
 	default:
@@ -827,15 +885,17 @@ out:
 
 static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	if (tf->protocol != ATA_PROT_DMA)
-		ata_tf_load_mmio(ap, tf);
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_tf_load_mmio(ap, tf);
 }
 
 
 static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	if (tf->protocol != ATA_PROT_DMA)
-		ata_exec_command_mmio(ap, tf);
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_exec_command_mmio(ap, tf);
 }
 
 
@@ -1366,6 +1426,7 @@ static int pdc_sata_init_one (struct pci
 	probe_ent->sht		= pdc_port_info[board_idx].sht;
 	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
 	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;
 	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
 	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
 
@@ -1376,21 +1437,11 @@ static int pdc_sata_init_one (struct pci
 	probe_ent->private_data = hpriv;
 	base += PDC_CHIP0_OFS;
 
+	probe_ent->n_ports = 4;
 	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
 	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
-
-	/* notice 4-port boards */
-	switch (board_idx) {
-	case board_20621:
-       		probe_ent->n_ports = 4;
-
-		pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
-		pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
-		break;
-	default:
-		BUG();
-		break;
-	}
+	pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+	pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
 
 	pci_set_master(pdev);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_via.c linux-2.4.28-pre1/drivers/scsi/sata_via.c
--- linux-2.4.27/drivers/scsi/sata_via.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_via.c	2004-08-15 19:51:45.000000000 +0000
@@ -109,10 +109,13 @@ static struct ata_port_operations svia_s
 
 	.bmdma_setup            = ata_bmdma_setup_pio,
 	.bmdma_start            = ata_bmdma_start_pio,
-	.fill_sg		= ata_fill_sg,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
 	.eng_timeout		= ata_eng_timeout,
 
 	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
 
 	.scr_read		= svia_scr_read,
 	.scr_write		= svia_scr_write,
@@ -209,6 +212,7 @@ static int svia_init_one (struct pci_dev
 	probe_ent->irq = pdev->irq;
 	probe_ent->irq_flags = SA_SHIRQ;
 	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x07;
 	probe_ent->udma_mask = 0x7f;
 
 	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/sata_vsc.c linux-2.4.28-pre1/drivers/scsi/sata_vsc.c
--- linux-2.4.27/drivers/scsi/sata_vsc.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/sata_vsc.c	2004-08-15 19:50:25.000000000 +0000
@@ -216,9 +216,11 @@ static struct ata_port_operations vsc_sa
 	.phy_reset		= sata_phy_reset,
 	.bmdma_setup            = ata_bmdma_setup_mmio,
 	.bmdma_start            = ata_bmdma_start_mmio,
-	.fill_sg		= ata_fill_sg,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
 	.irq_handler		= vsc_sata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
 	.scr_read		= vsc_sata_scr_read,
 	.scr_write		= vsc_sata_scr_write,
 	.port_start		= ata_port_start,
@@ -316,6 +318,7 @@ static int __devinit vsc_sata_init_one (
 	 * if we don't fill these
 	 */
 	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x07;
 	probe_ent->udma_mask = 0x7f;
 
 	/* We have 4 ports per PCI function */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/scsi/scsi_scan.c linux-2.4.28-pre1/drivers/scsi/scsi_scan.c
--- linux-2.4.27/drivers/scsi/scsi_scan.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/scsi/scsi_scan.c	2004-08-15 19:51:11.000000000 +0000
@@ -157,6 +157,7 @@ static struct dev_info device_list[] =
  	{"TOSHIBA","CDROM","*", BLIST_ISROM},
  	{"TOSHIBA","CD-ROM","*", BLIST_ISROM},
 	{"MegaRAID", "LD", "*", BLIST_FORCELUN},
+	{"3PARdata", "VV", "*", BLIST_SPARSELUN | BLIST_LARGELUN},    // 3PARdata InServ Virtual Volume
 	{"DGC",  "RAID",      "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (tgt @ LUN 0)
 	{"DGC",  "DISK",      "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (no tgt @ LUN 0) 
 	{"DELL", "PV660F",   "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -208,6 +209,7 @@ static struct dev_info device_list[] =
 	{"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, 
 	{"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"Xyratex", "4200", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 
 	/*
 	 * Must be at end of list...
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/sound/ac97_codec.c linux-2.4.28-pre1/drivers/sound/ac97_codec.c
--- linux-2.4.27/drivers/sound/ac97_codec.c	2003-11-28 18:26:20.000000000 +0000
+++ linux-2.4.28-pre1/drivers/sound/ac97_codec.c	2004-08-15 19:48:07.000000000 +0000
@@ -30,6 +30,9 @@
  **************************************************************************
  *
  * History
+ * Feb 25, 2004 Liam Girdwood
+ *  Added support for codecs that require a warm reset to power up.
+ *  Support for WM9713
  * May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
  *	Removed non existant WM9700
  *	Added support for WM9705, WM9708, WM9709, WM9710, WM9711
@@ -71,6 +74,7 @@ static int wolfson_init03(struct ac97_co
 static int wolfson_init04(struct ac97_codec * codec);
 static int wolfson_init05(struct ac97_codec * codec);
 static int wolfson_init11(struct ac97_codec * codec);
+static int wolfson_init13(struct ac97_codec * codec);
 static int tritech_init(struct ac97_codec * codec);
 static int tritech_maestro_init(struct ac97_codec * codec);
 static int sigmatel_9708_init(struct ac97_codec *codec);
@@ -107,6 +111,7 @@ static struct ac97_ops wolfson_ops03 = {
 static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL };
 static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL };
 static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL };
+static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL };
 static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL };
 static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL };
 static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL };
@@ -168,6 +173,7 @@ static const struct {
 	{0x574D4C05, "Wolfson WM9705/WM9710",   &wolfson_ops05},
 	{0x574D4C09, "Wolfson WM9709",		&null_ops},
 	{0x574D4C12, "Wolfson WM9711/9712",	&wolfson_ops11},
+	{0x574D4C13, "Wolfson WM9713",	&wolfson_ops13, AC97_DEFAULT_POWER_OFF},
 	{0x83847600, "SigmaTel STAC????",	&null_ops},
 	{0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops},
 	{0x83847605, "SigmaTel STAC9704",	&null_ops},
@@ -793,6 +799,9 @@ EXPORT_SYMBOL(ac97_release_codec);
  *	Currently codec_wait is used to wait for AC97 codec
  *	reset to complete. 
  *
+ *  Some codecs will power down when a register reset is
+ *  performed. We now check for such codecs.
+ *
  *	Returns 1 (true) on success, or 0 (false) on failure.
  */
  
@@ -805,35 +814,18 @@ int ac97_probe_codec(struct ac97_codec *
 	u16 f;
 	struct list_head *l;
 	struct ac97_driver *d;
-	
-	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
-	 * be read zero.
-	 *
-	 * FIXME: is the following comment outdated?  -jgarzik 
-	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
-	 */
-	codec->codec_write(codec, AC97_RESET, 0L);
 
-	/* also according to spec, we wait for codec-ready state */	
+	/* wait for codec-ready state */	
 	if (codec->codec_wait)
 		codec->codec_wait(codec);
 	else
 		udelay(10);
-
-	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
-		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
-		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
-		       : (codec->id&1 ? "Secondary":  "Primary"));
-		return 0;
-	}
-
-	/* probe for Modem Codec */
-	codec->modem = ac97_check_modem(codec);
-	codec->name = NULL;
-	codec->codec_ops = &default_ops;
-
+	
+	/* will the codec power down if register reset ? */
 	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+	codec->name = NULL;
+	codec->codec_ops = &null_ops;
 	for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) {
 		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
 			codec->type = ac97_codec_ids[i].id;
@@ -843,11 +835,35 @@ int ac97_probe_codec(struct ac97_codec *
 			break;
 		}
 	}
-
 	codec->model = (id1 << 16) | id2;
+	if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) {
+		/* reset codec and wait for the ready bit before we continue */
+		codec->codec_write(codec, AC97_RESET, 0L);
+		if (codec->codec_wait)
+			codec->codec_wait(codec);
+		else
+			udelay(10);
+	}
 	
+	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
+	 * be read zero.
+	 *
+	 * FIXME: is the following comment outdated?  -jgarzik 
+	 * Probing of AC97 in this way is not reliable, it is not even SAFE !!
+	 */
+	if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
+		printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
+		       (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") 
+		       : (codec->id&1 ? "Secondary":  "Primary"));
+		return 0;
+	}
+	
+	/* probe for Modem Codec */
+	codec->modem = ac97_check_modem(codec);
+	
+	/* enable SPDIF */
 	f = codec->codec_read(codec, AC97_EXTENDED_STATUS);
-	if(f & 4)
+	if((codec->codec_ops == &null_ops) && (f & 4))
 		codec->codec_ops = &default_digital_ops;
 	
 	/* A device which thinks its a modem but isnt */
@@ -916,11 +932,6 @@ static int ac97_init_mixer(struct ac97_c
 	codec->recmask_io = ac97_recmask_io;
 	codec->mixer_ioctl = ac97_mixer_ioctl;
 
-	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
-	if (codec->codec_ops->init != NULL) {
-		codec->codec_ops->init(codec);
-	}
-
 	/* initialize mixer channel volumes */
 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
 		struct mixer_defaults *md = &mixer_defaults[i];
@@ -930,6 +941,11 @@ static int ac97_init_mixer(struct ac97_c
 			continue;
 		ac97_set_mixer(codec, md->mixer, md->value);
 	}
+	
+	/* codec specific initialization for 4-6 channel output or secondary codec stuff */
+	if (codec->codec_ops->init != NULL) {
+		codec->codec_ops->init(codec);
+	}
 
 	/*
 	 *	Volume is MUTE only on this device. We have to initialise
@@ -1085,6 +1101,19 @@ static int wolfson_init11(struct ac97_co
 	return 0;
 }
 
+/* WM9713 */
+static int wolfson_init13(struct ac97_codec * codec)
+{
+	codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0);	
+	codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000);
+	codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00);
+	codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810);
+	codec->codec_write(codec, AC97_PHONE_VOL, 0x0808);
+	codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808);
+
+	return 0;
+}
+
 static int tritech_init(struct ac97_codec * codec)
 {
 	codec->codec_write(codec, 0x26, 0x0300);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/gadget/net2280.c linux-2.4.28-pre1/drivers/usb/gadget/net2280.c
--- linux-2.4.27/drivers/usb/gadget/net2280.c	2004-04-14 13:05:32.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/gadget/net2280.c	2004-08-15 19:48:53.000000000 +0000
@@ -537,7 +537,10 @@ write_fifo (struct net2280_ep *ep, struc
 	}
 
 	/* write just one packet at a time */
-	count = min (ep->ep.maxpacket, total);
+	count = ep->ep.maxpacket;
+	if (count > total)	/* min() cannot be used on a bitfield */
+		count = total;
+
 	VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
 			ep->ep.name, count,
 			(count != ep->ep.maxpacket) ? " (short)" : "",
@@ -2191,7 +2194,8 @@ static void handle_ep_small (struct net2
 		unsigned	len;
 
 		len = req->req.length - req->req.actual;
-		len = min (ep->ep.maxpacket, len);
+		if (len > ep->ep.maxpacket)
+			len = ep->ep.maxpacket;
 		req->req.actual += len;
 
 		/* if we wrote it all, we're usually done */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/hid-core.c linux-2.4.28-pre1/drivers/usb/hid-core.c
--- linux-2.4.27/drivers/usb/hid-core.c	2004-04-14 13:05:32.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/hid-core.c	2004-08-15 19:50:25.000000000 +0000
@@ -620,14 +620,16 @@ static __u8 *fetch_item(__u8 *start, __u
 
 				case 2:
 					if ((end - start) >= 2) {
-						item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
+						item->data.u16 = le16_to_cpu(get_unaligned((__u16*)start));
+						start = (__u8 *)((__u16 *)start + 1);
 						return start;
 					}
 
 				case 3:
 					item->size++;
 					if ((end - start) >= 4) {
-						item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
+						item->data.u32 = le32_to_cpu(get_unaligned((__u32*)start));
+						start = (__u8 *)((__u32 *)start + 1);
 						return start;
 					}
 			}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/host/ehci-hcd.c linux-2.4.28-pre1/drivers/usb/host/ehci-hcd.c
--- linux-2.4.27/drivers/usb/host/ehci-hcd.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/host/ehci-hcd.c	2004-08-15 19:49:57.000000000 +0000
@@ -303,7 +303,8 @@ static int bios_handoff (struct ehci_hcd
 		if (cap & (1 << 16)) {
 			ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
 				where, cap);
-			return 1;
+			pci_write_config_dword (ehci->hcd.pdev, where, 0);
+			return 0;
 		} 
 		ehci_dbg (ehci, "BIOS handoff succeeded\n");
 	}
@@ -547,7 +548,8 @@ static void ehci_stop (struct usb_hcd *h
 
 	/* root hub is shut down separately (first, when possible) */
 	spin_lock_irq (&ehci->lock);
-	ehci_work (ehci, NULL);
+	if (ehci->async)
+		ehci_work (ehci, NULL);
 	spin_unlock_irq (&ehci->lock);
 	ehci_mem_cleanup (ehci);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/storage/scsiglue.c linux-2.4.28-pre1/drivers/usb/storage/scsiglue.c
--- linux-2.4.27/drivers/usb/storage/scsiglue.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/storage/scsiglue.c	2004-08-15 19:50:01.000000000 +0000
@@ -127,7 +127,7 @@ static int release(struct Scsi_Host *psh
 	wait_for_completion(&(us->notify));
 
 	/* remove the pointer to the data structure we were using */
-	(struct us_data*)psh->hostdata[0] = NULL;
+	psh->hostdata[0] = (unsigned long)NULL;
 
 	/* we always have a successful release */
 	return 0;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/storage/sddr09.c linux-2.4.28-pre1/drivers/usb/storage/sddr09.c
--- linux-2.4.27/drivers/usb/storage/sddr09.c	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/storage/sddr09.c	2004-08-15 19:51:15.000000000 +0000
@@ -444,6 +444,7 @@ sddr09_test_unit_ready(struct us_data *u
  * byte 0: opcode: 03
  * byte 4: data length
  */
+#if 0
 static int
 sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
 	unsigned char command[12] = {
@@ -465,7 +466,7 @@ sddr09_request_sense(struct us_data *us,
 
 	return result;
 }
-
+#endif
 /*
  * Read Command: 12 bytes.
  * byte 0: opcode: E8
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/usb/storage/usb.c linux-2.4.28-pre1/drivers/usb/storage/usb.c
--- linux-2.4.27/drivers/usb/storage/usb.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/usb/storage/usb.c	2004-08-15 19:48:44.000000000 +0000
@@ -994,7 +994,7 @@ static void * storage_probe(struct usb_d
 		 * the host controller thread in us_detect.  But how else are
 		 * we to do it?
 		 */
-		(struct us_data *)ss->htmplt.proc_dir = ss; 
+		ss->htmplt.proc_dir = (void *)ss; 
 
 		/* Just before we start our control thread, initialize
 		 * the device if it needs initialization */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/video/fbcon.c linux-2.4.28-pre1/drivers/video/fbcon.c
--- linux-2.4.27/drivers/video/fbcon.c	2003-08-25 11:44:42.000000000 +0000
+++ linux-2.4.28-pre1/drivers/video/fbcon.c	2004-08-15 19:50:52.000000000 +0000
@@ -1877,7 +1877,10 @@ static inline int fbcon_set_font(int uni
        font length must be multiple of 256, at least. And 256 is multiple
        of 4 */
     k = 0;
-    while (p > new_data) k += *--(u32 *)p;
+    while (p > new_data) {
+	    p = (u8 *)((u32 *)p - 1);
+	    k += *(u32 *) p;
+    }
     FNTSUM(new_data) = k;
     /* Check if the same font is on some other console already */
     for (i = 0; i < MAX_NR_CONSOLES; i++) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/video/matrox/matroxfb_g450.c linux-2.4.28-pre1/drivers/video/matrox/matroxfb_g450.c
--- linux-2.4.27/drivers/video/matrox/matroxfb_g450.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.28-pre1/drivers/video/matrox/matroxfb_g450.c	2004-08-15 19:51:17.000000000 +0000
@@ -558,7 +558,7 @@ static int matroxfb_g450_program(void* m
 }
 
 static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
-	MINFO_FROM(md);
+//	MINFO_FROM(md);
 	
 	switch (arg) {
 		case MATROXFB_OUTPUT_MODE_PAL:
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/video/riva/fbdev.c linux-2.4.28-pre1/drivers/video/riva/fbdev.c
--- linux-2.4.27/drivers/video/riva/fbdev.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/drivers/video/riva/fbdev.c	2004-08-15 19:50:56.000000000 +0000
@@ -2221,7 +2221,6 @@ err_out_free_base1:
 	release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size);
 err_out_free_base0:
 	release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size);
-err_out_kfree:
 	kfree(rinfo);
 err_out:
 	return -ENODEV;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/drivers/video/sstfb.c linux-2.4.28-pre1/drivers/video/sstfb.c
--- linux-2.4.27/drivers/video/sstfb.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/drivers/video/sstfb.c	2004-08-15 19:50:36.000000000 +0000
@@ -968,7 +968,6 @@ static int sstfb_ioctl(struct inode *ino
                        struct fb_info *info)
 {
 #define sst_info	((struct sstfb_info *) info)
-	int i;
 	u_long p;
 	u32 tmp, val;
 	u32 fbiinit0;
@@ -980,12 +979,14 @@ static int sstfb_ioctl(struct inode *ino
 		
 #if (SST_DEBUG_VAR >0)
 	/* tmp ioctl : dumps fb_display[0-5] */
-	case _IO('F', 0xdb):		/* 0x46db */
+	case _IO('F', 0xdb):		/* 0x46db */ {
+		int i;
 		f_dprintk("dumping fb_display[0-5].var\n");
 		for (i = 0 ; i< 6 ; i++) {
 			print_var(&fb_display[i].var, "var(%d)", i);
 		}
 		return 0;
+	}
 #endif /* (SST_DEBUG_VAR >0) */
 
 	/* fills the lfb up to given count of pixels */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/befs/btree.c linux-2.4.28-pre1/fs/befs/btree.c
--- linux-2.4.27/fs/befs/btree.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.28-pre1/fs/befs/btree.c	2004-08-15 19:51:57.000000000 +0000
@@ -85,7 +85,7 @@ typedef struct {
 } befs_btree_node;
 
 /* local constants */
-const static befs_off_t befs_bt_inval = 0xffffffffffffffff;
+const static befs_off_t befs_bt_inval = 0xffffffffffffffffULL;
 
 /* local functions */
 static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/befs/linuxvfs.c linux-2.4.28-pre1/fs/befs/linuxvfs.c
--- linux-2.4.27/fs/befs/linuxvfs.c	2003-06-13 14:51:37.000000000 +0000
+++ linux-2.4.28-pre1/fs/befs/linuxvfs.c	2004-08-15 19:52:10.000000000 +0000
@@ -55,13 +55,6 @@ static int befs_remount(struct super_blo
 static int befs_statfs(struct super_block *, struct statfs *);
 static int parse_options(char *, befs_mount_options *);
 
-static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-static ssize_t befs_getxattr(struct dentry *dentry, const char *name,
-			     void *buffer, size_t size);
-static int befs_setxattr(struct dentry *dentry, const char *name, void *value,
-			 size_t size, int flags);
-static int befs_removexattr(struct dentry *dentry, const char *name);
-
 /* slab cache for befs_inode_info objects */
 static kmem_cache_t *befs_inode_cachep;
 
@@ -584,11 +577,11 @@ befs_utf2nls(struct super_block *sb, con
 		}
 	}
 	result[o] = '\0';
+	*out_len = o;
 
 	befs_debug(sb, "<--- utf2nls()");
 
 	return o;
-	*out_len = o;
 
       conv_err:
 	befs_error(sb, "Name using charecter set %s contains a charecter that "
@@ -675,35 +668,6 @@ befs_nls2utf(struct super_block *sb, con
 	return -EILSEQ;
 }
 
-/****Xattr****/
-
-static ssize_t
-befs_listxattr(struct dentry *dentry, char *buffer, size_t size)
-{
-	printk(KERN_ERR "befs_listxattr called\n");
-	return 0;
-}
-
-static ssize_t
-befs_getxattr(struct dentry *dentry, const char *name,
-	      void *buffer, size_t size)
-{
-	return 0;
-}
-
-static int
-befs_setxattr(struct dentry *dentry, const char *name,
-	      void *value, size_t size, int flags)
-{
-	return 0;
-}
-
-static int
-befs_removexattr(struct dentry *dentry, const char *name)
-{
-	return 0;
-}
-
 /****Superblock****/
 
 static int
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/buffer.c linux-2.4.28-pre1/fs/buffer.c
--- linux-2.4.27/fs/buffer.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/fs/buffer.c	2004-08-15 19:50:23.000000000 +0000
@@ -160,7 +160,7 @@ static inline void write_buffer(struct b
 	ll_rw_block(WRITE, 1, &bh);
 }
 
-void unlock_buffer(struct buffer_head *bh)
+void fastcall unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
 	clear_bit(BH_Launder, &bh->b_state);
@@ -649,7 +649,7 @@ struct buffer_head * get_hash_table(kdev
 	return bh;
 }
 
-void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
+void fastcall buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
 	if (buffer_attached(bh))
@@ -1092,7 +1092,7 @@ void balance_dirty(void)
 }
 EXPORT_SYMBOL(balance_dirty);
 
-inline void __mark_dirty(struct buffer_head *bh)
+inline void fastcall __mark_dirty(struct buffer_head *bh)
 {
 	bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer;
 	refile_buffer(bh);
@@ -1100,13 +1100,13 @@ inline void __mark_dirty(struct buffer_h
 
 /* atomic version, the user must call balance_dirty() by hand
    as soon as it become possible to block */
-void __mark_buffer_dirty(struct buffer_head *bh)
+void fastcall __mark_buffer_dirty(struct buffer_head *bh)
 {
 	if (!atomic_set_buffer_dirty(bh))
 		__mark_dirty(bh);
 }
 
-void mark_buffer_dirty(struct buffer_head *bh)
+void fastcall mark_buffer_dirty(struct buffer_head *bh)
 {
 	if (!atomic_set_buffer_dirty(bh)) {
 		if (block_dump)
@@ -1260,8 +1260,9 @@ struct buffer_head * get_unused_buffer_h
 
 	/*
 	 * If we need an async buffer, use the reserved buffer heads.
+	 * Non-PF_MEMALLOC tasks can just loop in create_buffers().
 	 */
-	if (async) {
+	if (async && (current->flags & PF_MEMALLOC)) {
 		spin_lock(&unused_list_lock);
 		if (unused_list) {
 			bh = unused_list;
@@ -2730,7 +2731,7 @@ static int sync_page_buffers(struct buff
  *       obtain a reference to a buffer head within a page.  So we must
  *	 lock out all of these paths to cleanly toss the page.
  */
-int try_to_free_buffers(struct page * page, unsigned int gfp_mask)
+int fastcall try_to_free_buffers(struct page * page, unsigned int gfp_mask)
 {
 	struct buffer_head * tmp, * bh = page->buffers;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/file_table.c linux-2.4.28-pre1/fs/file_table.c
--- linux-2.4.27/fs/file_table.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/fs/file_table.c	2004-08-15 19:47:42.000000000 +0000
@@ -97,7 +97,7 @@ int init_private_file(struct file *filp,
 		return 0;
 }
 
-void fput(struct file * file)
+void fastcall fput(struct file * file)
 {
 	struct dentry * dentry = file->f_dentry;
 	struct vfsmount * mnt = file->f_vfsmnt;
@@ -126,7 +126,7 @@ void fput(struct file * file)
 	}
 }
 
-struct file * fget(unsigned int fd)
+struct file fastcall *fget(unsigned int fd)
 {
 	struct file * file;
 	struct files_struct *files = current->files;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/hfs/file_hdr.c linux-2.4.28-pre1/fs/hfs/file_hdr.c
--- linux-2.4.27/fs/hfs/file_hdr.c	2004-08-07 23:26:05.000000000 +0000
+++ linux-2.4.28-pre1/fs/hfs/file_hdr.c	2004-08-15 19:50:43.000000000 +0000
@@ -241,7 +241,9 @@ static struct hfs_hdr_layout *dup_layout
 	if (HFS_NEW(new)) {
 		memcpy(new, old, sizeof(*new));
 		for (lcv = 0; lcv < new->entries; ++lcv) {
-			(char *)(new->order[lcv]) += (char *)new - (char *)old;
+			new->order[lcv] = (struct hfs_hdr_descr *)
+					  ((char *)(new->order[lcv]) +
+					   ((char *)new - (char *)old));
 		}
 	}
 	return new;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/jbd/journal.c linux-2.4.28-pre1/fs/jbd/journal.c
--- linux-2.4.27/fs/jbd/journal.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.28-pre1/fs/jbd/journal.c	2004-08-15 19:48:16.000000000 +0000
@@ -1581,7 +1581,7 @@ void journal_ack_err (journal_t *journal
  * journal_datalist_lock spinlock: most callers will need those anyway
  * in order to probe the buffer's journaling state safely.
  */
-void __jbd_unexpected_dirty_buffer(char *function, int line, 
+void __jbd_unexpected_dirty_buffer(const char *function, int line, 
 				 struct journal_head *jh)
 {
 	struct buffer_head *bh = jh2bh(jh);
@@ -1646,7 +1646,7 @@ void shrink_journal_memory(void)
  * Simple support for retying memory allocations.  Introduced to help to
  * debug different VM deadlock avoidance strategies. 
  */
-void * __jbd_kmalloc (char *where, size_t size, int flags, int retry)
+void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry)
 {
 	void *p;
 	static unsigned long last_warning;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/namei.c linux-2.4.28-pre1/fs/namei.c
--- linux-2.4.27/fs/namei.c	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/fs/namei.c	2004-08-15 19:49:17.000000000 +0000
@@ -447,7 +447,7 @@ static inline void follow_dotdot(struct 
  *
  * We expect 'base' to be positive and a directory.
  */
-int link_path_walk(const char * name, struct nameidata *nd)
+int fastcall link_path_walk(const char * name, struct nameidata *nd)
 {
 	struct dentry *dentry;
 	struct inode *inode;
@@ -653,7 +653,7 @@ return_err:
 	return err;
 }
 
-int path_walk(const char * name, struct nameidata *nd)
+int fastcall path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
 	return link_path_walk(name, nd);
@@ -741,7 +741,7 @@ walk_init_root(const char *name, struct 
 }
 
 /* SMP-safe */
-int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+int fastcall path_lookup(const char *path, unsigned flags, struct nameidata *nd)
 {
 	int error = 0;
 	if (path_init(path, flags, nd))
@@ -751,7 +751,7 @@ int path_lookup(const char *path, unsign
 
 
 /* SMP-safe */
-int path_init(const char *name, unsigned int flags, struct nameidata *nd)
+int fastcall path_init(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
@@ -847,7 +847,7 @@ access:
  * that namei follows links, while lnamei does not.
  * SMP-safe
  */
-int __user_walk(const char *name, unsigned flags, struct nameidata *nd)
+int fastcall __user_walk(const char *name, unsigned flags, struct nameidata *nd)
 {
 	char *tmp;
 	int err;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/ntfs/fs.c linux-2.4.28-pre1/fs/ntfs/fs.c
--- linux-2.4.27/fs/ntfs/fs.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/fs/ntfs/fs.c	2004-08-15 19:48:26.000000000 +0000
@@ -1045,7 +1045,7 @@ struct super_block *ntfs_read_super(stru
 	}
 	ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%lx\n", vol->mft_lcn);
 	brelse(bh);
-	NTFS_SB(vol) = sb;
+	vol->sb = sb;
 	if (vol->cluster_size > PAGE_SIZE) {
 		ntfs_error("Partition cluster size is not supported yet (it "
 			   "is > max kernel blocksize).\n");
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/ntfs/util.c linux-2.4.28-pre1/fs/ntfs/util.c
--- linux-2.4.27/fs/ntfs/util.c	2001-08-13 23:40:19.000000000 +0000
+++ linux-2.4.28-pre1/fs/ntfs/util.c	2004-08-15 19:47:18.000000000 +0000
@@ -165,13 +165,13 @@ int ntfs_decodeuni(ntfs_volume *vol, cha
 void ntfs_put(ntfs_io *dest, void *src, ntfs_size_t n)
 {
 	ntfs_memcpy(dest->param, src, n);
-	((char*)dest->param) += n;
+	dest->param = (char*)dest->param + n;
 }
 
 void ntfs_get(void* dest, ntfs_io *src, ntfs_size_t n)
 {
 	ntfs_memcpy(dest, src->param, n);
-	((char*)src->param) += n;
+	src->param = (char*)src->param + n;
 }
 
 void *ntfs_calloc(int size)
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/partitions/ldm.h linux-2.4.28-pre1/fs/partitions/ldm.h
--- linux-2.4.27/fs/partitions/ldm.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/fs/partitions/ldm.h	2004-08-15 19:49:03.000000000 +0000
@@ -38,8 +38,8 @@ struct parsed_partitions;
 /* Magic numbers in CPU format. */
 #define MAGIC_VMDB	0x564D4442		/* VMDB */
 #define MAGIC_VBLK	0x56424C4B		/* VBLK */
-#define MAGIC_PRIVHEAD	0x5052495648454144	/* PRIVHEAD */
-#define MAGIC_TOCBLOCK	0x544F43424C4F434B	/* TOCBLOCK */
+#define MAGIC_PRIVHEAD	0x5052495648454144ULL	/* PRIVHEAD */
+#define MAGIC_TOCBLOCK	0x544F43424C4F434BULL	/* TOCBLOCK */
 
 /* The defined vblk types. */
 #define VBLK_VOL5		0x51		/* Volume,     version 5 */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/fs/readdir.c linux-2.4.28-pre1/fs/readdir.c
--- linux-2.4.27/fs/readdir.c	2004-02-18 13:36:31.000000000 +0000
+++ linux-2.4.28-pre1/fs/readdir.c	2004-08-15 19:49:55.000000000 +0000
@@ -264,7 +264,7 @@ static int filldir(void * __buf, const c
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -347,7 +347,7 @@ static int filldir64(void * __buf, const
 	copy_to_user(dirent, &d, NAME_OFFSET(&d));
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-i386/rwsem.h linux-2.4.28-pre1/include/asm-i386/rwsem.h
--- linux-2.4.27/include/asm-i386/rwsem.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-i386/rwsem.h	2004-08-15 19:49:40.000000000 +0000
@@ -113,8 +113,8 @@ LOCK_PREFIX	"  incl      (%%eax)\n\t" /*
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending down_read\n\t"
-		: "+m"(sem->count)
-		: "a"(sem)
+		: "=m"(sem->count)
+		: "a"(sem), "m"(sem->count)
 		: "memory", "cc");
 }
 
@@ -151,8 +151,8 @@ static inline void __down_write(struct r
 	tmp = RWSEM_ACTIVE_WRITE_BIAS;
 	__asm__ __volatile__(
 		"# beginning down_write\n\t"
-LOCK_PREFIX	"  xadd      %0,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
-		"  testl     %0,%0\n\t" /* was the count 0 before? */
+LOCK_PREFIX	"  xadd      %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the old value */
+		"  testl     %%edx,%%edx\n\t" /* was the count 0 before? */
 		"  jnz       2f\n\t" /* jump if we weren't granted the lock */
 		"1:\n\t"
 		LOCK_SECTION_START("")
@@ -163,8 +163,8 @@ LOCK_PREFIX	"  xadd      %0,(%%eax)\n\t"
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending down_write"
-		: "+d"(tmp), "+m"(sem->count)
-		: "a"(sem)
+		: "=m"(sem->count), "=d"(tmp)
+		: "a"(sem), "1"(tmp), "m"(sem->count)
 		: "memory", "cc");
 }
 
@@ -202,8 +202,8 @@ LOCK_PREFIX	"  xadd      %%edx,(%%eax)\n
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending __up_read\n"
-		: "+m"(sem->count), "+d"(tmp)
-		: "a"(sem)
+		: "=m"(sem->count), "=d"(tmp)
+		: "a"(sem), "1"(tmp), "m"(sem->count)
 		: "memory", "cc");
 }
 
@@ -228,8 +228,8 @@ LOCK_PREFIX	"  xaddl     %%edx,(%%eax)\n
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending __up_write\n"
-		: "+m"(sem->count)
-		: "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS)
+		: "=m"(sem->count)
+		: "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count)
 		: "memory", "cc", "edx");
 }
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-i386/smp.h linux-2.4.28-pre1/include/asm-i386/smp.h
--- linux-2.4.27/include/asm-i386/smp.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-i386/smp.h	2004-08-15 19:47:39.000000000 +0000
@@ -39,7 +39,7 @@ extern int cpu_sibling_map[];
 
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_send_reschedule(int cpu);
+extern void fastcall smp_send_reschedule(int cpu);
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-i386/unistd.h linux-2.4.28-pre1/include/asm-i386/unistd.h
--- linux-2.4.27/include/asm-i386/unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-i386/unistd.h	2004-08-15 19:50:40.000000000 +0000
@@ -372,7 +372,7 @@ static inline _syscall1(int,dup,int,fd)
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
 static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
 static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
+static inline _syscall1(void,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 static inline _syscall1(int,delete_module,const char *,name)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-ppc/unistd.h linux-2.4.28-pre1/include/asm-ppc/unistd.h
--- linux-2.4.27/include/asm-ppc/unistd.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-ppc/unistd.h	2004-08-15 19:48:26.000000000 +0000
@@ -382,7 +382,7 @@ static inline _syscall1(int,dup,int,fd)
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
 static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
 static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
+static inline _syscall1(void,_exit,int,exitcode)
 static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 static inline _syscall1(int,delete_module,const char *,name)
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-sparc64/asi.h linux-2.4.28-pre1/include/asm-sparc64/asi.h
--- linux-2.4.27/include/asm-sparc64/asi.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-sparc64/asi.h	2004-08-15 19:48:37.000000000 +0000
@@ -8,125 +8,138 @@
  */
 
 /* V9 Architecture mandary ASIs. */
-#define ASI_N			0x04 /* Nucleus					*/
-#define ASI_NL			0x0c /* Nucleus, little endian			*/
-#define ASI_AIUP		0x10 /* Primary, user				*/
-#define ASI_AIUS		0x11 /* Secondary, user				*/
-#define ASI_AIUPL		0x18 /* Primary, user, little endian		*/
-#define ASI_AIUSL		0x19 /* Secondary, user, little endian		*/
-#define ASI_P			0x80 /* Primary, implicit			*/
-#define ASI_S			0x81 /* Secondary, implicit			*/
-#define ASI_PNF			0x82 /* Primary, no fault			*/
-#define ASI_SNF			0x83 /* Secondary, no fault			*/
-#define ASI_PL			0x88 /* Primary, implicit, little endian	*/
-#define ASI_SL			0x89 /* Secondary, implicit, little endian	*/
-#define ASI_PNFL		0x8a /* Primary, no fault, little endian	*/
-#define ASI_SNFL		0x8b /* Secondary, no fault, little endian	*/
+#define ASI_N			0x04 /* Nucleus				*/
+#define ASI_NL			0x0c /* Nucleus, little endian		*/
+#define ASI_AIUP		0x10 /* Primary, user			*/
+#define ASI_AIUS		0x11 /* Secondary, user			*/
+#define ASI_AIUPL		0x18 /* Primary, user, little endian	*/
+#define ASI_AIUSL		0x19 /* Secondary, user, little endian	*/
+#define ASI_P			0x80 /* Primary, implicit		*/
+#define ASI_S			0x81 /* Secondary, implicit		*/
+#define ASI_PNF			0x82 /* Primary, no fault		*/
+#define ASI_SNF			0x83 /* Secondary, no fault		*/
+#define ASI_PL			0x88 /* Primary, implicit, l-endian	*/
+#define ASI_SL			0x89 /* Secondary, implicit, l-endian	*/
+#define ASI_PNFL		0x8a /* Primary, no fault, l-endian	*/
+#define ASI_SNFL		0x8b /* Secondary, no fault, l-endian	*/
 
 /* SpitFire and later extended ASIs.  The "(III)" marker designates
- * UltraSparc-III specific ASIs.
+ * UltraSparc-III and later specific ASIs.  The "(CMT)" marker designates
+ * Chip Multi Threading specific ASIs.
  */
-#define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable			*/
-#define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-bit				*/
-#define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian	*/
-#define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-bit, little endian		*/
-#define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load			*/
-#define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, little endian 	*/
-#define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data status RAM diag	*/
-#define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag		*/
-#define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag		*/
-#define ASI_PCACHE_SNOOP_TAG	0x33 /* (III) PCache snoop tag RAM diag		*/
-#define ASI_QUAD_LDD_PHYS	0x34 /* (III+) PADDR, qword load		*/
-#define ASI_WCACHE_VALID_BITS	0x38 /* (III) WCache Valid Bits diag		*/
-#define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag		*/
-#define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag		*/
-#define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag		*/
-#define ASI_QUAD_LDD_PHYS_L	0x3c /* (III+) PADDR, qword load, little endian	*/
-#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init			*/
-#define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
-#define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
-#define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag		*/
-#define ASI_LSU_CONTROL		0x45 /* Load-store control unit			*/
-#define ASI_DCU_CONTROL_REG	0x45 /* (III) DCache Unit Control Register	*/
-#define ASI_DCACHE_DATA		0x46 /* Data cache data-ram diag access		*/
-#define ASI_DCACHE_TAG		0x47 /* Data cache tag/valid ram diag access	*/
-#define ASI_INTR_DISPATCH_STAT	0x48 /* IRQ vector dispatch status		*/
-#define ASI_INTR_RECEIVE	0x49 /* IRQ vector receive status		*/
-#define ASI_UPA_CONFIG		0x4a /* UPA config space			*/
-#define ASI_JBUS_CONFIG		0x4a /* (IIIi) JBUS Config Register		*/
-#define ASI_SAFARI_CONFIG	0x4a /* (III) Safari Config Register		*/
-#define ASI_SAFARI_ADDRESS	0x4a /* (III) Safari Address Register		*/
-#define ASI_ESTATE_ERROR_EN	0x4b /* E-cache error enable space		*/
-#define ASI_AFSR		0x4c /* Async fault status register		*/
-#define ASI_AFAR		0x4d /* Async fault address register		*/
-#define ASI_EC_TAG_DATA		0x4e /* E-cache tag/valid ram diag access	*/
-#define ASI_IMMU		0x50 /* Insn-MMU main register space		*/
-#define ASI_IMMU_TSB_8KB_PTR	0x51 /* Insn-MMU 8KB TSB pointer register	*/
-#define ASI_IMMU_TSB_64KB_PTR	0x52 /* Insn-MMU 64KB TSB pointer register	*/
-#define ASI_ITLB_DATA_IN	0x54 /* Insn-MMU TLB data in register		*/
-#define ASI_ITLB_DATA_ACCESS	0x55 /* Insn-MMU TLB data access register	*/
-#define ASI_ITLB_TAG_READ	0x56 /* Insn-MMU TLB tag read register		*/
-#define ASI_IMMU_DEMAP		0x57 /* Insn-MMU TLB demap			*/
-#define ASI_DMMU		0x58 /* Data-MMU main register space		*/
-#define ASI_DMMU_TSB_8KB_PTR	0x59 /* Data-MMU 8KB TSB pointer register	*/
-#define ASI_DMMU_TSB_64KB_PTR	0x5a /* Data-MMU 16KB TSB pointer register	*/
-#define ASI_DMMU_TSB_DIRECT_PTR	0x5b /* Data-MMU TSB direct pointer register	*/
-#define ASI_DTLB_DATA_IN	0x5c /* Data-MMU TLB data in register		*/
-#define ASI_DTLB_DATA_ACCESS	0x5d /* Data-MMU TLB data access register	*/
-#define ASI_DTLB_TAG_READ	0x5e /* Data-MMU TLB tag read register		*/
-#define ASI_DMMU_DEMAP		0x5f /* Data-MMU TLB demap			*/
-#define ASI_IIU_INST_TRAP	0x60 /* (III) Instruction Breakpoint register	*/
-#define ASI_IC_INSTR		0x66 /* Insn cache instrucion ram diag access	*/
-#define ASI_IC_TAG		0x67 /* Insn cache tag/valid ram diag access	*/
-#define ASI_IC_STAG		0x68 /* (III) Insn cache snoop tag ram diag	*/
-#define ASI_IC_PRE_DECODE	0x6e /* Insn cache pre-decode ram diag access	*/
-#define ASI_IC_NEXT_FIELD	0x6f /* Insn cache next-field ram diag access	*/
-#define ASI_BRPRED_ARRAY	0x6f /* (III) Branch Prediction RAM diag	*/
-#define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store		*/
-#define ASI_BLK_AIUS		0x71 /* Secondary, user, block load/store	*/
-#define ASI_MCU_CTRL_REG	0x72 /* (III) Memory controller registers	*/
-#define ASI_EC_DATA		0x74 /* (III) E-cache data staging register	*/
-#define ASI_EC_CTRL		0x75 /* (III) E-cache control register		*/
-#define ASI_EC_W		0x76 /* E-cache diag write access		*/
-#define ASI_UDB_ERROR_W		0x77 /* External UDB error registers write	*/
-#define ASI_UDB_CONTROL_W	0x77 /* External UDB control registers write	*/
-#define ASI_INTR_W		0x77 /* IRQ vector dispatch write		*/
-#define ASI_INTR_DATAN_W	0x77 /* (III) Outgoing irq vector data reg N	*/
-#define ASI_INTR_DISPATCH_W	0x77 /* (III) Interrupt vector dispatch		*/
-#define ASI_BLK_AIUPL		0x78 /* Primary, user, little, blk ld/st	*/
-#define ASI_BLK_AIUSL		0x79 /* Secondary, user, little, blk ld/st	*/
-#define ASI_EC_R		0x7e /* E-cache diag read access		*/
-#define ASI_UDBH_ERROR_R	0x7f /* External UDB error registers read hi	*/
-#define ASI_UDBL_ERROR_R	0x7f /* External UDB error registers read low	*/
-#define ASI_UDBH_CONTROL_R	0x7f /* External UDB control registers read hi	*/
-#define ASI_UDBL_CONTROL_R	0x7f /* External UDB control registers read low	*/
-#define ASI_INTR_R		0x7f /* IRQ vector dispatch read		*/
-#define ASI_INTR_DATAN_R	0x7f /* (III) Incoming irq vector data reg N	*/
-#define ASI_PST8_P		0xc0 /* Primary, 8 8-bit, partial		*/
-#define ASI_PST8_S		0xc1 /* Secondary, 8 8-bit, partial		*/
-#define ASI_PST16_P		0xc2 /* Primary, 4 16-bit, partial		*/
-#define ASI_PST16_S		0xc3 /* Seconary, 4 16-bit, partial		*/
-#define ASI_PST32_P		0xc4 /* Primary, 2 32-bit, partial		*/
-#define ASI_PST32_S		0xc5 /* Secondary, 2 32-bit, partial		*/
-#define ASI_PST8_PL		0xc8 /* Primary, 8 8-bit, partial, little	*/
-#define ASI_PST8_SL		0xc9 /* Secondary, 8 8-bit, partial, little	*/
-#define ASI_PST16_PL		0xca /* Primary, 4 16-bit, partial, little	*/
-#define ASI_PST16_SL		0xcb /* Seconary, 4 16-bit, partial, little	*/
-#define ASI_PST32_PL		0xcc /* Primary, 2 32-bit, partial, little	*/
-#define ASI_PST32_SL		0xcd /* Secondary, 2 32-bit, partial, little	*/
-#define ASI_FL8_P		0xd0 /* Primary, 1 8-bit, fpu ld/st		*/
-#define ASI_FL8_S		0xd1 /* Secondary, 1 8-bit, fpu ld/st		*/
-#define ASI_FL16_P		0xd2 /* Primary, 1 16-bit, fpu ld/st		*/
-#define ASI_FL16_S		0xd3 /* Secondary, 1 16-bit, fpu ld/st		*/
-#define ASI_FL8_PL		0xd8 /* Primary, 1 8-bit, fpu ld/st, little	*/
-#define ASI_FL8_SL		0xd9 /* Secondary, 1 8-bit, fpu ld/st, little	*/
-#define ASI_FL16_PL		0xda /* Primary, 1 16-bit, fpu ld/st, little	*/
-#define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st, little	*/
-#define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit		*/
-#define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit		*/
-#define ASI_BLK_P		0xf0 /* Primary, blk ld/st			*/
-#define ASI_BLK_S		0xf1 /* Secondary, blk ld/st			*/
-#define ASI_BLK_PL		0xf8 /* Primary, blk ld/st, little		*/
-#define ASI_BLK_SL		0xf9 /* Secondary, blk ld/st, little		*/
+#define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable		*/
+#define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-bit			*/
+#define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian*/
+#define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-bit, little endian	*/
+#define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load		*/
+#define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, l-endian 	*/
+#define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data stat RAM diag	*/
+#define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag	*/
+#define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag	*/
+#define ASI_PCACHE_SNOOP_TAG	0x33 /* (III) PCache snoop tag RAM diag	*/
+#define ASI_QUAD_LDD_PHYS	0x34 /* (III+) PADDR, qword load	*/
+#define ASI_WCACHE_VALID_BITS	0x38 /* (III) WCache Valid Bits diag	*/
+#define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag	*/
+#define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag	*/
+#define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag	*/
+#define ASI_QUAD_LDD_PHYS_L	0x3c /* (III+) PADDR, qw-load, l-endian	*/
+#define ASI_SRAM_FAST_INIT	0x40 /* (III+) Fast SRAM init		*/
+#define ASI_CORE_AVAILABLE	0x41 /* (CMT) LP Available		*/
+#define ASI_CORE_ENABLE_STAT	0x41 /* (CMT) LP Enable Status		*/
+#define ASI_CORE_ENABLE		0x41 /* (CMT) LP Enable RW		*/
+#define ASI_XIR_STEERING	0x41 /* (CMT) XIR Steering RW		*/
+#define ASI_CORE_RUNNING_RW	0x41 /* (CMT) LP Running RW		*/
+#define ASI_CORE_RUNNING_W1S	0x41 /* (CMT) LP Running Write-One Set	*/
+#define ASI_CORE_RUNNING_W1C	0x41 /* (CMT) LP Running Write-One Clr	*/
+#define ASI_CORE_RUNNING_STAT	0x41 /* (CMT) LP Running Status		*/
+#define ASI_CMT_ERROR_STEERING	0x41 /* (CMT) Error Steering RW		*/
+#define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag	*/
+#define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag		*/
+#define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag	*/
+#define ASI_LSU_CONTROL		0x45 /* Load-store control unit		*/
+#define ASI_DCU_CONTROL_REG	0x45 /* (III) DCache Unit Control reg	*/
+#define ASI_DCACHE_DATA		0x46 /* DCache data-ram diag access	*/
+#define ASI_DCACHE_TAG		0x47 /* Dcache tag/valid ram diag access*/
+#define ASI_INTR_DISPATCH_STAT	0x48 /* IRQ vector dispatch status	*/
+#define ASI_INTR_RECEIVE	0x49 /* IRQ vector receive status	*/
+#define ASI_UPA_CONFIG		0x4a /* UPA config space		*/
+#define ASI_JBUS_CONFIG		0x4a /* (IIIi) JBUS Config Register	*/
+#define ASI_SAFARI_CONFIG	0x4a /* (III) Safari Config Register	*/
+#define ASI_SAFARI_ADDRESS	0x4a /* (III) Safari Address Register	*/
+#define ASI_ESTATE_ERROR_EN	0x4b /* E-cache error enable space	*/
+#define ASI_AFSR		0x4c /* Async fault status register	*/
+#define ASI_AFAR		0x4d /* Async fault address register	*/
+#define ASI_EC_TAG_DATA		0x4e /* E-cache tag/valid ram diag acc	*/
+#define ASI_IMMU		0x50 /* Insn-MMU main register space	*/
+#define ASI_IMMU_TSB_8KB_PTR	0x51 /* Insn-MMU 8KB TSB pointer reg	*/
+#define ASI_IMMU_TSB_64KB_PTR	0x52 /* Insn-MMU 64KB TSB pointer reg	*/
+#define ASI_ITLB_DATA_IN	0x54 /* Insn-MMU TLB data in reg	*/
+#define ASI_ITLB_DATA_ACCESS	0x55 /* Insn-MMU TLB data access reg	*/
+#define ASI_ITLB_TAG_READ	0x56 /* Insn-MMU TLB tag read reg	*/
+#define ASI_IMMU_DEMAP		0x57 /* Insn-MMU TLB demap		*/
+#define ASI_DMMU		0x58 /* Data-MMU main register space	*/
+#define ASI_DMMU_TSB_8KB_PTR	0x59 /* Data-MMU 8KB TSB pointer reg	*/
+#define ASI_DMMU_TSB_64KB_PTR	0x5a /* Data-MMU 16KB TSB pointer reg	*/
+#define ASI_DMMU_TSB_DIRECT_PTR	0x5b /* Data-MMU TSB direct pointer reg	*/
+#define ASI_DTLB_DATA_IN	0x5c /* Data-MMU TLB data in reg	*/
+#define ASI_DTLB_DATA_ACCESS	0x5d /* Data-MMU TLB data access reg	*/
+#define ASI_DTLB_TAG_READ	0x5e /* Data-MMU TLB tag read reg	*/
+#define ASI_DMMU_DEMAP		0x5f /* Data-MMU TLB demap		*/
+#define ASI_IIU_INST_TRAP	0x60 /* (III) Instruction Breakpoint	*/
+#define ASI_INTR_ID		0x63 /* (CMT) Interrupt ID register	*/
+#define ASI_CORE_ID		0x63 /* (CMT) LP ID register		*/
+#define ASI_CESR_ID		0x63 /* (CMT) CESR ID register		*/
+#define ASI_IC_INSTR		0x66 /* Insn cache instrucion ram diag	*/
+#define ASI_IC_TAG		0x67 /* Insn cache tag/valid ram diag 	*/
+#define ASI_IC_STAG		0x68 /* (III) Insn cache snoop tag ram	*/
+#define ASI_IC_PRE_DECODE	0x6e /* Insn cache pre-decode ram diag	*/
+#define ASI_IC_NEXT_FIELD	0x6f /* Insn cache next-field ram diag	*/
+#define ASI_BRPRED_ARRAY	0x6f /* (III) Branch Prediction RAM diag*/
+#define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store	*/
+#define ASI_BLK_AIUS		0x71 /* Secondary, user, block ld/st	*/
+#define ASI_MCU_CTRL_REG	0x72 /* (III) Memory controller regs	*/
+#define ASI_EC_DATA		0x74 /* (III) E-cache data staging reg	*/
+#define ASI_EC_CTRL		0x75 /* (III) E-cache control reg	*/
+#define ASI_EC_W		0x76 /* E-cache diag write access	*/
+#define ASI_UDB_ERROR_W		0x77 /* External UDB error regs W	*/
+#define ASI_UDB_CONTROL_W	0x77 /* External UDB control regs W	*/
+#define ASI_INTR_W		0x77 /* IRQ vector dispatch write	*/
+#define ASI_INTR_DATAN_W	0x77 /* (III) Out irq vector data reg N	*/
+#define ASI_INTR_DISPATCH_W	0x77 /* (III) Interrupt vector dispatch	*/
+#define ASI_BLK_AIUPL		0x78 /* Primary, user, little, blk ld/st*/
+#define ASI_BLK_AIUSL		0x79 /* Secondary, user, little, blk ld/st*/
+#define ASI_EC_R		0x7e /* E-cache diag read access	*/
+#define ASI_UDBH_ERROR_R	0x7f /* External UDB error regs rd hi	*/
+#define ASI_UDBL_ERROR_R	0x7f /* External UDB error regs rd low	*/
+#define ASI_UDBH_CONTROL_R	0x7f /* External UDB control regs rd hi	*/
+#define ASI_UDBL_CONTROL_R	0x7f /* External UDB control regs rd low*/
+#define ASI_INTR_R		0x7f /* IRQ vector dispatch read	*/
+#define ASI_INTR_DATAN_R	0x7f /* (III) In irq vector data reg N	*/
+#define ASI_PST8_P		0xc0 /* Primary, 8 8-bit, partial	*/
+#define ASI_PST8_S		0xc1 /* Secondary, 8 8-bit, partial	*/
+#define ASI_PST16_P		0xc2 /* Primary, 4 16-bit, partial	*/
+#define ASI_PST16_S		0xc3 /* Secondary, 4 16-bit, partial	*/
+#define ASI_PST32_P		0xc4 /* Primary, 2 32-bit, partial	*/
+#define ASI_PST32_S		0xc5 /* Secondary, 2 32-bit, partial	*/
+#define ASI_PST8_PL		0xc8 /* Primary, 8 8-bit, partial, L	*/
+#define ASI_PST8_SL		0xc9 /* Secondary, 8 8-bit, partial, L	*/
+#define ASI_PST16_PL		0xca /* Primary, 4 16-bit, partial, L	*/
+#define ASI_PST16_SL		0xcb /* Secondary, 4 16-bit, partial, L	*/
+#define ASI_PST32_PL		0xcc /* Primary, 2 32-bit, partial, L	*/
+#define ASI_PST32_SL		0xcd /* Secondary, 2 32-bit, partial, L	*/
+#define ASI_FL8_P		0xd0 /* Primary, 1 8-bit, fpu ld/st	*/
+#define ASI_FL8_S		0xd1 /* Secondary, 1 8-bit, fpu ld/st	*/
+#define ASI_FL16_P		0xd2 /* Primary, 1 16-bit, fpu ld/st	*/
+#define ASI_FL16_S		0xd3 /* Secondary, 1 16-bit, fpu ld/st	*/
+#define ASI_FL8_PL		0xd8 /* Primary, 1 8-bit, fpu ld/st, L	*/
+#define ASI_FL8_SL		0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/
+#define ASI_FL16_PL		0xda /* Primary, 1 16-bit, fpu ld/st, L	*/
+#define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/
+#define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit	*/
+#define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit	*/
+#define ASI_BLK_P		0xf0 /* Primary, blk ld/st		*/
+#define ASI_BLK_S		0xf1 /* Secondary, blk ld/st		*/
+#define ASI_BLK_PL		0xf8 /* Primary, blk ld/st, little	*/
+#define ASI_BLK_SL		0xf9 /* Secondary, blk ld/st, little	*/
 
 #endif /* _SPARC64_ASI_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-sparc64/cmt.h linux-2.4.28-pre1/include/asm-sparc64/cmt.h
--- linux-2.4.27/include/asm-sparc64/cmt.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-sparc64/cmt.h	2004-08-15 19:51:36.000000000 +0000
@@ -0,0 +1,59 @@
+#ifndef _SPARC64_CMT_H
+#define _SPARC64_CMT_H
+
+/* cmt.h: Chip Multi-Threading register definitions
+ *
+ * Copyright (C) 2004 David S. Miller (davem@redhat.com)
+ */
+
+/* ASI_CORE_ID - private */
+#define LP_ID		0x0000000000000010UL
+#define  LP_ID_MAX	0x00000000003f0000UL
+#define  LP_ID_ID	0x000000000000003fUL
+
+/* ASI_INTR_ID - private */
+#define LP_INTR_ID	0x0000000000000000UL
+#define  LP_INTR_ID_ID	0x00000000000003ffUL
+
+/* ASI_CESR_ID - private */
+#define CESR_ID		0x0000000000000040UL
+#define  CESR_ID_ID	0x00000000000000ffUL
+
+/* ASI_CORE_AVAILABLE - shared */
+#define LP_AVAIL	0x0000000000000000UL
+#define  LP_AVAIL_1	0x0000000000000002UL
+#define  LP_AVAIL_0	0x0000000000000001UL
+
+/* ASI_CORE_ENABLE_STATUS - shared */
+#define LP_ENAB_STAT	0x0000000000000010UL
+#define  LP_ENAB_STAT_1	0x0000000000000002UL
+#define  LP_ENAB_STAT_0	0x0000000000000001UL
+
+/* ASI_CORE_ENABLE - shared */
+#define LP_ENAB		0x0000000000000020UL
+#define  LP_ENAB_1	0x0000000000000002UL
+#define  LP_ENAB_0	0x0000000000000001UL
+
+/* ASI_CORE_RUNNING - shared */
+#define LP_RUNNING_RW	0x0000000000000050UL
+#define LP_RUNNING_W1S	0x0000000000000060UL
+#define LP_RUNNING_W1C	0x0000000000000068UL
+#define  LP_RUNNING_1	0x0000000000000002UL
+#define  LP_RUNNING_0	0x0000000000000001UL
+
+/* ASI_CORE_RUNNING_STAT - shared */
+#define LP_RUN_STAT	0x0000000000000058UL
+#define  LP_RUN_STAT_1	0x0000000000000002UL
+#define  LP_RUN_STAT_0	0x0000000000000001UL
+
+/* ASI_XIR_STEERING - shared */
+#define LP_XIR_STEER	0x0000000000000030UL
+#define  LP_XIR_STEER_1	0x0000000000000002UL
+#define  LP_XIR_STEER_0	0x0000000000000001UL
+
+/* ASI_CMT_ERROR_STEERING - shared */
+#define CMT_ER_STEER	0x0000000000000040UL
+#define  CMT_ER_STEER_1	0x0000000000000002UL
+#define  CMT_ER_STEER_0	0x0000000000000001UL
+
+#endif /* _SPARC64_CMT_H */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-sparc64/page.h linux-2.4.28-pre1/include/asm-sparc64/page.h
--- linux-2.4.27/include/asm-sparc64/page.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-sparc64/page.h	2004-08-15 19:49:39.000000000 +0000
@@ -36,7 +36,7 @@ extern void do_BUG(const char *file, int
 extern void _clear_page(void *page);
 #define clear_page(X)	_clear_page((void *)(X))
 extern void clear_user_page(void *page, unsigned long vaddr);
-#define copy_page(X,Y)	__memcpy((void *)(X), (void *)(Y), PAGE_SIZE)
+#define copy_page(X,Y)	memcpy((void *)(X), (void *)(Y), PAGE_SIZE)
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
 /* GROSS, defining this makes gcc pass these types as aggregates,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-sparc64/pgtable.h linux-2.4.28-pre1/include/asm-sparc64/pgtable.h
--- linux-2.4.27/include/asm-sparc64/pgtable.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-sparc64/pgtable.h	2004-08-15 19:47:35.000000000 +0000
@@ -101,32 +101,36 @@
 #endif /* !(__ASSEMBLY__) */
 
 /* Spitfire/Cheetah TTE bits. */
-#define _PAGE_VALID	0x8000000000000000	/* Valid TTE                          */
-#define _PAGE_R		0x8000000000000000	/* Used to keep ref bit up to date    */
-#define _PAGE_SZ4MB	0x6000000000000000	/* 4MB Page                           */
-#define _PAGE_SZ512K	0x4000000000000000	/* 512K Page                          */
-#define _PAGE_SZ64K	0x2000000000000000	/* 64K Page                           */
-#define _PAGE_SZ8K	0x0000000000000000	/* 8K Page                            */
-#define _PAGE_NFO	0x1000000000000000	/* No Fault Only                      */
-#define _PAGE_IE	0x0800000000000000	/* Invert Endianness                  */
-#define _PAGE_SN	0x0000800000000000	/* (Cheetah) Snoop                    */
-#define _PAGE_PADDR_SF	0x000001FFFFFFE000	/* (Spitfire) Phys Address [40:13]    */
-#define _PAGE_PADDR	0x000007FFFFFFE000	/* (Cheetah) Phys Address [42:13]     */
-#define _PAGE_SOFT	0x0000000000001F80	/* Software bits                      */
-#define _PAGE_L		0x0000000000000040	/* Locked TTE                         */
-#define _PAGE_CP	0x0000000000000020	/* Cacheable in Physical Cache        */
-#define _PAGE_CV	0x0000000000000010	/* Cacheable in Virtual Cache         */
-#define _PAGE_E		0x0000000000000008	/* side-Effect                        */
-#define _PAGE_P		0x0000000000000004	/* Privileged Page                    */
-#define _PAGE_W		0x0000000000000002	/* Writable                           */
-#define _PAGE_G		0x0000000000000001	/* Global                             */
+#define _PAGE_VALID	0x8000000000000000	/* Valid TTE                 */
+#define _PAGE_R		0x8000000000000000	/* Keep ref bit up to date   */
+#define _PAGE_SZ4MB	0x6000000000000000	/* 4MB Page                  */
+#define _PAGE_SZ512K	0x4000000000000000	/* 512K Page                 */
+#define _PAGE_SZ64K	0x2000000000000000	/* 64K Page                  */
+#define _PAGE_SZ8K	0x0000000000000000	/* 8K Page                   */
+#define _PAGE_NFO	0x1000000000000000	/* No Fault Only             */
+#define _PAGE_IE	0x0800000000000000	/* Invert Endianness         */
+#define _PAGE_SOFT2	0x07FC000000000000	/* Software bits, set 2      */
+#define _PAGE_RES1	0x0003000000000000	/* Reserved                  */
+#define _PAGE_SN	0x0000800000000000	/* (Cheetah) Snoop           */
+#define _PAGE_RES2	0x0000780000000000	/* Reserved                  */
+#define _PAGE_PADDR_SF	0x000001FFFFFFE000	/* (Spitfire) paddr[40:13]   */
+#define _PAGE_PADDR	0x000007FFFFFFE000	/* (Cheetah) paddr[42:13]    */
+#define _PAGE_SOFT	0x0000000000001F80	/* Software bits             */
+#define _PAGE_L		0x0000000000000040	/* Locked TTE                */
+#define _PAGE_CP	0x0000000000000020	/* Cacheable in P-Cache      */
+#define _PAGE_CV	0x0000000000000010	/* Cacheable in V-Cache      */
+#define _PAGE_E		0x0000000000000008	/* side-Effect               */
+#define _PAGE_P		0x0000000000000004	/* Privileged Page           */
+#define _PAGE_W		0x0000000000000002	/* Writable                  */
+#define _PAGE_G		0x0000000000000001	/* Global                    */
 
 /* Here are the SpitFire software bits we use in the TTE's. */
-#define _PAGE_MODIFIED	0x0000000000000800	/* Modified Page (ie. dirty)          */
-#define _PAGE_ACCESSED	0x0000000000000400	/* Accessed Page (ie. referenced)     */
-#define _PAGE_READ	0x0000000000000200	/* Readable SW Bit                    */
-#define _PAGE_WRITE	0x0000000000000100	/* Writable SW Bit                    */
-#define _PAGE_PRESENT	0x0000000000000080	/* Present Page (ie. not swapped out) */
+#define _PAGE_EXEC	0x0000000000001000	/* Executable SW bit         */
+#define _PAGE_MODIFIED	0x0000000000000800	/* Modified Page (ie. dirty) */
+#define _PAGE_ACCESSED	0x0000000000000400	/* Accessed Page (ie. ref'd) */
+#define _PAGE_READ	0x0000000000000200	/* Readable SW Bit           */
+#define _PAGE_WRITE	0x0000000000000100	/* Writable SW Bit           */
+#define _PAGE_PRESENT	0x0000000000000080	/* Present                   */
 
 #if PAGE_SHIFT == 13
 #define _PAGE_SZBITS	_PAGE_SZ8K
@@ -150,16 +154,27 @@
 
 /* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */
 #define PAGE_SHARED	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS | _PAGE_WRITE)
+				  __ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC)
 
 #define PAGE_COPY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS)
+				  __ACCESS_BITS | _PAGE_EXEC)
 
 #define PAGE_READONLY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __ACCESS_BITS)
+				  __ACCESS_BITS | _PAGE_EXEC)
 
 #define PAGE_KERNEL	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
-				  __PRIV_BITS | __ACCESS_BITS | __DIRTY_BITS)
+				  __PRIV_BITS | \
+				  __ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC)
+
+#define PAGE_SHARED_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
+					  _PAGE_CACHE | \
+					  __ACCESS_BITS | _PAGE_WRITE)
+
+#define PAGE_COPY_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
+					  _PAGE_CACHE | __ACCESS_BITS)
+
+#define PAGE_READONLY_NOEXEC	__pgprot (_PAGE_PRESENT | _PAGE_VALID | \
+					  _PAGE_CACHE | __ACCESS_BITS)
 
 #define PAGE_INVALID	__pgprot (0)
 
@@ -170,18 +185,18 @@
 #define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | __ACCESS_BITS | _PAGE_E)
 
 #define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY
-#define __P010	PAGE_COPY
-#define __P011	PAGE_COPY
+#define __P001	PAGE_READONLY_NOEXEC
+#define __P010	PAGE_COPY_NOEXEC
+#define __P011	PAGE_COPY_NOEXEC
 #define __P100	PAGE_READONLY
 #define __P101	PAGE_READONLY
 #define __P110	PAGE_COPY
 #define __P111	PAGE_COPY
 
 #define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
+#define __S001	PAGE_READONLY_NOEXEC
+#define __S010	PAGE_SHARED_NOEXEC
+#define __S011	PAGE_SHARED_NOEXEC
 #define __S100	PAGE_READONLY
 #define __S101	PAGE_READONLY
 #define __S110	PAGE_SHARED
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-sparc64/string.h linux-2.4.28-pre1/include/asm-sparc64/string.h
--- linux-2.4.27/include/asm-sparc64/string.h	2001-10-01 16:19:56.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-sparc64/string.h	2004-08-15 19:51:30.000000000 +0000
@@ -16,9 +16,7 @@
 #include <asm/asi.h>
 
 extern void __memmove(void *,const void *,__kernel_size_t);
-extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t);
 extern void *__memset(void *,int,__kernel_size_t);
-extern void *__builtin_memcpy(void *,const void *,__kernel_size_t);
 extern void *__builtin_memset(void *,int,__kernel_size_t);
 
 #ifndef EXPORT_SYMTAB_STROPS
@@ -37,29 +35,7 @@ extern void *__builtin_memset(void *,int
 
 #define __HAVE_ARCH_MEMCPY
 
-static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n)
-{
-	if(n) {
-		if(n <= 32) {
-			__builtin_memcpy(to, from, n);
-		} else {
-			__memcpy(to, from, n);
-		}
-	}
-	return to;
-}
-
-static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
-{
-	__memcpy(to, from, n);
-	return to;
-}
-
-#undef memcpy
-#define memcpy(t, f, n) \
-(__builtin_constant_p(n) ? \
- __constant_memcpy((t),(f),(n)) : \
- __nonconstant_memcpy((t),(f),(n)))
+extern void * memcpy(void *,const void *,__kernel_size_t);
 
 #define __HAVE_ARCH_MEMSET
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/asm-x86_64/unistd.h linux-2.4.28-pre1/include/asm-x86_64/unistd.h
--- linux-2.4.27/include/asm-x86_64/unistd.h	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.28-pre1/include/asm-x86_64/unistd.h	2004-08-15 19:51:12.000000000 +0000
@@ -673,7 +673,7 @@ static inline long close(unsigned int fd
 }
 
 extern long sys_exit(int) __attribute__((noreturn));
-extern inline long exit(int error_code)
+static inline void exit(int error_code)
 {
 	sys_exit(error_code);
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/ac97_codec.h linux-2.4.28-pre1/include/linux/ac97_codec.h
--- linux-2.4.27/include/linux/ac97_codec.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/ac97_codec.h	2004-08-15 19:47:45.000000000 +0000
@@ -290,6 +290,7 @@ struct ac97_ops
 	
 #define AC97_DELUDED_MODEM	1	/* Audio codec reports its a modem */
 #define AC97_NO_PCM_VOLUME	2	/* Volume control is missing 	   */
+#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */
 };
 
 extern int ac97_read_proc (char *page_out, char **start, off_t off,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/agp_backend.h linux-2.4.28-pre1/include/linux/agp_backend.h
--- linux-2.4.27/include/linux/agp_backend.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/agp_backend.h	2004-08-15 19:51:12.000000000 +0000
@@ -55,6 +55,7 @@ enum chipset_type {
 	INTEL_I855_PM,
 	INTEL_I860,
 	INTEL_I865_G,
+	INTEL_I915_G,
 	INTEL_I7205,
 	INTEL_I7505,
 	INTEL_460GX,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/ata.h linux-2.4.28-pre1/include/linux/ata.h
--- linux-2.4.27/include/linux/ata.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/ata.h	2004-08-15 19:48:14.000000000 +0000
@@ -42,6 +42,7 @@ enum {
 	ATA_ID_SERNO_OFS	= 10,
 	ATA_ID_MAJOR_VER	= 80,
 	ATA_ID_PIO_MODES	= 64,
+	ATA_ID_MWDMA_MODES	= 63,
 	ATA_ID_UDMA_MODES	= 88,
 	ATA_ID_PIO4		= (1 << 1),
 
@@ -78,9 +79,11 @@ enum {
 	ATA_NIEN		= (1 << 1),	/* disable-irq flag */
 	ATA_LBA			= (1 << 6),	/* LBA28 selector */
 	ATA_DEV1		= (1 << 4),	/* Select Device 1 (slave) */
-	ATA_BUSY		= (1 << 7),	/* BSY status bit */
 	ATA_DEVICE_OBS		= (1 << 7) | (1 << 5), /* obs bits in dev reg */
 	ATA_DEVCTL_OBS		= (1 << 3),	/* obsolete bit in devctl reg */
+	ATA_BUSY		= (1 << 7),	/* BSY status bit */
+	ATA_DRDY		= (1 << 6),	/* device ready */
+	ATA_DF			= (1 << 5),	/* device fault */
 	ATA_DRQ			= (1 << 3),	/* data request i/o */
 	ATA_ERR			= (1 << 0),	/* have an error */
 	ATA_SRST		= (1 << 2),	/* software reset */
@@ -131,13 +134,20 @@ enum {
 	XFER_UDMA_2		= 0x42,
 	XFER_UDMA_1		= 0x41,
 	XFER_UDMA_0		= 0x40,
+	XFER_MW_DMA_2		= 0x22,
+	XFER_MW_DMA_1		= 0x21,
+	XFER_MW_DMA_0		= 0x20,
 	XFER_PIO_4		= 0x0C,
 	XFER_PIO_3		= 0x0B,
+	XFER_PIO_2		= 0x0A,
+	XFER_PIO_1		= 0x09,
+	XFER_PIO_0		= 0x08,
 
 	/* ATAPI stuff */
 	ATAPI_PKT_DMA		= (1 << 0),
 	ATAPI_DMADIR		= (1 << 2),	/* ATAPI data dir:
 						   0=to device, 1=to host */
+	ATAPI_CDB_LEN		= 16,
 
 	/* cable types */
 	ATA_CBL_NONE		= 0,
@@ -167,7 +177,8 @@ enum ata_tf_protocols {
 	ATA_PROT_PIO,		/* PIO single sector */
 	ATA_PROT_PIO_MULT,	/* PIO multiple sector */
 	ATA_PROT_DMA,		/* DMA */
-	ATA_PROT_ATAPI,		/* packet command */
+	ATA_PROT_ATAPI,		/* packet command, PIO data xfer*/
+	ATA_PROT_ATAPI_NODATA,	/* packet command, no data */
 	ATA_PROT_ATAPI_DMA,	/* packet command with special DMA sauce */
 };
 
@@ -207,8 +218,8 @@ struct ata_taskfile {
 #define ata_id_has_lba48(dev)	((dev)->id[83] & (1 << 10))
 #define ata_id_has_wcache(dev)	((dev)->id[82] & (1 << 5))
 #define ata_id_has_pm(dev)	((dev)->id[82] & (1 << 3))
-#define ata_id_has_lba(dev)	((dev)->id[49] & (1 << 8))
-#define ata_id_has_dma(dev)	((dev)->id[49] & (1 << 9))
+#define ata_id_has_lba(dev)	((dev)->id[49] & (1 << 9))
+#define ata_id_has_dma(dev)	((dev)->id[49] & (1 << 8))
 #define ata_id_removeable(dev)	((dev)->id[0] & (1 << 7))
 #define ata_id_u32(dev,n)	\
 	(((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)]))
@@ -218,10 +229,27 @@ struct ata_taskfile {
 	  ((u64) dev->id[(n) + 1] << 16) |	\
 	  ((u64) dev->id[(n) + 0]) )
 
+static inline int atapi_cdb_len(u16 *dev_id)
+{
+	u16 tmp = dev_id[0] & 0x3;
+	switch (tmp) {
+	case 0:		return 12;
+	case 1:		return 16;
+	default:	return -1;
+	}
+}
+
 static inline int is_atapi_taskfile(struct ata_taskfile *tf)
 {
 	return (tf->protocol == ATA_PROT_ATAPI) ||
+	       (tf->protocol == ATA_PROT_ATAPI_NODATA) ||
 	       (tf->protocol == ATA_PROT_ATAPI_DMA);
 }
 
+static inline int ata_ok(u8 status)
+{
+	return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
+			== ATA_DRDY);
+}
+
 #endif /* __LINUX_ATA_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/in6.h linux-2.4.28-pre1/include/linux/in6.h
--- linux-2.4.27/include/linux/in6.h	2003-06-13 14:51:38.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/in6.h	2004-08-15 19:50:32.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	Sources:
  *	IPv6 Program Interfaces for BSD Systems
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/ipv6_route.h linux-2.4.28-pre1/include/linux/ipv6_route.h
--- linux-2.4.27/include/linux/ipv6_route.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/ipv6_route.h	2004-08-15 19:48:30.000000000 +0000
@@ -2,7 +2,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/irq_cpustat.h linux-2.4.28-pre1/include/linux/irq_cpustat.h
--- linux-2.4.27/include/linux/irq_cpustat.h	2001-11-22 19:46:18.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/irq_cpustat.h	2004-08-15 19:51:42.000000000 +0000
@@ -22,7 +22,7 @@ extern irq_cpustat_t irq_stat[];			/* de
 #ifdef CONFIG_SMP
 #define __IRQ_STAT(cpu, member)	(irq_stat[cpu].member)
 #else
-#define __IRQ_STAT(cpu, member)	((void)(cpu), irq_stat[0].member)
+#define __IRQ_STAT(cpu, member)	(irq_stat[((void)(cpu), 0)].member)
 #endif	
 
   /* arch independent irq_stat fields */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/jbd.h linux-2.4.28-pre1/include/linux/jbd.h
--- linux-2.4.27/include/linux/jbd.h	2003-06-13 14:51:38.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/jbd.h	2004-08-15 19:51:15.000000000 +0000
@@ -70,7 +70,7 @@ extern int journal_enable_debug;
 #define jbd_debug(f, a...)	/**/
 #endif
 
-extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
+extern void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry);
 #define jbd_kmalloc(size, flags) \
 	__jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
 #define jbd_rep_kmalloc(size, flags) \
@@ -867,7 +867,7 @@ do {								      \
 	schedule();						      \
 } while (1)
 
-extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *);
+extern void __jbd_unexpected_dirty_buffer(const char *, int, struct journal_head *);
 #define jbd_unexpected_dirty_buffer(jh) \
 	__jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh))
 	
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/kernel.h linux-2.4.28-pre1/include/linux/kernel.h
--- linux-2.4.27/include/linux/kernel.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/kernel.h	2004-08-15 19:47:18.000000000 +0000
@@ -51,8 +51,10 @@ extern int console_printk[];
 
 #ifdef __i386__
 #define FASTCALL(x)	x __attribute__((regparm(3)))
+#define fastcall	__attribute__((regparm(3)))
 #else
 #define FASTCALL(x)	x
+#define fastcall
 #endif
 
 struct completion;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/libata.h linux-2.4.28-pre1/include/linux/libata.h
--- linux-2.4.27/include/linux/libata.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/libata.h	2004-08-15 19:51:07.000000000 +0000
@@ -32,7 +32,6 @@
 /*
  * compile-time options
  */
-#undef ATA_FORCE_PIO		/* do not configure or use DMA */
 #undef ATA_DEBUG		/* debugging output */
 #undef ATA_VERBOSE_DEBUG	/* yet more debugging output */
 #undef ATA_IRQ_TRAP		/* define to ack screaming irqs */
@@ -89,9 +88,7 @@ enum {
 	/* struct ata_device stuff */
 	ATA_DFLAG_LBA48		= (1 << 0), /* device supports LBA48 */
 	ATA_DFLAG_PIO		= (1 << 1), /* device currently in PIO mode */
-	ATA_DFLAG_MASTER	= (1 << 2), /* is device 0? */
-	ATA_DFLAG_WCACHE	= (1 << 3), /* has write cache we can
-					     * (hopefully) flush? */
+	ATA_DFLAG_LOCK_SECTORS	= (1 << 2), /* don't adjust max_sectors */
 
 	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
 	ATA_DEV_ATA		= 1,	/* ATA device */
@@ -111,8 +108,9 @@ enum {
 	ATA_FLAG_SATA_RESET	= (1 << 7), /* use COMRESET */
 
 	ATA_QCFLAG_ACTIVE	= (1 << 1), /* cmd not yet ack'd to scsi lyer */
-	ATA_QCFLAG_DMA		= (1 << 2), /* data delivered via DMA */
-	ATA_QCFLAG_SG		= (1 << 4), /* have s/g table? */
+	ATA_QCFLAG_SG		= (1 << 3), /* have s/g table? */
+	ATA_QCFLAG_SINGLE	= (1 << 4), /* no s/g, just a single buffer */
+	ATA_QCFLAG_DMAMAP	= ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
 
 	/* various lengths of time */
 	ATA_TMOUT_EDD		= 5 * HZ,	/* hueristic */
@@ -134,24 +132,17 @@ enum {
 	BUS_IDENTIFY		= 8,
 	BUS_PACKET		= 9,
 
-	/* thread states */
-	THR_UNKNOWN		= 0,
-	THR_PORT_RESET		= (THR_UNKNOWN + 1),
-	THR_AWAIT_DEATH		= (THR_PORT_RESET + 1),
-	THR_PROBE_FAILED	= (THR_AWAIT_DEATH + 1),
-	THR_IDLE		= (THR_PROBE_FAILED + 1),
-	THR_PROBE_SUCCESS	= (THR_IDLE + 1),
-	THR_PROBE_START		= (THR_PROBE_SUCCESS + 1),
-
 	/* SATA port states */
 	PORT_UNKNOWN		= 0,
 	PORT_ENABLED		= 1,
 	PORT_DISABLED		= 2,
 
-	/* ata_qc_cb_t flags - note uses above ATA_QCFLAG_xxx namespace,
-	 * but not numberspace
+	/* encoding various smaller bitmaps into a single
+	 * unsigned long bitmap
 	 */
-	ATA_QCFLAG_TIMEOUT	= (1 << 0),
+	ATA_SHIFT_UDMA		= 0,
+	ATA_SHIFT_MWDMA		= 8,
+	ATA_SHIFT_PIO		= 11,
 };
 
 enum pio_task_states {
@@ -171,7 +162,7 @@ struct ata_port;
 struct ata_queued_cmd;
 
 /* typedefs */
-typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc, unsigned int flags);
+typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat);
 
 struct ata_ioports {
 	unsigned long		cmd_addr;
@@ -199,6 +190,7 @@ struct ata_probe_ent {
 	struct ata_ioports	port[ATA_MAX_PORTS];
 	unsigned int		n_ports;
 	unsigned int		pio_mask;
+	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		legacy_mode;
 	unsigned long		irq;
@@ -215,6 +207,7 @@ struct ata_host_set {
 	void			*mmio_base;
 	unsigned int		n_ports;
 	void			*private_data;
+	struct ata_port_operations *ops;
 	struct ata_port *	ports[0];
 };
 
@@ -225,19 +218,26 @@ struct ata_queued_cmd {
 	struct scsi_cmnd	*scsicmd;
 	void			(*scsidone)(struct scsi_cmnd *);
 
+	struct ata_taskfile	tf;
+	u8			cdb[ATAPI_CDB_LEN];
+
 	unsigned long		flags;		/* ATA_QCFLAG_xxx */
 	unsigned int		tag;
 	unsigned int		n_elem;
+
+	int			pci_dma_dir;
+
 	unsigned int		nsect;
 	unsigned int		cursect;
 	unsigned int		cursg;
 	unsigned int		cursg_ofs;
-	struct ata_taskfile	tf;
+
 	struct scatterlist	sgent;
+	void			*buf_virt;
 
 	struct scatterlist	*sg;
 
-	ata_qc_cb_t		callback;
+	ata_qc_cb_t		complete_fn;
 
 	struct completion	*waiting;
 
@@ -256,8 +256,10 @@ struct ata_device {
 	unsigned int		class;		/* ATA_DEV_xxx */
 	unsigned int		devno;		/* 0 or 1 */
 	u16			id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
-	unsigned int		pio_mode;
-	unsigned int		udma_mode;
+	u8			pio_mode;
+	u8			dma_mode;
+	u8			xfer_mode;
+	unsigned int		xfer_shift;	/* ATA_SHIFT_xxx */
 
 	/* cache info about current transfer mode */
 	u8			xfer_protocol;	/* taskfile xfer protocol */
@@ -282,8 +284,10 @@ struct ata_port {
 	unsigned int		bus_state;
 	unsigned int		port_state;
 	unsigned int		pio_mask;
+	unsigned int		mwdma_mask;
 	unsigned int		udma_mask;
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
+	unsigned int		cdb_len;
 
 	struct ata_device	device[ATA_MAX_DEVICES];
 
@@ -294,18 +298,12 @@ struct ata_port {
 	struct ata_host_stats	stats;
 	struct ata_host_set	*host_set;
 
-	struct semaphore	probe_sem;
-
-	unsigned int		thr_state;
-
 	struct tq_struct	packet_task;
 
 	struct tq_struct	pio_task;
 	unsigned int		pio_task_state;
 	unsigned long		pio_task_timeout;
 
-	struct tq_struct	probe_task;
-
 	void			*private_data;
 };
 
@@ -314,10 +312,8 @@ struct ata_port_operations {
 
 	void (*dev_config) (struct ata_port *, struct ata_device *);
 
-	void (*set_piomode) (struct ata_port *, struct ata_device *,
-			     unsigned int);
-	void (*set_udmamode) (struct ata_port *, struct ata_device *,
-			     unsigned int);
+	void (*set_piomode) (struct ata_port *, struct ata_device *);
+	void (*set_dmamode) (struct ata_port *, struct ata_device *);
 
 	void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
 	void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -330,10 +326,14 @@ struct ata_port_operations {
 
 	void (*bmdma_setup) (struct ata_queued_cmd *qc);
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
-	void (*fill_sg) (struct ata_queued_cmd *qc);
+
+	void (*qc_prep) (struct ata_queued_cmd *qc);
+	int (*qc_issue) (struct ata_queued_cmd *qc);
+
 	void (*eng_timeout) (struct ata_port *ap);
 
 	irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+	void (*irq_clear) (struct ata_port *);
 
 	u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
 	void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
@@ -349,6 +349,7 @@ struct ata_port_info {
 	Scsi_Host_Template	*sht;
 	unsigned long		host_flags;
 	unsigned long		pio_mask;
+	unsigned long		mwdma_mask;
 	unsigned long		udma_mask;
 	struct ata_port_operations	*port_ops;
 };
@@ -390,18 +391,25 @@ extern void ata_exec_command_mmio(struct
 extern int ata_port_start (struct ata_port *ap);
 extern void ata_port_stop (struct ata_port *ap);
 extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-extern void ata_fill_sg(struct ata_queued_cmd *qc);
+extern void ata_qc_prep(struct ata_queued_cmd *qc);
+extern int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf,
+		unsigned int buflen);
+extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
+		 unsigned int n_elem);
 extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s,
 			      unsigned int ofs, unsigned int len);
 extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc);
 extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc);
 extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc);
+extern void ata_bmdma_irq_clear(struct ata_port *ap);
 extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
 extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat);
 extern void ata_eng_timeout(struct ata_port *ap);
 extern void ata_add_to_probe_list (struct ata_probe_ent *probe_ent);
 extern int ata_std_bios_param(Disk * disk, kdev_t dev, int *ip);
+extern void libata_msleep(unsigned long msecs);
 
 
 static inline unsigned long msecs_to_jiffies(unsigned long msecs)
@@ -476,7 +484,6 @@ static inline u8 ata_wait_idle(struct at
 
 static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
 {
-	qc->flags &= ~ATA_QCFLAG_DMA;
 	qc->tf.ctl |= ATA_NIEN;
 }
 
@@ -502,6 +509,7 @@ static inline void ata_tf_init(struct at
 static inline u8 ata_irq_on(struct ata_port *ap)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u8 tmp;
 
 	ap->ctl &= ~ATA_NIEN;
 	ap->last_ctl = ap->ctl;
@@ -510,7 +518,11 @@ static inline u8 ata_irq_on(struct ata_p
 		writeb(ap->ctl, ioaddr->ctl_addr);
 	else
 		outb(ap->ctl, ioaddr->ctl_addr);
-	return ata_wait_idle(ap);
+	tmp = ata_wait_idle(ap);
+
+	ap->ops->irq_clear(ap);
+
+	return tmp;
 }
 
 static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
@@ -559,4 +571,44 @@ static inline unsigned int sata_dev_pres
 	return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
 }
 
+static inline void ata_bmdma_stop(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+
+		/* clear start/stop bit */
+		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+		      mmio + ATA_DMA_CMD);
+	} else {
+		/* clear start/stop bit */
+		outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+		    ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	}
+
+	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+	ata_altstatus(ap);	      /* dummy read */
+}
+
+static inline void ata_bmdma_ack_irq(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void *mmio = ((void *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
+		writeb(readb(mmio), mmio);
+	} else {
+		unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+		outb(inb(addr), addr);
+	}
+}
+
+static inline u8 ata_bmdma_status(struct ata_port *ap)
+{
+	u8 host_stat;
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+		host_stat = readb(mmio + ATA_DMA_STATUS);
+	} else
+		host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	return host_stat;
+}
+
 #endif /* __LINUX_LIBATA_H__ */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/linux/pci_ids.h linux-2.4.28-pre1/include/linux/pci_ids.h
--- linux-2.4.27/include/linux/pci_ids.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/linux/pci_ids.h	2004-08-15 19:49:36.000000000 +0000
@@ -606,6 +606,7 @@
 #define PCI_DEVICE_ID_HP_ZX1_IOC	0x122a
 #define PCI_DEVICE_ID_HP_PCIX_LBA	0x122e
 #define PCI_DEVICE_ID_HP_SX1000_IOC	0x127c
+#define PCI_DEVICE_ID_HP_CISS		0x3210
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/if_inet6.h linux-2.4.28-pre1/include/net/if_inet6.h
--- linux-2.4.27/include/net/if_inet6.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/net/if_inet6.h	2004-08-15 19:51:53.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *
  *	This program is free software; you can redistribute it and/or
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/ip6_fib.h linux-2.4.28-pre1/include/net/ip6_fib.h
--- linux-2.4.27/include/net/ip6_fib.h	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/include/net/ip6_fib.h	2004-08-15 19:51:03.000000000 +0000
@@ -2,7 +2,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/ipv6.h linux-2.4.28-pre1/include/net/ipv6.h
--- linux-2.4.27/include/net/ipv6.h	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.28-pre1/include/net/ipv6.h	2004-08-15 19:51:16.000000000 +0000
@@ -2,7 +2,7 @@
  *	Linux INET6 implementation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *
  *	$Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/neighbour.h linux-2.4.28-pre1/include/net/neighbour.h
--- linux-2.4.27/include/net/neighbour.h	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/include/net/neighbour.h	2004-08-15 19:51:53.000000000 +0000
@@ -5,7 +5,7 @@
  *	Generic neighbour manipulation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  */
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/sctp/command.h linux-2.4.28-pre1/include/net/sctp/command.h
--- linux-2.4.27/include/net/sctp/command.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/net/sctp/command.h	2004-08-15 19:51:13.000000000 +0000
@@ -94,6 +94,9 @@ typedef enum {
 	SCTP_CMD_REPORT_FWDTSN,	 /* Report new cumulative TSN Ack. */
 	SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */
 	SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */
+	SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */
+	SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */
+	SCTP_CMD_FORCE_PRIM_RETRAN,  /* Forces retrans. over primary path. */
 	SCTP_CMD_LAST
 } sctp_verb_t;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/sctp/constants.h linux-2.4.28-pre1/include/net/sctp/constants.h
--- linux-2.4.27/include/net/sctp/constants.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/net/sctp/constants.h	2004-08-15 19:47:25.000000000 +0000
@@ -175,6 +175,10 @@ typedef enum {
 	SCTP_IERROR_BAD_TAG,
 	SCTP_IERROR_BIG_GAP,
 	SCTP_IERROR_DUP_TSN,
+	SCTP_IERROR_HIGH_TSN,
+	SCTP_IERROR_IGNORE_TSN,
+	SCTP_IERROR_NO_DATA,
+	SCTP_IERROR_BAD_STREAM,
 
 } sctp_ierror_t;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/include/net/sctp/sm.h linux-2.4.28-pre1/include/net/sctp/sm.h
--- linux-2.4.27/include/net/sctp/sm.h	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/include/net/sctp/sm.h	2004-08-15 19:49:15.000000000 +0000
@@ -322,6 +322,9 @@ void sctp_send_stale_cookie_err(const st
 				const struct sctp_chunk *chunk,
 				sctp_cmd_seq_t *commands,
 				struct sctp_chunk *err_chunk);
+int sctp_eat_data(const struct sctp_association *asoc,
+		  struct sctp_chunk *chunk,
+		  sctp_cmd_seq_t *commands);
 
 /* 3rd level prototypes */
 __u32 sctp_generate_tag(const struct sctp_endpoint *);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/kernel/fork.c linux-2.4.28-pre1/kernel/fork.c
--- linux-2.4.27/kernel/fork.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.28-pre1/kernel/fork.c	2004-08-15 19:47:58.000000000 +0000
@@ -39,7 +39,7 @@ int last_pid;
 
 struct task_struct *pidhash[PIDHASH_SZ];
 
-void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -49,7 +49,7 @@ void add_wait_queue(wait_queue_head_t *q
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -59,7 +59,7 @@ void add_wait_queue_exclusive(wait_queue
 	wq_write_unlock_irqrestore(&q->lock, flags);
 }
 
-void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
+void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
@@ -264,7 +264,7 @@ struct mm_struct * mm_alloc(void)
  * is dropped: either by a lazy thread or by
  * mmput. Free the page directory and the mm.
  */
-inline void __mmdrop(struct mm_struct *mm)
+inline void fastcall __mmdrop(struct mm_struct *mm)
 {
 	BUG_ON(mm == &init_mm);
 	pgd_free(mm->pgd);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/kernel/panic.c linux-2.4.28-pre1/kernel/panic.c
--- linux-2.4.27/kernel/panic.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/kernel/panic.c	2004-08-15 19:51:46.000000000 +0000
@@ -59,7 +59,7 @@ NORET_TYPE void panic(const char * fmt, 
 	
 	bust_spinlocks(1);
 	va_start(args, fmt);
-	vsprintf(buf, fmt, args);
+	vsnprintf(buf, sizeof(buf), fmt, args);
 	va_end(args);
 	printk(KERN_EMERG "Kernel panic: %s\n",buf);
 	if (in_interrupt())
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/kernel/sched.c linux-2.4.28-pre1/kernel/sched.c
--- linux-2.4.27/kernel/sched.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/kernel/sched.c	2004-08-15 19:51:12.000000000 +0000
@@ -209,7 +209,7 @@ static inline int preemption_goodness(st
  */
 static FASTCALL(void reschedule_idle(struct task_struct * p));
 
-static void reschedule_idle(struct task_struct * p)
+static void fastcall reschedule_idle(struct task_struct * p)
 {
 #ifdef CONFIG_SMP
 	int this_cpu = smp_processor_id();
@@ -367,7 +367,7 @@ out:
 	return success;
 }
 
-inline int wake_up_process(struct task_struct * p)
+inline int fastcall wake_up_process(struct task_struct * p)
 {
 	return try_to_wake_up(p, 0);
 }
@@ -405,7 +405,7 @@ static void process_timeout(unsigned lon
  *
  * In all cases the return value is guaranteed to be non-negative.
  */
-signed long schedule_timeout(signed long timeout)
+signed long fastcall schedule_timeout(signed long timeout)
 {
 	struct timer_list timer;
 	unsigned long expire;
@@ -735,7 +735,7 @@ static inline void __wake_up_common (wai
 	}
 }
 
-void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr)
+void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode, int nr)
 {
 	if (q) {
 		unsigned long flags;
@@ -745,7 +745,7 @@ void __wake_up(wait_queue_head_t *q, uns
 	}
 }
 
-void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)
+void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)
 {
 	if (q) {
 		unsigned long flags;
@@ -755,7 +755,7 @@ void __wake_up_sync(wait_queue_head_t *q
 	}
 }
 
-void complete(struct completion *x)
+void fastcall complete(struct completion *x)
 {
 	unsigned long flags;
 
@@ -765,7 +765,7 @@ void complete(struct completion *x)
 	spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 
-void wait_for_completion(struct completion *x)
+void fastcall wait_for_completion(struct completion *x)
 {
 	spin_lock_irq(&x->wait.lock);
 	if (!x->done) {
@@ -800,7 +800,7 @@ void wait_for_completion(struct completi
 	__remove_wait_queue(q, &wait);				\
 	wq_write_unlock_irqrestore(&q->lock,flags);
 
-void interruptible_sleep_on(wait_queue_head_t *q)
+void fastcall interruptible_sleep_on(wait_queue_head_t *q)
 {
 	SLEEP_ON_VAR
 
@@ -811,7 +811,7 @@ void interruptible_sleep_on(wait_queue_h
 	SLEEP_ON_TAIL
 }
 
-long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
+long fastcall interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
 	SLEEP_ON_VAR
 
@@ -824,7 +824,7 @@ long interruptible_sleep_on_timeout(wait
 	return timeout;
 }
 
-void sleep_on(wait_queue_head_t *q)
+void fastcall sleep_on(wait_queue_head_t *q)
 {
 	SLEEP_ON_VAR
 	
@@ -835,7 +835,7 @@ void sleep_on(wait_queue_head_t *q)
 	SLEEP_ON_TAIL
 }
 
-long sleep_on_timeout(wait_queue_head_t *q, long timeout)
+long fastcall sleep_on_timeout(wait_queue_head_t *q, long timeout)
 {
 	SLEEP_ON_VAR
 	
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/kernel/softirq.c linux-2.4.28-pre1/kernel/softirq.c
--- linux-2.4.27/kernel/softirq.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.28-pre1/kernel/softirq.c	2004-08-15 19:48:42.000000000 +0000
@@ -111,7 +111,7 @@ restart:
 /*
  * This function must run with irq disabled!
  */
-inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr)
+inline fastcall void cpu_raise_softirq(unsigned int cpu, unsigned int nr)
 {
 	__cpu_raise_softirq(cpu, nr);
 
@@ -128,7 +128,7 @@ inline void cpu_raise_softirq(unsigned i
 		wakeup_softirqd(cpu);
 }
 
-void raise_softirq(unsigned int nr)
+void fastcall raise_softirq(unsigned int nr)
 {
 	unsigned long flags;
 
@@ -149,7 +149,7 @@ void open_softirq(int nr, void (*action)
 struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;
 struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
 
-void __tasklet_schedule(struct tasklet_struct *t)
+void fastcall __tasklet_schedule(struct tasklet_struct *t)
 {
 	int cpu = smp_processor_id();
 	unsigned long flags;
@@ -161,7 +161,7 @@ void __tasklet_schedule(struct tasklet_s
 	local_irq_restore(flags);
 }
 
-void __tasklet_hi_schedule(struct tasklet_struct *t)
+void fastcall __tasklet_hi_schedule(struct tasklet_struct *t)
 {
 	int cpu = smp_processor_id();
 	unsigned long flags;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/kernel/sysctl.c linux-2.4.28-pre1/kernel/sysctl.c
--- linux-2.4.27/kernel/sysctl.c	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/kernel/sysctl.c	2004-08-15 19:47:59.000000000 +0000
@@ -879,7 +879,7 @@ static int do_proc_dointvec(ctl_table *t
 				if (!isspace(c))
 					break;
 				left--;
-				((char *) buffer)++;
+				buffer++;
 			}
 			if (!left)
 				break;
@@ -1032,7 +1032,7 @@ int proc_dointvec_minmax(ctl_table *tabl
 				if (!isspace(c))
 					break;
 				left--;
-				((char *) buffer)++;
+				buffer++;
 			}
 			if (!left)
 				break;
@@ -1133,7 +1133,7 @@ static int do_proc_doulongvec_minmax(ctl
 				if (!isspace(c))
 					break;
 				left--;
-				((char *) buffer)++;
+				buffer++;
 			}
 			if (!left)
 				break;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/lib/brlock.c linux-2.4.28-pre1/lib/brlock.c
--- linux-2.4.27/lib/brlock.c	2001-11-09 22:11:15.000000000 +0000
+++ linux-2.4.28-pre1/lib/brlock.c	2004-08-15 19:50:53.000000000 +0000
@@ -20,7 +20,7 @@
 brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] =
    { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = RW_LOCK_UNLOCKED } };
 
-void __br_write_lock (enum brlock_indices idx)
+void fastcall __br_write_lock (enum brlock_indices idx)
 {
 	int i;
 
@@ -28,7 +28,7 @@ void __br_write_lock (enum brlock_indice
 		write_lock(&__brlock_array[cpu_logical_map(i)][idx]);
 }
 
-void __br_write_unlock (enum brlock_indices idx)
+void fastcall __br_write_unlock (enum brlock_indices idx)
 {
 	int i;
 
@@ -44,7 +44,7 @@ brlock_read_lock_t __brlock_array[NR_CPU
 struct br_wrlock __br_write_locks[__BR_IDX_MAX] =
    { [0 ... __BR_IDX_MAX-1] = { SPIN_LOCK_UNLOCKED } };
 
-void __br_write_lock (enum brlock_indices idx)
+void fastcall __br_write_lock (enum brlock_indices idx)
 {
 	int i;
 
@@ -59,7 +59,7 @@ again:
 		}
 }
 
-void __br_write_unlock (enum brlock_indices idx)
+void fastcall __br_write_unlock (enum brlock_indices idx)
 {
 	spin_unlock(&__br_write_locks[idx].lock);
 }
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/lib/crc32.c linux-2.4.28-pre1/lib/crc32.c
--- linux-2.4.27/lib/crc32.c	2004-04-14 13:05:40.000000000 +0000
+++ linux-2.4.28-pre1/lib/crc32.c	2004-08-15 19:47:18.000000000 +0000
@@ -99,7 +99,9 @@ u32 attribute((pure)) crc32_le(u32 crc, 
 	/* Align it */
 	if(unlikely(((long)b)&3 && len)){
 		do {
-			DO_CRC(*((u8 *)b)++);
+			u8 *p = (u8 *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
 		} while ((--len) && ((long)b)&3 );
 	}
 	if(likely(len >= 4)){
@@ -120,7 +122,9 @@ u32 attribute((pure)) crc32_le(u32 crc, 
 	/* And the last few bytes */
 	if(len){
 		do {
-			DO_CRC(*((u8 *)b)++);
+			u8 *p = (u8 *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
 		} while (--len);
 	}
 
@@ -200,7 +204,9 @@ u32 attribute((pure)) crc32_be(u32 crc, 
 	/* Align it */
 	if(unlikely(((long)b)&3 && len)){
 		do {
-			DO_CRC(*((u8 *)b)++);
+			u8 *p = (u8 *)b;
+			DO_CRC(*p++);
+			b = (u32 *)p;
 		} while ((--len) && ((long)b)&3 );
 	}
 	if(likely(len >= 4)){
@@ -221,7 +227,9 @@ u32 attribute((pure)) crc32_be(u32 crc, 
 	/* And the last few bytes */
 	if(len){
 		do {
-			DO_CRC(*((u8 *)b)++);
+			u8 *p = (u8 *)b;
+			DO_CRC(*p++);
+			b = (void *)p;
 		} while (--len);
 	}
 	return __be32_to_cpu(crc);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/lib/rwsem.c linux-2.4.28-pre1/lib/rwsem.c
--- linux-2.4.27/lib/rwsem.c	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/lib/rwsem.c	2004-08-15 19:47:37.000000000 +0000
@@ -160,7 +160,7 @@ static inline struct rw_semaphore *rwsem
 /*
  * wait for the read lock to be granted
  */
-struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_down_read_failed(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 
@@ -176,7 +176,7 @@ struct rw_semaphore *rwsem_down_read_fai
 /*
  * wait for the write lock to be granted
  */
-struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_down_write_failed(struct rw_semaphore *sem)
 {
 	struct rwsem_waiter waiter;
 
@@ -193,7 +193,7 @@ struct rw_semaphore *rwsem_down_write_fa
  * handle waking up a waiter on the semaphore
  * - up_read has decremented the active part of the count if we come here
  */
-struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
+struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem)
 {
 	rwsemtrace(sem,"Entering rwsem_wake");
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/lib/string.c linux-2.4.28-pre1/lib/string.c
--- linux-2.4.27/lib/string.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.28-pre1/lib/string.c	2004-08-15 19:51:28.000000000 +0000
@@ -380,14 +380,13 @@ void * memset(void * s,int c,size_t coun
  * You should not use this function to access IO space, use memcpy_toio()
  * or memcpy_fromio() instead.
  */
-char * bcopy(const char * src, char * dest, int count)
+void bcopy(const void * srcp, void * destp, size_t count)
 {
-	char *tmp = dest;
+	const char *src = srcp;
+	char *dest = destp;
 
 	while (count--)
-		*tmp++ = *src++;
-
-	return dest;
+		*dest++ = *src++;
 }
 #endif
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/filemap.c linux-2.4.28-pre1/mm/filemap.c
--- linux-2.4.27/mm/filemap.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/mm/filemap.c	2004-08-15 19:49:16.000000000 +0000
@@ -68,7 +68,7 @@ spinlock_cacheline_t pagemap_lru_lock_ca
 #define CLUSTER_OFFSET(x)	(((x) >> page_cluster) << page_cluster)
 
 static void FASTCALL(add_page_to_hash_queue(struct page * page, struct page **p));
-static void add_page_to_hash_queue(struct page * page, struct page **p)
+static void fastcall add_page_to_hash_queue(struct page * page, struct page **p)
 {
 	struct page *next = *p;
 
@@ -151,7 +151,7 @@ static inline int sync_page(struct page 
 /*
  * Add a page to the dirty page list.
  */
-void set_page_dirty(struct page *page)
+void fastcall set_page_dirty(struct page *page)
 {
 	if (!test_and_set_bit(PG_dirty, &page->flags)) {
 		struct address_space *mapping = page->mapping;
@@ -260,7 +260,7 @@ static void truncate_complete_page(struc
 }
 
 static int FASTCALL(truncate_list_pages(struct list_head *, unsigned long, unsigned *));
-static int truncate_list_pages(struct list_head *head, unsigned long start, unsigned *partial)
+static int fastcall truncate_list_pages(struct list_head *head, unsigned long start, unsigned *partial)
 {
 	struct list_head *curr;
 	struct page * page;
@@ -382,7 +382,7 @@ static inline int invalidate_this_page2(
 }
 
 static int FASTCALL(invalidate_list_pages2(struct list_head *));
-static int invalidate_list_pages2(struct list_head *head)
+static int fastcall invalidate_list_pages2(struct list_head *head)
 {
 	struct list_head *curr;
 	struct page * page;
@@ -755,7 +755,7 @@ int add_to_page_cache_unique(struct page
  * and schedules an I/O to read in its contents from disk.
  */
 static int FASTCALL(page_cache_read(struct file * file, unsigned long offset));
-static int page_cache_read(struct file * file, unsigned long offset)
+static int fastcall page_cache_read(struct file * file, unsigned long offset)
 {
 	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
 	struct page **hash = page_hash(mapping, offset);
@@ -790,7 +790,7 @@ static int page_cache_read(struct file *
  */
 static int FASTCALL(read_cluster_nonblocking(struct file * file, unsigned long offset,
 					     unsigned long filesize));
-static int read_cluster_nonblocking(struct file * file, unsigned long offset,
+static int fastcall read_cluster_nonblocking(struct file * file, unsigned long offset,
 	unsigned long filesize)
 {
 	unsigned long pages = CLUSTER_PAGES;
@@ -871,7 +871,7 @@ static inline wait_queue_head_t *page_wa
  * callbacks that would result into the blkdev layer waking
  * up the page after a queue unplug.
  */
-void wakeup_page_waiters(struct page * page)
+void fastcall wakeup_page_waiters(struct page * page)
 {
 	wait_queue_head_t * head;
 
@@ -927,7 +927,7 @@ void ___wait_on_page(struct page *page)
  * of the waiters for all of the pages in the appropriate
  * wait queue are woken.
  */
-void unlock_page(struct page *page)
+void fastcall unlock_page(struct page *page)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	ClearPageLaunder(page);
@@ -974,7 +974,7 @@ static void __lock_page(struct page *pag
  * Get an exclusive lock on the page, optimistically
  * assuming it's not locked..
  */
-void lock_page(struct page *page)
+void fastcall lock_page(struct page *page)
 {
 	if (TryLockPage(page))
 		__lock_page(page);
@@ -1025,7 +1025,7 @@ struct page *find_trylock_page(struct ad
  * during blocking operations..
  */
 static struct page * FASTCALL(__find_lock_page_helper(struct address_space *, unsigned long, struct page *));
-static struct page * __find_lock_page_helper(struct address_space *mapping,
+static struct page * fastcall __find_lock_page_helper(struct address_space *mapping,
 					unsigned long offset, struct page *hash)
 {
 	struct page *page;
@@ -1388,7 +1388,7 @@ static void generic_file_readahead(int r
  * If it was already so marked, move it to the active queue and drop
  * the referenced bit.  Otherwise, just mark it for future action..
  */
-void mark_page_accessed(struct page *page)
+void fastcall mark_page_accessed(struct page *page)
 {
 	if (!PageActive(page) && PageReferenced(page)) {
 		activate_page(page);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/highmem.c linux-2.4.28-pre1/mm/highmem.c
--- linux-2.4.27/mm/highmem.c	2003-06-13 14:51:39.000000000 +0000
+++ linux-2.4.28-pre1/mm/highmem.c	2004-08-15 19:50:35.000000000 +0000
@@ -129,7 +129,7 @@ start:
 	return vaddr;
 }
 
-void *kmap_high(struct page *page, int nonblocking)
+void fastcall *kmap_high(struct page *page, int nonblocking)
 {
 	unsigned long vaddr;
 
@@ -154,7 +154,7 @@ void *kmap_high(struct page *page, int n
 	return (void*) vaddr;
 }
 
-void kunmap_high(struct page *page)
+void fastcall kunmap_high(struct page *page)
 {
 	unsigned long vaddr;
 	unsigned long nr;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/memory.c linux-2.4.28-pre1/mm/memory.c
--- linux-2.4.27/mm/memory.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/mm/memory.c	2004-08-15 19:49:49.000000000 +0000
@@ -1396,7 +1396,7 @@ int handle_mm_fault(struct mm_struct *mm
  * On a two-level page table, this ends up actually being entirely
  * optimized away.
  */
-pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
+pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
 {
 	pmd_t *new;
 
@@ -1430,7 +1430,7 @@ out:
  * We've already handled the fast-path in-line, and we own the
  * page table lock.
  */
-pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+pte_t fastcall *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
 {
 	if (pmd_none(*pmd)) {
 		pte_t *new;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/oom_kill.c linux-2.4.28-pre1/mm/oom_kill.c
--- linux-2.4.27/mm/oom_kill.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.28-pre1/mm/oom_kill.c	2004-08-15 19:47:19.000000000 +0000
@@ -141,7 +141,7 @@ static struct task_struct * select_bad_p
  * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that
  * we select a process with CAP_SYS_RAW_IO set).
  */
-void oom_kill_task(struct task_struct *p)
+static void __oom_kill_task(struct task_struct *p)
 {
 	printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm);
 
@@ -161,6 +161,26 @@ void oom_kill_task(struct task_struct *p
 	}
 }
 
+static struct mm_struct *oom_kill_task(struct task_struct *p)
+{
+	struct mm_struct *mm;
+
+	task_lock(p);
+	mm = p->mm;
+	if (mm) {
+		spin_lock(&mmlist_lock);
+		if (atomic_read(&mm->mm_users))
+			atomic_inc(&mm->mm_users);
+		else
+			mm = NULL;
+		spin_unlock(&mmlist_lock);
+	}
+	task_unlock(p);
+	if (mm)
+		__oom_kill_task(p);
+	return mm;
+}
+
 /**
  * oom_kill - kill the "best" process when we run out of memory
  *
@@ -172,21 +192,27 @@ void oom_kill_task(struct task_struct *p
 static void oom_kill(void)
 {
 	struct task_struct *p, *q;
+	struct mm_struct *mm;
 
+retry:
 	read_lock(&tasklist_lock);
 	p = select_bad_process();
 
 	/* Found nothing?!?! Either we hang forever, or we panic. */
 	if (p == NULL)
 		panic("Out of memory and no killable processes...\n");
-
+	mm = oom_kill_task(p);
+	if (!mm) {
+		read_unlock(&tasklist_lock);
+		goto retry;
+	}
 	/* kill all processes that share the ->mm (i.e. all threads) */
 	for_each_task(q) {
-		if (q->mm == p->mm)
-			oom_kill_task(q);
+		if (q->mm == mm)
+			__oom_kill_task(q);
 	}
 	read_unlock(&tasklist_lock);
-
+	mmput(mm);
 	/*
 	 * Make kswapd go out of the way, so "p" has a good chance of
 	 * killing itself before someone else gets the chance to ask
@@ -263,7 +289,7 @@ void out_of_memory(void)
 	spin_lock(&oom_lock);
 
 reset:
-	if (first < now)
+	if ((long)first - (long)now < 0)
 		first = now;
 	count = 0;
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/page_alloc.c linux-2.4.28-pre1/mm/page_alloc.c
--- linux-2.4.27/mm/page_alloc.c	2004-08-07 23:26:06.000000000 +0000
+++ linux-2.4.28-pre1/mm/page_alloc.c	2004-08-15 19:47:51.000000000 +0000
@@ -109,7 +109,7 @@ static struct tq_struct free_pages_ok_no
  * -- wli
  */
 
-static void __free_pages_ok (struct page *page, unsigned int order)
+static void fastcall __free_pages_ok (struct page *page, unsigned int order)
 {
 	unsigned long index, page_idx, mask, flags;
 	free_area_t *area;
@@ -239,7 +239,7 @@ static inline struct page * expand (zone
 }
 
 static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order));
-static struct page * rmqueue(zone_t *zone, unsigned int order)
+static struct page * fastcall rmqueue(zone_t *zone, unsigned int order)
 {
 	free_area_t * area = zone->free_area + order;
 	unsigned int curr_order = order;
@@ -285,7 +285,7 @@ static struct page * rmqueue(zone_t *zon
 }
 
 #ifndef CONFIG_DISCONTIGMEM
-struct page *_alloc_pages(unsigned int gfp_mask, unsigned int order)
+struct page * fastcall _alloc_pages(unsigned int gfp_mask, unsigned int order)
 {
 	return __alloc_pages(gfp_mask, order,
 		contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK));
@@ -293,7 +293,7 @@ struct page *_alloc_pages(unsigned int g
 #endif
 
 static struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *));
-static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed)
+static struct page * fastcall balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed)
 {
 	struct page * page = NULL;
 	int __freed;
@@ -371,7 +371,7 @@ static inline unsigned long zone_free_pa
 /*
  * This is the 'heart' of the zoned buddy allocator:
  */
-struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)
+struct page * fastcall __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)
 {
 	zone_t **zone, * classzone;
 	struct page * page;
@@ -484,7 +484,7 @@ struct page * __alloc_pages(unsigned int
 /*
  * Common helper functions.
  */
-unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
+fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
 {
 	struct page * page;
 
@@ -494,7 +494,7 @@ unsigned long __get_free_pages(unsigned 
 	return (unsigned long) page_address(page);
 }
 
-unsigned long get_zeroed_page(unsigned int gfp_mask)
+fastcall unsigned long get_zeroed_page(unsigned int gfp_mask)
 {
 	struct page * page;
 
@@ -507,13 +507,13 @@ unsigned long get_zeroed_page(unsigned i
 	return 0;
 }
 
-void __free_pages(struct page *page, unsigned int order)
+fastcall void __free_pages(struct page *page, unsigned int order)
 {
 	if (!PageReserved(page) && put_page_testzero(page))
 		__free_pages_ok(page, order);
 }
 
-void free_pages(unsigned long addr, unsigned int order)
+fastcall void free_pages(unsigned long addr, unsigned int order)
 {
 	if (addr != 0)
 		__free_pages(virt_to_page(addr), order);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/slab.c linux-2.4.28-pre1/mm/slab.c
--- linux-2.4.27/mm/slab.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/mm/slab.c	2004-08-15 19:51:10.000000000 +0000
@@ -1735,7 +1735,7 @@ static void enable_all_cpucaches (void)
  *
  * Called from do_try_to_free_pages() and __alloc_pages()
  */
-int kmem_cache_reap (int gfp_mask)
+int fastcall kmem_cache_reap (int gfp_mask)
 {
 	slab_t *slabp;
 	kmem_cache_t *searchp;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/swap.c linux-2.4.28-pre1/mm/swap.c
--- linux-2.4.27/mm/swap.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/mm/swap.c	2004-08-15 19:49:29.000000000 +0000
@@ -44,7 +44,7 @@ static inline void activate_page_nolock(
 	}
 }
 
-void activate_page(struct page * page)
+void fastcall activate_page(struct page * page)
 {
 	spin_lock(&pagemap_lru_lock);
 	activate_page_nolock(page);
@@ -55,7 +55,7 @@ void activate_page(struct page * page)
  * lru_cache_add: add a page to the page lists
  * @page: the page to add
  */
-void lru_cache_add(struct page * page)
+void fastcall lru_cache_add(struct page * page)
 {
 	if (!PageLRU(page)) {
 		spin_lock(&pagemap_lru_lock);
@@ -72,7 +72,7 @@ void lru_cache_add(struct page * page)
  * This function is for when the caller already holds
  * the pagemap_lru_lock.
  */
-void __lru_cache_del(struct page * page)
+void fastcall __lru_cache_del(struct page * page)
 {
 	if (TestClearPageLRU(page)) {
 		if (PageActive(page)) {
@@ -87,7 +87,7 @@ void __lru_cache_del(struct page * page)
  * lru_cache_del: remove a page from the page lists
  * @page: the page to remove
  */
-void lru_cache_del(struct page * page)
+void fastcall lru_cache_del(struct page * page)
 {
 	spin_lock(&pagemap_lru_lock);
 	__lru_cache_del(page);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/swapfile.c linux-2.4.28-pre1/mm/swapfile.c
--- linux-2.4.27/mm/swapfile.c	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/mm/swapfile.c	2004-08-15 19:48:29.000000000 +0000
@@ -256,7 +256,7 @@ static int exclusive_swap_page(struct pa
  * work, but we opportunistically check whether
  * we need to get all the locks first..
  */
-int can_share_swap_page(struct page *page)
+int fastcall can_share_swap_page(struct page *page)
 {
 	int retval = 0;
 
@@ -284,7 +284,7 @@ int can_share_swap_page(struct page *pag
  * Work out if there are any other processes sharing this
  * swap cache page. Free it if you can. Return success.
  */
-int remove_exclusive_swap_page(struct page *page)
+int fastcall remove_exclusive_swap_page(struct page *page)
 {
 	int retval;
 	struct swap_info_struct * p;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/mm/vmscan.c linux-2.4.28-pre1/mm/vmscan.c
--- linux-2.4.27/mm/vmscan.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.28-pre1/mm/vmscan.c	2004-08-15 19:48:07.000000000 +0000
@@ -323,7 +323,7 @@ out_unlock:
 }
 
 static int FASTCALL(swap_out(zone_t * classzone));
-static int swap_out(zone_t * classzone)
+static int fastcall swap_out(zone_t * classzone)
 {
 	int counter, nr_pages = SWAP_CLUSTER_MAX;
 	struct mm_struct *mm;
@@ -366,7 +366,7 @@ empty:
 
 static void FASTCALL(refill_inactive(int nr_pages, zone_t * classzone));
 static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout));
-static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout)
+static int fastcall shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int * failed_swapout)
 {
 	struct list_head * entry;
 	int max_scan = (classzone->nr_inactive_pages + classzone->nr_active_pages) / vm_cache_scan_ratio;
@@ -577,7 +577,7 @@ page_mapped:
  * We move them the other way when we see the
  * reference bit on the page.
  */
-static void refill_inactive(int nr_pages, zone_t * classzone)
+static void fastcall refill_inactive(int nr_pages, zone_t * classzone)
 {
 	struct list_head * entry;
 	unsigned long ratio;
@@ -610,7 +610,7 @@ static void refill_inactive(int nr_pages
 }
 
 static int FASTCALL(shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout));
-static int shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout)
+static int fastcall shrink_caches(zone_t * classzone, unsigned int gfp_mask, int nr_pages, int * failed_swapout)
 {
 	nr_pages -= kmem_cache_reap(gfp_mask);
 	if (nr_pages <= 0)
@@ -627,7 +627,7 @@ out:
 
 static int check_classzone_need_balance(zone_t * classzone);
 
-int try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask)
+int fastcall try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask)
 {
 	gfp_mask = pf_gfp_mask(gfp_mask);
 
@@ -665,7 +665,7 @@ int try_to_free_pages_zone(zone_t *class
 	return 0;
 }
 
-int try_to_free_pages(unsigned int gfp_mask)
+int fastcall try_to_free_pages(unsigned int gfp_mask)
 {
 	pg_data_t *pgdat;
 	zonelist_t *zonelist;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/bluetooth/rfcomm/core.c linux-2.4.28-pre1/net/bluetooth/rfcomm/core.c
--- linux-2.4.27/net/bluetooth/rfcomm/core.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/net/bluetooth/rfcomm/core.c	2004-08-15 19:50:39.000000000 +0000
@@ -406,7 +406,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d
 	return len;
 }
 
-void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
@@ -417,7 +417,7 @@ void __rfcomm_dlc_throttle(struct rfcomm
 	rfcomm_schedule(RFCOMM_SCHED_TX);
 }
 
-void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
 {
 	BT_DBG("dlc %p state %ld", d, d->state);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/core/neighbour.c linux-2.4.28-pre1/net/core/neighbour.c
--- linux-2.4.27/net/core/neighbour.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.28-pre1/net/core/neighbour.c	2004-08-15 19:47:43.000000000 +0000
@@ -2,7 +2,7 @@
  *	Generic address resolution entity
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
  *	This program is free software; you can redistribute it and/or
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/addrconf.c linux-2.4.28-pre1/net/ipv6/addrconf.c
--- linux-2.4.27/net/ipv6/addrconf.c	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/addrconf.c	2004-08-15 19:51:43.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
  *	$Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/af_inet6.c linux-2.4.28-pre1/net/ipv6/af_inet6.c
--- linux-2.4.27/net/ipv6/af_inet6.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/af_inet6.c	2004-08-15 19:50:21.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/datagram.c linux-2.4.28-pre1/net/ipv6/datagram.c
--- linux-2.4.27/net/ipv6/datagram.c	2003-06-13 14:51:39.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/datagram.c	2004-08-15 19:47:56.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: datagram.c,v 1.23 2001/09/01 00:31:50 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/exthdrs.c linux-2.4.28-pre1/net/ipv6/exthdrs.c
--- linux-2.4.27/net/ipv6/exthdrs.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/exthdrs.c	2004-08-15 19:47:42.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *	Andi Kleen		<ak@muc.de>
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/icmp.c linux-2.4.28-pre1/net/ipv6/icmp.c
--- linux-2.4.27/net/ipv6/icmp.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/icmp.c	2004-08-15 19:49:02.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *
  *	$Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/ip6_fib.c linux-2.4.28-pre1/net/ipv6/ip6_fib.c
--- linux-2.4.27/net/ipv6/ip6_fib.c	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/ip6_fib.c	2004-08-15 19:51:15.000000000 +0000
@@ -3,7 +3,7 @@
  *	Forwarding Information Database
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/ip6_input.c linux-2.4.28-pre1/net/ipv6/ip6_input.c
--- linux-2.4.27/net/ipv6/ip6_input.c	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/ip6_input.c	2004-08-15 19:51:03.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>
+ *	Pedro Roque		<pedro_m@yahoo.com>
  *	Ian P. Morris		<I.P.Morris@soton.ac.uk>
  *
  *	$Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/ip6_output.c linux-2.4.28-pre1/net/ipv6/ip6_output.c
--- linux-2.4.27/net/ipv6/ip6_output.c	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/ip6_output.c	2004-08-15 19:47:48.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: ip6_output.c,v 1.33 2001/09/20 00:35:35 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/ipv6_sockglue.c linux-2.4.28-pre1/net/ipv6/ipv6_sockglue.c
--- linux-2.4.27/net/ipv6/ipv6_sockglue.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/ipv6_sockglue.c	2004-08-15 19:47:53.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/mcast.c linux-2.4.28-pre1/net/ipv6/mcast.c
--- linux-2.4.27/net/ipv6/mcast.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/mcast.c	2004-08-15 19:51:28.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/ndisc.c linux-2.4.28-pre1/net/ipv6/ndisc.c
--- linux-2.4.27/net/ipv6/ndisc.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/ndisc.c	2004-08-15 19:50:30.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *	Mike Shaver		<shaver@ingenia.com>
  *
  *	This program is free software; you can redistribute it and/or
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/protocol.c linux-2.4.28-pre1/net/ipv6/protocol.c
--- linux-2.4.27/net/ipv6/protocol.c	2001-05-20 00:56:43.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/protocol.c	2004-08-15 19:48:16.000000000 +0000
@@ -7,7 +7,7 @@
  *
  * Version:	$Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $
  *
- * Authors:	Pedro Roque	<roque@di.fc.ul.pt>
+ * Authors:	Pedro Roque	<pedro_m@yahoo.com>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/raw.c linux-2.4.28-pre1/net/ipv6/raw.c
--- linux-2.4.27/net/ipv6/raw.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/raw.c	2004-08-15 19:49:29.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/reassembly.c linux-2.4.28-pre1/net/ipv6/reassembly.c
--- linux-2.4.27/net/ipv6/reassembly.c	2003-08-25 11:44:44.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/reassembly.c	2004-08-15 19:49:08.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/route.c linux-2.4.28-pre1/net/ipv6/route.c
--- linux-2.4.27/net/ipv6/route.c	2004-02-18 13:36:32.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/route.c	2004-08-15 19:48:31.000000000 +0000
@@ -3,7 +3,7 @@
  *	FIB front-end.
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/sit.c linux-2.4.28-pre1/net/ipv6/sit.c
--- linux-2.4.27/net/ipv6/sit.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/sit.c	2004-08-15 19:51:41.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
  *	$Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/tcp_ipv6.c linux-2.4.28-pre1/net/ipv6/tcp_ipv6.c
--- linux-2.4.27/net/ipv6/tcp_ipv6.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/tcp_ipv6.c	2004-08-15 19:50:21.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	$Id: tcp_ipv6.c,v 1.142.2.1 2001/12/21 05:06:08 davem Exp $
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipv6/udp.c linux-2.4.28-pre1/net/ipv6/udp.c
--- linux-2.4.27/net/ipv6/udp.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/ipv6/udp.c	2004-08-15 19:51:18.000000000 +0000
@@ -3,7 +3,7 @@
  *	Linux INET6 implementation 
  *
  *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
+ *	Pedro Roque		<pedro_m@yahoo.com>	
  *
  *	Based on linux/ipv4/udp.c
  *
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/ipx/af_ipx.c linux-2.4.28-pre1/net/ipx/af_ipx.c
--- linux-2.4.27/net/ipx/af_ipx.c	2001-09-30 19:26:13.000000000 +0000
+++ linux-2.4.28-pre1/net/ipx/af_ipx.c	2004-08-15 19:48:16.000000000 +0000
@@ -1544,7 +1544,8 @@ static int ipxrtr_route_packet(struct so
 	ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
 	IPX_SKB_CB(skb)->ipx_tctrl = 0;
 	ipx->ipx_type 	 = usipx->sipx_type;
-	skb->h.raw 	 = (void *)skb->nh.ipxh = ipx;
+	skb->nh.ipxh	 = ipx;
+	skb->h.raw 	 = (void *)skb->nh.ipxh;
 
 	IPX_SKB_CB(skb)->last_hop.index = -1;
 #ifdef CONFIG_IPX_INTERN
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sched/sch_htb.c linux-2.4.28-pre1/net/sched/sch_htb.c
--- linux-2.4.27/net/sched/sch_htb.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sched/sch_htb.c	2004-08-15 19:47:27.000000000 +0000
@@ -77,7 +77,7 @@
 #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
 #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
 #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
-#define HTB_VER 0x30010	/* major must be matched with number suplied by TC as version */
+#define HTB_VER 0x30011	/* major must be matched with number suplied by TC as version */
 
 #if HTB_VER >> 16 != TC_HTB_PROTOVER
 #error "Mismatched sch_htb.c and pkt_sch.h"
@@ -172,6 +172,11 @@ struct htb_class
 	    struct htb_class_inner {
 		    rb_root_t feed[TC_HTB_NUMPRIO];	/* feed trees */
 		    rb_node_t *ptr[TC_HTB_NUMPRIO];	/* current class ptr */
+		    /* When class changes from state 1->2 and disconnects from 
+		       parent's feed then we lost ptr value and start from the
+		       first child again. Here we store classid of the
+		       last valid ptr (used when ptr is NULL). */
+		    u32 last_ptr_id[TC_HTB_NUMPRIO];
 	    } inner;
     } un;
     rb_node_t node[TC_HTB_NUMPRIO];	/* node for self or feed tree */
@@ -218,6 +223,7 @@ struct htb_sched
     rb_root_t row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
     int row_mask[TC_HTB_MAXDEPTH];
     rb_node_t *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
+    u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO];
 
     /* self wait list - roots of wait PQs per row */
     rb_root_t wait_pq[TC_HTB_MAXDEPTH];
@@ -576,8 +582,13 @@ static void htb_deactivate_prios(struct 
 			int prio = ffz(~m);
 			m &= ~(1 << prio);
 			
-			if (p->un.inner.ptr[prio] == cl->node+prio)
-				htb_next_rb_node(p->un.inner.ptr + prio);
+			if (p->un.inner.ptr[prio] == cl->node+prio) {
+				/* we are removing child which is pointed to from
+				   parent feed - forget the pointer but remember
+				   classid */
+				p->un.inner.last_ptr_id[prio] = cl->classid;
+				p->un.inner.ptr[prio] = NULL;
+			}
 			
 			htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio);
 			
@@ -908,25 +919,56 @@ static long htb_do_events(struct htb_sch
 	return HZ/10;
 }
 
+/* Returns class->node+prio from id-tree where classe's id is >= id. NULL
+   is no such one exists. */
+static rb_node_t *
+htb_id_find_next_upper(int prio,rb_node_t *n,u32 id)
+{
+	rb_node_t *r = NULL;
+	while (n) {
+		struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]);
+		if (id == cl->classid) return n;
+		
+		if (id > cl->classid) {
+			n = n->rb_right;
+		} else {
+			r = n;
+			n = n->rb_left;
+		}
+	}
+	return r;
+}
+
 /**
  * htb_lookup_leaf - returns next leaf class in DRR order
  *
  * Find leaf where current feed pointers points to.
  */
 static struct htb_class *
-htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr)
+htb_lookup_leaf(HTB_ARGQ rb_root_t *tree,int prio,rb_node_t **pptr,u32 *pid)
 {
 	int i;
 	struct {
 		rb_node_t *root;
 		rb_node_t **pptr;
+		u32 *pid;
 	} stk[TC_HTB_MAXDEPTH],*sp = stk;
 	
 	BUG_TRAP(tree->rb_node);
 	sp->root = tree->rb_node;
 	sp->pptr = pptr;
+	sp->pid = pid;
 
 	for (i = 0; i < 65535; i++) {
+		HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid);
+
+		if (!*sp->pptr && *sp->pid) { 
+			/* ptr was invalidated but id is valid - try to recover 
+			   the original or next ptr */
+			*sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid);
+		}
+		*sp->pid = 0; /* ptr is valid now so that remove this hint as it
+			         can become out of date quickly */
 		if (!*sp->pptr) { /* we are at right end; rewind & go up */
 			*sp->pptr = sp->root;
 			while ((*sp->pptr)->rb_left) 
@@ -944,6 +986,7 @@ htb_lookup_leaf(rb_root_t *tree,int prio
 				return cl;
 			(++sp)->root = cl->un.inner.feed[prio].rb_node;
 			sp->pptr = cl->un.inner.ptr+prio;
+			sp->pid = cl->un.inner.last_ptr_id+prio;
 		}
 	}
 	BUG_TRAP(0);
@@ -958,7 +1001,8 @@ htb_dequeue_tree(struct htb_sched *q,int
 	struct sk_buff *skb = NULL;
 	struct htb_class *cl,*start;
 	/* look initial class up in the row */
-	start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
+	start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,
+			q->ptr[level]+prio,q->last_ptr_id[level]+prio);
 	
 	do {
 next:
@@ -979,8 +1023,8 @@ next:
 			if ((q->row_mask[level] & (1 << prio)) == 0)
 				return NULL; 
 			
-			next = htb_lookup_leaf (q->row[level]+prio,
-					prio,q->ptr[level]+prio);
+			next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,
+					prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio);
 			if (cl == start) /* fix start if we just deleted it */
 				start = next;
 			cl = next;
@@ -995,7 +1039,8 @@ next:
 		}
 		q->nwc_hit++;
 		htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio);
-		cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
+		cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio,
+				q->last_ptr_id[level]+prio);
 	} while (cl != start);
 
 	if (likely(skb != NULL)) {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/associola.c linux-2.4.28-pre1/net/sctp/associola.c
--- linux-2.4.27/net/sctp/associola.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/associola.c	2004-08-15 19:49:28.000000000 +0000
@@ -1108,6 +1108,7 @@ static inline int sctp_peer_needs_update
 	case SCTP_STATE_ESTABLISHED:
 	case SCTP_STATE_SHUTDOWN_PENDING:
 	case SCTP_STATE_SHUTDOWN_RECEIVED:
+	case SCTP_STATE_SHUTDOWN_SENT:
 		if ((asoc->rwnd > asoc->a_rwnd) &&
 		    ((asoc->rwnd - asoc->a_rwnd) >=
 		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/inqueue.c linux-2.4.28-pre1/net/sctp/inqueue.c
--- linux-2.4.27/net/sctp/inqueue.c	2004-04-14 13:05:41.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/inqueue.c	2004-08-15 19:49:28.000000000 +0000
@@ -81,7 +81,7 @@ void sctp_inq_free(struct sctp_inq *queu
 	struct sctp_chunk *chunk;
 
 	/* Empty the queue.  */
-	while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)))
+	while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL)
 		sctp_chunk_free(chunk);
 
 	/* If there is a packet which is currently being worked on,
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/output.c linux-2.4.28-pre1/net/sctp/output.c
--- linux-2.4.27/net/sctp/output.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/output.c	2004-08-15 19:49:48.000000000 +0000
@@ -133,7 +133,7 @@ void sctp_packet_free(struct sctp_packet
 
 	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
 
-        while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
+        while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL)
 		sctp_chunk_free(chunk);
 
 	if (packet->malloced)
@@ -370,7 +370,7 @@ int sctp_packet_transmit(struct sctp_pac
 	 * [This whole comment explains WORD_ROUND() below.]
 	 */
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
-	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
+	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
 		if (sctp_chunk_is_data(chunk)) {
 
 			if (!chunk->has_tsn) {
@@ -511,7 +511,7 @@ err:
 	 * will get resent or dropped later.
 	 */
 
-	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
+	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
 		if (!sctp_chunk_is_data(chunk))
     			sctp_chunk_free(chunk);
 	}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/outqueue.c linux-2.4.28-pre1/net/sctp/outqueue.c
--- linux-2.4.27/net/sctp/outqueue.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/outqueue.c	2004-08-15 19:48:45.000000000 +0000
@@ -245,7 +245,7 @@ void sctp_outq_teardown(struct sctp_outq
 	/* Throw away unacknowledged chunks. */
 	list_for_each(pos, &q->asoc->peer.transport_addr_list) {
 		transport = list_entry(pos, struct sctp_transport, transports);
-		while ((lchunk = sctp_list_dequeue(&transport->transmitted))) {
+		while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) {
 			chunk = list_entry(lchunk, struct sctp_chunk,
 					   transmitted_list);
 			/* Mark as part of a failed message. */
@@ -282,7 +282,7 @@ void sctp_outq_teardown(struct sctp_outq
 	}
 
 	/* Throw away any leftover data chunks. */
-	while ((chunk = sctp_outq_dequeue_data(q))) {
+	while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
 
 		/* Mark as send failure. */
 		sctp_chunk_fail(chunk, q->error);
@@ -292,7 +292,7 @@ void sctp_outq_teardown(struct sctp_outq
 	q->error = 0;
 
 	/* Throw away any leftover control chunks. */
-	while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)))
+	while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL)
 		sctp_chunk_free(chunk);
 }
 
@@ -525,10 +525,10 @@ static int sctp_outq_flush_rtx(struct sc
 			       int rtx_timeout, int *start_timer)
 {
 	struct list_head *lqueue;
-	struct list_head *lchunk;
+	struct list_head *lchunk, *lchunk1;
 	struct sctp_transport *transport = pkt->transport;
 	sctp_xmit_t status;
-	struct sctp_chunk *chunk;
+	struct sctp_chunk *chunk, *chunk1;
 	struct sctp_association *asoc;
 	int error = 0;
 
@@ -615,6 +615,12 @@ static int sctp_outq_flush_rtx(struct sc
 			 * the transmitted list.
 			 */
 			list_add_tail(lchunk, &transport->transmitted);
+
+			/* Mark the chunk as ineligible for fast retransmit 
+			 * after it is retransmitted.
+			 */
+			chunk->fast_retransmit = 0;
+
 			*start_timer = 1;
 			q->empty = 0;
 
@@ -622,6 +628,18 @@ static int sctp_outq_flush_rtx(struct sc
 			lchunk = sctp_list_dequeue(lqueue);
 			break;
 		};
+
+		/* If we are here due to a retransmit timeout or a fast
+		 * retransmit and if there are any chunks left in the retransmit
+		 * queue that could not fit in the PMTU sized packet, they need			 * to be marked as ineligible for a subsequent fast retransmit.
+		 */
+		if (rtx_timeout && !lchunk) {
+			list_for_each(lchunk1, lqueue) {
+				chunk1 = list_entry(lchunk1, struct sctp_chunk,
+						    transmitted_list);
+				chunk1->fast_retransmit = 0;
+			}
+		}
 	}
 
 	return error;
@@ -681,7 +699,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 	 */
 
 	queue = &q->control;
-	while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) {
+	while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) {
 		/* Pick the right transport to use. */
 		new_transport = chunk->transport;
 
@@ -812,7 +830,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 		start_timer = 0;
 		queue = &q->out;
 
-		while ((chunk = sctp_outq_dequeue_data(q))) {
+		while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
 			/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
 			 * stream identifier.
 			 */
@@ -866,7 +884,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 			SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head "
 					"%p skb->users %d.\n",
 					ntohl(chunk->subh.data_hdr->tsn),
-					chunk->skb ?chunk->skb->head : 0,
+					chunk->skb ?chunk->skb->head : NULL,
 					chunk->skb ?
 					atomic_read(&chunk->skb->users) : -1);
 
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/protocol.c linux-2.4.28-pre1/net/sctp/protocol.c
--- linux-2.4.27/net/sctp/protocol.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/protocol.c	2004-08-15 19:50:10.000000000 +0000
@@ -97,7 +97,7 @@ __init int sctp_proc_init(void)
 {
 	if (!proc_net_sctp) {
 		struct proc_dir_entry *ent;
-		ent = proc_mkdir("net/sctp", 0);
+		ent = proc_mkdir("net/sctp", NULL);
 		if (ent) {
 			ent->owner = THIS_MODULE;
 			proc_net_sctp = ent;
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/sm_sideeffect.c linux-2.4.28-pre1/net/sctp/sm_sideeffect.c
--- linux-2.4.27/net/sctp/sm_sideeffect.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/sm_sideeffect.c	2004-08-15 19:50:33.000000000 +0000
@@ -529,6 +529,23 @@ static void sctp_cmd_hb_timers_stop(sctp
 	}
 }
 
+/* Helper function to stop any pending T3-RTX timers */
+static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds,
+				        struct sctp_association *asoc)
+{
+	struct sctp_transport *t;
+	struct list_head *pos;
+
+	list_for_each(pos, &asoc->peer.transport_addr_list) {
+		t = list_entry(pos, struct sctp_transport, transports);
+		if (timer_pending(&t->T3_rtx_timer) &&
+		    del_timer(&t->T3_rtx_timer)) {
+			sctp_transport_put(t);
+		}
+	}
+}
+
+
 /* Helper function to update the heartbeat timer. */
 static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
 				     struct sctp_association *asoc,
@@ -749,6 +766,26 @@ static void sctp_cmd_process_fwdtsn(stru
 	return;
 }
 
+/* Helper function to remove the association non-primary peer 
+ * transports.
+ */ 
+static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
+{
+	struct sctp_transport *t;
+	struct list_head *pos;
+	struct list_head *temp;
+
+	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
+		t = list_entry(pos, struct sctp_transport, transports);
+		if (!sctp_cmp_addr_exact(&t->ipaddr,
+		                         &asoc->peer.primary_addr)) {
+			sctp_assoc_del_peer(asoc, &t->ipaddr);
+		}
+	}
+
+	return;
+}
+
 /* These three macros allow us to pull the debugging code out of the
  * main flow of sctp_do_sm() to keep attention focused on the real
  * functionality there.
@@ -1048,6 +1085,27 @@ int sctp_cmd_interpreter(sctp_event_t ev
 			if (cmd->obj.ptr)
 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
 						SCTP_CHUNK(cmd->obj.ptr));
+
+			/* FIXME - Eventually come up with a cleaner way to
+			 * enabling COOKIE-ECHO + DATA bundling during 
+			 * multihoming stale cookie scenarios, the following 
+			 * command plays with asoc->peer.retran_path to 
+			 * avoid the problem of sending the COOKIE-ECHO and 
+			 * DATA in different paths, which could result 
+			 * in the association being ABORTed if the DATA chunk 
+			 * is processed first by the server.  Checking the
+			 * init error counter simply causes this command
+			 * to be executed only during failed attempts of
+			 * association establishment.
+			 */
+			if ((asoc->peer.retran_path != 
+			     asoc->peer.primary_path) && 
+			    (asoc->counters[SCTP_COUNTER_INIT_ERROR] > 0)) {
+				sctp_add_cmd_sf(commands, 
+				                SCTP_CMD_FORCE_PRIM_RETRAN,
+						SCTP_NULL());
+			}
+
 			break;
 
 		case SCTP_CMD_GEN_SHUTDOWN:
@@ -1282,6 +1340,19 @@ int sctp_cmd_interpreter(sctp_event_t ev
 		case SCTP_CMD_CLEAR_INIT_TAG:
 			asoc->peer.i.init_tag = 0;
 			break;
+		case SCTP_CMD_DEL_NON_PRIMARY:
+			sctp_cmd_del_non_primary(asoc);
+			break;
+		case SCTP_CMD_T3_RTX_TIMERS_STOP:
+			sctp_cmd_t3_rtx_timers_stop(commands, asoc);
+			break;
+		case SCTP_CMD_FORCE_PRIM_RETRAN:
+			t = asoc->peer.retran_path;
+			asoc->peer.retran_path = asoc->peer.primary_path;
+			error = sctp_outq_uncork(&asoc->outqueue);
+			local_cork = 0;
+			asoc->peer.retran_path = t;
+			break;
 		default:
 			printk(KERN_WARNING "Impossible command: %u, %p\n",
 			       cmd->verb, cmd->obj.ptr);
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/sm_statefuns.c linux-2.4.28-pre1/net/sctp/sm_statefuns.c
--- linux-2.4.27/net/sctp/sm_statefuns.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/sm_statefuns.c	2004-08-15 19:49:48.000000000 +0000
@@ -472,8 +472,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(c
 	 */
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
-	sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET,
-			SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -674,6 +672,15 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(co
 	if (!sctp_vtag_verify(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
+	/* Reset init error count upon receipt of COOKIE-ACK,
+	 * to avoid problems with the managemement of this
+	 * counter in stale cookie situations when a transition back
+	 * from the COOKIE-ECHOED state to the COOKIE-WAIT
+	 * state is performed.
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET,
+	                SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
+
 	/* RFC 2960 5.1 Normal Establishment of an Association
 	 *
 	 * E) Upon reception of the COOKIE ACK, endpoint "A" will move
@@ -995,7 +1002,7 @@ static int sctp_sf_check_restart_addrs(c
 	/* Search through all current addresses and make sure
 	 * we aren't adding any new ones.
 	 */
-	new_addr = 0;
+	new_addr = NULL;
 	found = 0;
 
 	list_for_each(pos, &new_asoc->peer.transport_addr_list) {
@@ -1872,8 +1879,6 @@ sctp_disposition_t sctp_sf_do_5_2_6_stal
 	time_t stale;
 	sctp_cookie_preserve_param_t bht;
 	sctp_errhdr_t *err;
-	struct list_head *pos;
-	struct sctp_transport *t;
 	struct sctp_chunk *reply;
 	struct sctp_bind_addr *bp;
 	int attempts;
@@ -1920,20 +1925,27 @@ sctp_disposition_t sctp_sf_do_5_2_6_stal
 	/* Clear peer's init_tag cached in assoc as we are sending a new INIT */
 	sctp_add_cmd_sf(commands, SCTP_CMD_CLEAR_INIT_TAG, SCTP_NULL());
 
+	/* Stop pending T3-rtx and heartbeat timers */
+	sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL());
+	sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL());
+
+	/* Delete non-primary peer ip addresses since we are transitioning
+	 * back to the COOKIE-WAIT state
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL());
+
+	/* If we've sent any data bundled with COOKIE-ECHO we will need to 
+	 * resend 
+	 */
+	sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, 
+			SCTP_TRANSPORT(asoc->peer.primary_path));
+
 	/* Cast away the const modifier, as we want to just
 	 * rerun it through as a sideffect.
 	 */
 	sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC,
 			SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR));
 
-	/* If we've sent any data bundled with COOKIE-ECHO we need to
-	 * resend.
-	 */
-	list_for_each(pos, &asoc->peer.transport_addr_list) {
-		t = list_entry(pos, struct sctp_transport, transports);
-		sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(t));
-	}
-
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
@@ -2321,12 +2333,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(
 					sctp_cmd_seq_t *commands)
 {
 	struct sctp_chunk *chunk = arg;
-	sctp_datahdr_t *data_hdr;
-	struct sctp_chunk *err;
-	size_t datalen;
-	sctp_verb_t deliver;
-	int tmp;
-	__u32 tsn;
+	int error;
 
 	if (!sctp_vtag_verify(chunk, asoc)) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -2334,158 +2341,22 @@ sctp_disposition_t sctp_sf_eat_data_6_2(
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
         }
 
-	data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
-	skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
-
-	tsn = ntohl(data_hdr->tsn);
-	SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
-
-	/* ASSERT:  Now skb->data is really the user data.  */
-
-	/* Process ECN based congestion.
-	 *
-	 * Since the chunk structure is reused for all chunks within
-	 * a packet, we use ecn_ce_done to track if we've already
-	 * done CE processing for this packet.
-	 *
-	 * We need to do ECN processing even if we plan to discard the
-	 * chunk later.
-	 */
-
-	if (!chunk->ecn_ce_done) {
-		struct sctp_af *af;
-		chunk->ecn_ce_done = 1;
-
-		af = sctp_get_af_specific(
-			ipver2af(chunk->skb->nh.iph->version));
-
-		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
-			/* Do real work as sideffect. */
-			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
-					SCTP_U32(tsn));
-		}
-	}
-
-	tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
-	if (tmp < 0) {
-		/* The TSN is too high--silently discard the chunk and
-		 * count on it getting retransmitted later.
-		 */
+	error = sctp_eat_data(asoc, chunk, commands );
+	switch (error) {
+	case SCTP_IERROR_NO_ERROR:
+		break;
+	case SCTP_IERROR_HIGH_TSN:
+	case SCTP_IERROR_BAD_STREAM:
 		goto discard_noforce;
-	} else if (tmp > 0) {
-		/* This is a duplicate.  Record it.  */
-		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
+	case SCTP_IERROR_DUP_TSN:
+	case SCTP_IERROR_IGNORE_TSN:
 		goto discard_force;
+	case SCTP_IERROR_NO_DATA:
+		goto consume;
+	default:
+		BUG();
 	}
 
-	/* This is a new TSN.  */
-
-	/* Discard if there is no room in the receive window.
-	 * Actually, allow a little bit of overflow (up to a MTU).
-	 */
-	datalen = ntohs(chunk->chunk_hdr->length);
-	datalen -= sizeof(sctp_data_chunk_t);
-
-	deliver = SCTP_CMD_CHUNK_ULP;
-
-	/* Think about partial delivery. */
-	if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
-
-		/* Even if we don't accept this chunk there is
-		 * memory pressure.
-		 */
-		sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
-	}
-
-        /* Spill over rwnd a little bit.  Note: While allowed, this spill over
-	 * seems a bit troublesome in that frag_point varies based on
-	 * PMTU.  In cases, such as loopback, this might be a rather
-	 * large spill over.
-	 */
-	if (!asoc->rwnd || asoc->rwnd_over ||
-	    (datalen > asoc->rwnd + asoc->frag_point)) {
-
-		/* If this is the next TSN, consider reneging to make
-		 * room.   Note: Playing nice with a confused sender.  A
-		 * malicious sender can still eat up all our buffer
-		 * space and in the future we may want to detect and
-		 * do more drastic reneging.
-		 */
-		if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
-		    (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
-			SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
-			deliver = SCTP_CMD_RENEGE;
-		} else {
-			SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
-					  "rwnd: %d\n", tsn, datalen,
-					  asoc->rwnd);
-			goto discard_force;
-		}
-	}
-
-	/*
-	 * Section 3.3.10.9 No User Data (9)
-	 *
-	 * Cause of error
-	 * ---------------
-	 * No User Data:  This error cause is returned to the originator of a
-	 * DATA chunk if a received DATA chunk has no user data.
-	 */
-	if (unlikely(0 == datalen)) {
-		err = sctp_make_abort_no_data(asoc, chunk, tsn);
-		if (err) {
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(err));
-		}
-		/* We are going to ABORT, so we might as well stop
-		 * processing the rest of the chunks in the packet.
-		 */
-		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-				SCTP_U32(SCTP_ERROR_NO_DATA));
-		SCTP_INC_STATS(SctpAborteds);
-		SCTP_DEC_STATS(SctpCurrEstab);
-		return SCTP_DISPOSITION_CONSUME;
-	}
-
-	/* If definately accepting the DATA chunk, record its TSN, otherwise
-	 * wait for renege processing.
-	 */
-	if (SCTP_CMD_CHUNK_ULP == deliver)
-		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
-
-	/* Note: Some chunks may get overcounted (if we drop) or overcounted
-	 * if we renege and the chunk arrives again.
-	 */
-	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-		SCTP_INC_STATS(SctpInUnorderChunks);
-	else
-		SCTP_INC_STATS(SctpInOrderChunks);
-
-	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
-	 *
-	 * If an endpoint receive a DATA chunk with an invalid stream
-	 * identifier, it shall acknowledge the reception of the DATA chunk
-	 * following the normal procedure, immediately send an ERROR chunk
-	 * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
-	 * and discard the DATA chunk.
-	 */
-	if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
-		err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
-					 &data_hdr->stream,
-					 sizeof(data_hdr->stream));
-		if (err)
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(err));
-		goto discard_noforce;
-	}
-
-	/* Send the data up to the user.  Note:  Schedule  the
-	 * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
-	 * chunk needs the updated rwnd.
-	 */
-	sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
-
 	if (asoc->autoclose) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
 				SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
@@ -2551,6 +2422,9 @@ discard_noforce:
 				SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
 	}
 	return SCTP_DISPOSITION_DISCARD;
+consume:
+	return SCTP_DISPOSITION_CONSUME;
+	
 }
 
 /*
@@ -2576,11 +2450,7 @@ sctp_disposition_t sctp_sf_eat_data_fast
 				     sctp_cmd_seq_t *commands)
 {
 	struct sctp_chunk *chunk = arg;
-	sctp_datahdr_t *data_hdr;
-	struct sctp_chunk *err;
-	size_t datalen;
-	int tmp;
-	__u32 tsn;
+	int error;
 
 	if (!sctp_vtag_verify(chunk, asoc)) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -2588,110 +2458,23 @@ sctp_disposition_t sctp_sf_eat_data_fast
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 	}
 
-	data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *) chunk->skb->data;
-	skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
-
-	tsn = ntohl(data_hdr->tsn);
-
-	SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
-
-	/* ASSERT:  Now skb->data is really the user data.  */
-
-	/* Process ECN based congestion.
-	 *
-	 * Since the chunk structure is reused for all chunks within
-	 * a packet, we use ecn_ce_done to track if we've already
-	 * done CE processing for this packet.
-	 *
-	 * We need to do ECN processing even if we plan to discard the
-	 * chunk later.
-	 */
-	if (!chunk->ecn_ce_done) {
-		struct sctp_af *af;
-		chunk->ecn_ce_done = 1;
-
-		af = sctp_get_af_specific(
-			ipver2af(chunk->skb->nh.iph->version));
-
-		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
-			/* Do real work as sideffect. */
-			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
-					SCTP_U32(tsn));
-		}
-	}
-
-	tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
-	if (tmp < 0) {
-		/* The TSN is too high--silently discard the chunk and
-		 * count on it getting retransmitted later.
-		 */
-		goto gen_shutdown;
-	} else if (tmp > 0) {
-		/* This is a duplicate.  Record it.  */
-		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
-		goto gen_shutdown;
-	}
-
-	/* This is a new TSN.  */
 
-	datalen = ntohs(chunk->chunk_hdr->length);
-	datalen -= sizeof(sctp_data_chunk_t);
-
-	/*
-	 * Section 3.3.10.9 No User Data (9)
-	 *
-	 * Cause of error
-	 * ---------------
-	 * No User Data:  This error cause is returned to the originator of a
-	 * DATA chunk if a received DATA chunk has no user data.
-	 */
-	if (unlikely(0 == datalen)) {
-		err = sctp_make_abort_no_data(asoc, chunk, tsn);
-		if (err) {
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(err));
-		}
-		/* We are going to ABORT, so we might as well stop
-		 * processing the rest of the chunks in the packet.
-		 */
-		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
-				SCTP_U32(SCTP_ERROR_NO_DATA));
-		SCTP_INC_STATS(SctpAborteds);
-		SCTP_DEC_STATS(SctpCurrEstab);
-		return SCTP_DISPOSITION_CONSUME;
-	}
-
-	/* We are accepting this DATA chunk. */
-
-	/* Record the fact that we have received this TSN.  */
-	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
-
-	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-		SCTP_INC_STATS(SctpInUnorderChunks);
-	else
-		SCTP_INC_STATS(SctpInOrderChunks);
-
-	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
-	 *
-	 * If an endpoint receive a DATA chunk with an invalid stream
-	 * identifier, it shall acknowledge the reception of the DATA chunk
-	 * following the normal procedure, immediately send an ERROR chunk
-	 * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
-	 * and discard the DATA chunk.
-	 */
-	if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
-		err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
-					 &data_hdr->stream,
-					 sizeof(data_hdr->stream));
-		if (err) {
-			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-					SCTP_CHUNK(err));
-		}
+	error = sctp_eat_data(asoc, chunk, commands );
+	switch (error) {
+	case SCTP_IERROR_NO_ERROR:
+	case SCTP_IERROR_HIGH_TSN:
+	case SCTP_IERROR_DUP_TSN:
+	case SCTP_IERROR_IGNORE_TSN:
+	case SCTP_IERROR_BAD_STREAM:
+		break;
+	case SCTP_IERROR_NO_DATA:
+		goto consume;
+	default:
+		BUG();
 	}
 
 	/* Go a head and force a SACK, since we are shutting down. */
-gen_shutdown:
+
 	/* Implementor's Guide.
 	 *
 	 * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
@@ -2707,6 +2490,8 @@ gen_shutdown:
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
 				SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
 	}
+
+consume:
 	return SCTP_DISPOSITION_CONSUME;
 }
 
@@ -4709,7 +4494,7 @@ struct sctp_sackhdr *sctp_sm_pull_sack(s
 	num_blocks = ntohs(sack->num_gap_ack_blocks);
 	num_dup_tsns = ntohs(sack->num_dup_tsns);
 	len = sizeof(struct sctp_sackhdr);
-	len = (num_blocks + num_dup_tsns) * sizeof(__u32);
+	len += (num_blocks + num_dup_tsns) * sizeof(__u32);
 	if (len > chunk->skb->len)
 		return NULL;
 
@@ -4848,3 +4633,171 @@ void sctp_send_stale_cookie_err(const st
 			sctp_chunk_free (err_chunk);
 	}
 }
+
+
+/* Process a data chunk */
+int sctp_eat_data(const struct sctp_association *asoc,
+		  struct sctp_chunk *chunk,
+		  sctp_cmd_seq_t *commands)
+{
+	sctp_datahdr_t *data_hdr;
+	struct sctp_chunk *err;
+	size_t datalen;
+	sctp_verb_t deliver;
+	int tmp;
+	__u32 tsn;
+
+	data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
+	skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
+
+	tsn = ntohl(data_hdr->tsn);
+	SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
+
+	/* ASSERT:  Now skb->data is really the user data.  */
+
+	/* Process ECN based congestion.
+	 *
+	 * Since the chunk structure is reused for all chunks within
+	 * a packet, we use ecn_ce_done to track if we've already
+	 * done CE processing for this packet.
+	 *
+	 * We need to do ECN processing even if we plan to discard the
+	 * chunk later.
+	 */
+
+	if (!chunk->ecn_ce_done) {
+		struct sctp_af *af;
+		chunk->ecn_ce_done = 1;
+
+		af = sctp_get_af_specific(
+			ipver2af(chunk->skb->nh.iph->version));
+
+		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
+			/* Do real work as sideffect. */
+			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
+					SCTP_U32(tsn));
+		}
+	}
+
+	tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn);
+	if (tmp < 0) {
+		/* The TSN is too high--silently discard the chunk and
+		 * count on it getting retransmitted later.
+		 */
+		return SCTP_IERROR_HIGH_TSN;
+	} else if (tmp > 0) {
+		/* This is a duplicate.  Record it.  */
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn));
+		return SCTP_IERROR_DUP_TSN;
+	}
+
+	/* This is a new TSN.  */
+
+	/* Discard if there is no room in the receive window.
+	 * Actually, allow a little bit of overflow (up to a MTU).
+	 */
+	datalen = ntohs(chunk->chunk_hdr->length);
+	datalen -= sizeof(sctp_data_chunk_t);
+
+	deliver = SCTP_CMD_CHUNK_ULP;
+
+	/* Think about partial delivery. */
+	if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
+
+		/* Even if we don't accept this chunk there is
+		 * memory pressure.
+		 */
+		sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
+	}
+
+        /* Spill over rwnd a little bit.  Note: While allowed, this spill over
+	 * seems a bit troublesome in that frag_point varies based on
+	 * PMTU.  In cases, such as loopback, this might be a rather
+	 * large spill over.
+	 */
+	if (!asoc->rwnd || asoc->rwnd_over ||
+	    (datalen > asoc->rwnd + asoc->frag_point)) {
+
+		/* If this is the next TSN, consider reneging to make
+		 * room.   Note: Playing nice with a confused sender.  A
+		 * malicious sender can still eat up all our buffer
+		 * space and in the future we may want to detect and
+		 * do more drastic reneging.
+		 */
+		if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
+		    (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
+			SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
+			deliver = SCTP_CMD_RENEGE;
+		} else {
+			SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
+					  "rwnd: %d\n", tsn, datalen,
+					  asoc->rwnd);
+			return SCTP_IERROR_IGNORE_TSN;
+		}
+	}
+
+	/*
+	 * Section 3.3.10.9 No User Data (9)
+	 *
+	 * Cause of error
+	 * ---------------
+	 * No User Data:  This error cause is returned to the originator of a
+	 * DATA chunk if a received DATA chunk has no user data.
+	 */
+	if (unlikely(0 == datalen)) {
+		err = sctp_make_abort_no_data(asoc, chunk, tsn);
+		if (err) {
+			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+					SCTP_CHUNK(err));
+		}
+		/* We are going to ABORT, so we might as well stop
+		 * processing the rest of the chunks in the packet.
+		 */
+		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+				SCTP_U32(SCTP_ERROR_NO_DATA));
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
+		return SCTP_IERROR_NO_DATA;
+	}
+
+	/* If definately accepting the DATA chunk, record its TSN, otherwise
+	 * wait for renege processing.
+	 */
+	if (SCTP_CMD_CHUNK_ULP == deliver)
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
+
+	/* Note: Some chunks may get overcounted (if we drop) or overcounted
+	 * if we renege and the chunk arrives again.
+	 */
+	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+		SCTP_INC_STATS(SctpInUnorderChunks);
+	else
+		SCTP_INC_STATS(SctpInOrderChunks);
+
+	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
+	 *
+	 * If an endpoint receive a DATA chunk with an invalid stream
+	 * identifier, it shall acknowledge the reception of the DATA chunk
+	 * following the normal procedure, immediately send an ERROR chunk
+	 * with cause set to "Invalid Stream Identifier" (See Section 3.3.10)
+	 * and discard the DATA chunk.
+	 */
+	if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) {
+		err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
+					 &data_hdr->stream,
+					 sizeof(data_hdr->stream));
+		if (err)
+			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
+					SCTP_CHUNK(err));
+		return SCTP_IERROR_BAD_STREAM;
+	}
+
+	/* Send the data up to the user.  Note:  Schedule  the
+	 * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
+	 * chunk needs the updated rwnd.
+	 */
+	sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
+
+	return SCTP_IERROR_NO_ERROR;
+}
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/socket.c linux-2.4.28-pre1/net/sctp/socket.c
--- linux-2.4.27/net/sctp/socket.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/socket.c	2004-08-15 19:48:20.000000000 +0000
@@ -86,8 +86,6 @@
 
 /* Forward declarations for internal helper functions. */
 static int sctp_writeable(struct sock *sk);
-static inline int sctp_wspace(struct sctp_association *asoc);
-static inline void sctp_set_owner_w(struct sctp_chunk *chunk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
 				size_t msg_len);
@@ -95,7 +93,8 @@ static int sctp_wait_for_packet(struct s
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static int sctp_wait_for_accept(struct sock *sk, long timeo);
 static void sctp_wait_for_close(struct sock *sk, long timeo);
-static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
+static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
+					union sctp_addr *addr, int len);
 static int sctp_bindx_add(struct sock *, struct sockaddr *, int);
 static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
 static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int);
@@ -111,6 +110,64 @@ static char *sctp_hmac_alg = SCTP_COOKIE
 extern kmem_cache_t *sctp_bucket_cachep;
 extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc);
 
+/* Get the sndbuf space available at the time on the association.  */
+static inline int sctp_wspace(struct sctp_association *asoc)
+{
+	struct sock *sk = asoc->base.sk;
+	int amt = 0;
+
+	amt = sk->sk_sndbuf - asoc->sndbuf_used;
+	if (amt < 0)
+		amt = 0;
+	return amt;
+}
+
+/* Increment the used sndbuf space count of the corresponding association by
+ * the size of the outgoing data chunk.
+ * Also, set the skb destructor for sndbuf accounting later.
+ *
+ * Since it is always 1-1 between chunk and skb, and also a new skb is always
+ * allocated for chunk bundling in sctp_packet_transmit(), we can use the
+ * destructor in the data chunk skb for the purpose of the sndbuf space
+ * tracking.
+ */
+static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
+{
+	struct sctp_association *asoc = chunk->asoc;
+	struct sock *sk = asoc->base.sk;
+
+	/* The sndbuf space is tracked per association.  */
+	sctp_association_hold(asoc);
+
+	chunk->skb->destructor = sctp_wfree;
+	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
+	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
+
+	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
+	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
+}
+
+/* Verify that this is a valid address. */
+static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
+				   int len)
+{
+	struct sctp_af *af;
+
+	/* Verify basic sockaddr. */
+	af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
+	if (!af)
+		return -EINVAL;
+
+	/* Is this a valid SCTP address?  */
+	if (!af->addr_valid(addr, sctp_sk(sk)))
+		return -EINVAL;
+
+	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
+		return -EINVAL;
+
+	return 0;
+}
+
 /* Look up the association by its id.  If this is not a UDP-style
  * socket, the ID field is always ignored.
  */
@@ -999,7 +1056,7 @@ SCTP_STATIC int sctp_sendmsg(struct sock
 	struct sctp_sndrcvinfo *sinfo;
 	struct sctp_initmsg *sinit;
 	sctp_assoc_t associd = NULL;
-	sctp_cmsgs_t cmsgs = { 0 };
+	sctp_cmsgs_t cmsgs = { NULL };
 	int err;
 	sctp_scope_t scope;
 	long timeo;
@@ -1630,6 +1687,32 @@ static int sctp_setsockopt_peer_addr_par
 	if (copy_from_user(&params, optval, optlen))
 		return -EFAULT;
 
+	/*
+	 * API 7. Socket Options (setting the default value for the endpoint)
+	 * All options that support specific settings on an association by
+	 * filling in either an association id variable or a sockaddr_storage
+	 * SHOULD also support setting of the same value for the entire endpoint
+	 * (i.e. future associations). To accomplish this the following logic is
+	 * used when setting one of these options:
+
+	 * c) If neither the sockaddr_storage or association identification is
+	 *    set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and
+	 *    the association identification is 0, the settings are a default
+	 *    and to be applied to the endpoint (all future associations).
+	 */
+
+	/* update default value for endpoint (all future associations) */
+	if (!params.spp_assoc_id && 
+	    sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+		if (params.spp_hbinterval)
+			sctp_sk(sk)->paddrparam.spp_hbinterval =
+						params.spp_hbinterval;
+		if (sctp_max_retrans_path)
+			sctp_sk(sk)->paddrparam.spp_pathmaxrxt =
+						params.spp_pathmaxrxt;
+		return 0;
+	}
+
 	trans = sctp_addr_id2transport(sk, &params.spp_address,
 				       params.spp_assoc_id);
 	if (!trans)
@@ -2795,6 +2878,17 @@ static int sctp_getsockopt_peer_addr_par
 	if (copy_from_user(&params, optval, *optlen))
 		return -EFAULT;
 
+	/* If no association id is specified retrieve the default value
+	 * for the endpoint that will be used for all future associations
+	 */
+	if (!params.spp_assoc_id &&
+	    sctp_is_any(( union sctp_addr *)&params.spp_address)) {
+		params.spp_hbinterval = sctp_sk(sk)->paddrparam.spp_hbinterval;
+		params.spp_pathmaxrxt = sctp_sk(sk)->paddrparam.spp_pathmaxrxt;
+
+		goto done;
+	}
+
 	trans = sctp_addr_id2transport(sk, &params.spp_address,
 				       params.spp_assoc_id);
 	if (!trans)
@@ -2814,6 +2908,7 @@ static int sctp_getsockopt_peer_addr_par
 	 */
 	params.spp_pathmaxrxt = trans->error_threshold;
 
+done:
 	if (copy_to_user(optval, &params, len))
 		return -EFAULT;
 
@@ -4138,64 +4233,6 @@ no_packet:
 	return NULL;
 }
 
-/* Verify that this is a valid address. */
-static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
-				   int len)
-{
-	struct sctp_af *af;
-
-	/* Verify basic sockaddr. */
-	af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
-	if (!af)
-		return -EINVAL;
-
-	/* Is this a valid SCTP address?  */
-	if (!af->addr_valid(addr, sctp_sk(sk)))
-		return -EINVAL;
-
-	if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr)))
-		return -EINVAL;
-
-	return 0;
-}
-
-/* Get the sndbuf space available at the time on the association.  */
-static inline int sctp_wspace(struct sctp_association *asoc)
-{
-	struct sock *sk = asoc->base.sk;
-	int amt = 0;
-
-	amt = sk->sk_sndbuf - asoc->sndbuf_used;
-	if (amt < 0)
-		amt = 0;
-	return amt;
-}
-
-/* Increment the used sndbuf space count of the corresponding association by
- * the size of the outgoing data chunk.
- * Also, set the skb destructor for sndbuf accounting later.
- *
- * Since it is always 1-1 between chunk and skb, and also a new skb is always
- * allocated for chunk bundling in sctp_packet_transmit(), we can use the
- * destructor in the data chunk skb for the purpose of the sndbuf space
- * tracking.
- */
-static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
-{
-	struct sctp_association *asoc = chunk->asoc;
-	struct sock *sk = asoc->base.sk;
-
-	/* The sndbuf space is tracked per association.  */
-	sctp_association_hold(asoc);
-
-	chunk->skb->destructor = sctp_wfree;
-	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
-	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
-
-	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
-	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk);
-}
-
 /* If sndbuf has changed, wake up per association sndbuf waiters.  */
 static void __sctp_write_space(struct sctp_association *asoc)
 {
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/ulpevent.c linux-2.4.28-pre1/net/sctp/ulpevent.c
--- linux-2.4.27/net/sctp/ulpevent.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/ulpevent.c	2004-08-15 19:50:51.000000000 +0000
@@ -48,13 +48,23 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
-					   const struct sctp_association *asoc);
-static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event);
 static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
 				       struct sctp_association *asoc);
 static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
 
+/* Stub skb destructor.  */
+static void sctp_stub_rfree(struct sk_buff *skb)
+{
+/* WARNING:  This function is just a warning not to use the
+ * skb destructor.  If the skb is shared, we may get the destructor
+ * callback on some processor that does not own the sock_lock.  This
+ * was occuring with PACKET socket applications that were monitoring
+ * our skbs.   We can't take the sock_lock, because we can't risk
+ * recursing if we do really own the sock lock.  Instead, do all
+ * of our rwnd manipulation while we own the sock_lock outright.
+ */
+}
+
 /* Create a new sctp_ulpevent.  */
 struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
 {
@@ -87,6 +97,30 @@ int sctp_ulpevent_is_notification(const 
 	return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);
 }
 
+/* Hold the association in case the msg_name needs read out of
+ * the association.
+ */
+static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
+					   const struct sctp_association *asoc)
+{
+	struct sk_buff *skb;
+
+	/* Cast away the const, as we are just wanting to
+	 * bump the reference count.
+	 */
+	sctp_association_hold((struct sctp_association *)asoc);
+	skb = sctp_event2skb(event);
+	skb->sk = asoc->base.sk;
+	event->asoc = (struct sctp_association *)asoc;
+	skb->destructor = sctp_stub_rfree;
+}
+
+/* A simple destructor to give up the reference to the association. */
+static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
+{
+	sctp_association_put(event->asoc);
+}
+
 /* Create and initialize an SCTP_ASSOC_CHANGE event.
  *
  * 5.3.1.1 SCTP_ASSOC_CHANGE
@@ -789,43 +823,6 @@ void sctp_ulpevent_read_sndrcvinfo(const
 		 sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
 }
 
-/* Stub skb destructor.  */
-static void sctp_stub_rfree(struct sk_buff *skb)
-{
-/* WARNING:  This function is just a warning not to use the
- * skb destructor.  If the skb is shared, we may get the destructor
- * callback on some processor that does not own the sock_lock.  This
- * was occuring with PACKET socket applications that were monitoring
- * our skbs.   We can't take the sock_lock, because we can't risk
- * recursing if we do really own the sock lock.  Instead, do all
- * of our rwnd manipulation while we own the sock_lock outright.
- */
-}
-
-/* Hold the association in case the msg_name needs read out of
- * the association.
- */
-static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
-					   const struct sctp_association *asoc)
-{
-	struct sk_buff *skb;
-
-	/* Cast away the const, as we are just wanting to
-	 * bump the reference count.
-	 */
-	sctp_association_hold((struct sctp_association *)asoc);
-	skb = sctp_event2skb(event);
-	skb->sk = asoc->base.sk;
-	event->asoc = (struct sctp_association *)asoc;
-	skb->destructor = sctp_stub_rfree;
-}
-
-/* A simple destructor to give up the reference to the association. */
-static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
-{
-	sctp_association_put(event->asoc);
-}
-
 /* Do accounting for bytes received and hold a reference to the association
  * for each skb.
  */
diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.27/net/sctp/ulpqueue.c linux-2.4.28-pre1/net/sctp/ulpqueue.c
--- linux-2.4.27/net/sctp/ulpqueue.c	2004-08-07 23:26:07.000000000 +0000
+++ linux-2.4.28-pre1/net/sctp/ulpqueue.c	2004-08-15 19:47:11.000000000 +0000
@@ -49,10 +49,10 @@
 #include <net/sctp/sm.h>
 
 /* Forward declarations for internal helpers.  */
-static inline struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
-						     struct sctp_ulpevent *);
-static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *,
-						    struct sctp_ulpevent *);
+static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
+						struct sctp_ulpevent *);
+static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *,
+						struct sctp_ulpevent *);
 
 /* 1st Level Abstractions */
 
@@ -97,12 +97,12 @@ void sctp_ulpq_flush(struct sctp_ulpq *u
 	struct sk_buff *skb;
 	struct sctp_ulpevent *event;
 
-	while ((skb = __skb_dequeue(&ulpq->lobby))) {
+	while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) {
 		event = sctp_skb2event(skb);
 		sctp_ulpevent_free(event);
 	}
 
-	while ((skb = __skb_dequeue(&ulpq->reasm))) {
+	while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) {
 		event = sctp_skb2event(skb);
 		sctp_ulpevent_free(event);
 	}
@@ -466,8 +466,8 @@ done:
 /* Helper function to reassemble chunks.  Hold chunks on the reasm queue that
  * need reassembling.
  */
-static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
-						   struct sctp_ulpevent *event)
+static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
+						struct sctp_ulpevent *event)
 {
 	struct sctp_ulpevent *retval = NULL;
 
@@ -645,8 +645,8 @@ static inline void sctp_ulpq_store_order
 
 }
 
-static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
-					struct sctp_ulpevent *event)
+static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
+						struct sctp_ulpevent *event)
 {
 	__u16 sid, ssn;
 	struct sctp_stream *in;
@@ -756,7 +756,7 @@ static __u16 sctp_ulpq_renege_order(stru
 
 	tsnmap = &ulpq->asoc->peer.tsn_map;
 
-	while ((skb = __skb_dequeue_tail(&ulpq->lobby))) {
+	while ((skb = __skb_dequeue_tail(&ulpq->lobby)) != NULL) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
 		tsn = event->tsn;
@@ -782,7 +782,7 @@ static __u16 sctp_ulpq_renege_frags(stru
 	tsnmap = &ulpq->asoc->peer.tsn_map;
 
 	/* Walk backwards through the list, reneges the newest tsns. */
-	while ((skb = __skb_dequeue_tail(&ulpq->reasm))) {
+	while ((skb = __skb_dequeue_tail(&ulpq->reasm)) != NULL) {
 		freed += skb_headlen(skb);
 		event = sctp_skb2event(skb);
 		tsn = event->tsn;
